structure adjustment
This commit is contained in:
213
lib/ui/popup.js
213
lib/ui/popup.js
@ -1,11 +1,37 @@
|
||||
import "../../css/popup.scss";
|
||||
import "./css/popup.scss";
|
||||
import { r } from "../utility/lgres";
|
||||
import { nullOrEmpty } from "../utility/strings";
|
||||
import { global } from "../utility";
|
||||
import { createElement } from "../functions";
|
||||
import { r, nullOrEmpty } from "../utility";
|
||||
import { createIcon } from "./icon";
|
||||
import { createIcon, changeIcon } from "./icon";
|
||||
|
||||
const ResizeMods = {
|
||||
right: 1,
|
||||
bottom: 2,
|
||||
left: 4,
|
||||
top: 8,
|
||||
bottomRight: 2 | 1,
|
||||
bottomLeft: 2 | 4,
|
||||
topRight: 8 | 1,
|
||||
topLeft: 8 | 4
|
||||
}
|
||||
|
||||
// const Cursors = {
|
||||
// [ResizeMods.right]: 'ew-resize',
|
||||
// [ResizeMods.bottom]: 'ns-resize',
|
||||
// [ResizeMods.bottomRight]: 'nwse-resize',
|
||||
// [ResizeMods.left]: 'ew-resize',
|
||||
// [ResizeMods.bottomLeft]: 'nesw-resize',
|
||||
// [ResizeMods.top]: 'ns-resize',
|
||||
// [ResizeMods.topRight]: 'nesw-resize',
|
||||
// [ResizeMods.topLeft]: 'nwse-resize'
|
||||
// }
|
||||
|
||||
class Popup {
|
||||
#mask;
|
||||
#option;
|
||||
#bounds;
|
||||
// #cursor;
|
||||
|
||||
constructor(opts = {}) {
|
||||
this.#option = opts;
|
||||
@ -13,8 +39,47 @@ class Popup {
|
||||
|
||||
get container() { return this.#mask.querySelector('.popup-container') }
|
||||
|
||||
get rect() {
|
||||
const container = this.container;
|
||||
if (container == null) {
|
||||
return null;
|
||||
}
|
||||
const style = global.getComputedStyle(container);
|
||||
return {
|
||||
left: style.left,
|
||||
top: style.top,
|
||||
width: style.width,
|
||||
height: style.height
|
||||
};
|
||||
}
|
||||
set rect(r) {
|
||||
const container = this.container;
|
||||
if (container == null) {
|
||||
return;
|
||||
}
|
||||
const css = [];
|
||||
if (!isNaN(r.left)) {
|
||||
css.push(`left: ${r.left}px`);
|
||||
}
|
||||
if (!isNaN(r.top)) {
|
||||
css.push(`top: ${r.top}px`);
|
||||
}
|
||||
if (!isNaN(r.width) && r.width > 0) {
|
||||
css.push(`width: ${r.width}px`);
|
||||
}
|
||||
if (!isNaN(r.height) && r.height > 0) {
|
||||
css.push(`height: ${r.height}px`);
|
||||
}
|
||||
if (css.length > 0) {
|
||||
container.style.cssText += css.join('; ');
|
||||
}
|
||||
}
|
||||
|
||||
create() {
|
||||
const mask = createElement('div', 'popup-mask');
|
||||
if (this.#option.mask === false) {
|
||||
mask.classList.add('popup-transparent');
|
||||
}
|
||||
const container = createElement('div', 'popup-container');
|
||||
const close = () => {
|
||||
mask.classList.add('popup-active');
|
||||
@ -30,7 +95,10 @@ class Popup {
|
||||
header.className = 'popup-header';
|
||||
let title = this.#option.title;
|
||||
if (!(title instanceof HTMLElement)) {
|
||||
title = createElement('div', t => t.innerText = title);
|
||||
title = createElement('div', t => {
|
||||
t.className = 'popup-header-title';
|
||||
t.innerText = title;
|
||||
});
|
||||
}
|
||||
header.appendChild(title);
|
||||
const move = title.querySelector('.popup-move') ?? title;
|
||||
@ -46,6 +114,27 @@ class Popup {
|
||||
mask.removeEventListener('mousemove', move, { passive: false });
|
||||
});
|
||||
});
|
||||
if (this.#option.collapsable === true) {
|
||||
const collapse = createIcon('fa-regular', 'compress-alt');
|
||||
collapse.classList.add('icon-expand');
|
||||
collapse.addEventListener('click', () => {
|
||||
if (container.classList.contains('popup-collapse')) {
|
||||
const bounds = this.#bounds;
|
||||
if (bounds != null) {
|
||||
container.style.cssText += `width: ${bounds.width}; height: ${bounds.height}`;
|
||||
}
|
||||
container.classList.remove('popup-collapse');
|
||||
changeIcon(collapse, 'fa-regular', 'compress-alt');
|
||||
} else {
|
||||
const rect = this.rect;
|
||||
this.#bounds = rect;
|
||||
container.style.cssText += `left: ${rect.left}; top: ${rect.top}; width: 160px; height: 40px`;
|
||||
container.classList.add('popup-collapse');
|
||||
changeIcon(collapse, 'fa-regular', 'expand-alt');
|
||||
}
|
||||
});
|
||||
header.appendChild(collapse);
|
||||
}
|
||||
const cancel = createIcon('fa-regular', 'times');
|
||||
cancel.addEventListener('click', () => close());
|
||||
header.appendChild(cancel);
|
||||
@ -79,6 +168,43 @@ class Popup {
|
||||
}))
|
||||
);
|
||||
}
|
||||
// resizable
|
||||
if (this.#option.resizable === true) {
|
||||
container.append(
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-right';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.right, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-bottom';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.bottom, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-left';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.left, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-top';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.top, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-bottom-right';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.bottomRight, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-bottom-left';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.bottomLeft, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-top-left';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.topLeft, e));
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.className = 'popup-border popup-border-top-right';
|
||||
layer.addEventListener('mousedown', e => this.#resize(ResizeMods.topRight, e));
|
||||
})
|
||||
)
|
||||
}
|
||||
mask.appendChild(container);
|
||||
this.#mask = mask;
|
||||
return mask;
|
||||
@ -90,6 +216,12 @@ class Popup {
|
||||
}
|
||||
let mask = this.#mask ?? this.create();
|
||||
parent.appendChild(mask);
|
||||
if (this.#option.mask === false) {
|
||||
// calculator position
|
||||
const container = this.container;
|
||||
container.style.left = String((parent.offsetWidth - container.offsetWidth) / 2) + 'px';
|
||||
container.style.top = String((parent.offsetHeight - container.offsetHeight) / 2) + 'px';
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
mask.style.opacity = 1
|
||||
@ -112,6 +244,79 @@ class Popup {
|
||||
loading.style.opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#resize(mod, e) {
|
||||
const container = this.container;
|
||||
const option = this.#option;
|
||||
if (typeof option.onResizeStarted === 'function') {
|
||||
option.onResizeStarted.call(this);
|
||||
}
|
||||
const mask = this.#mask;
|
||||
// this.#cursor = mask.style.cursor;
|
||||
// mask.style.cursor = Cursors[mod];
|
||||
const originalX = e.clientX;
|
||||
const originalY = e.clientY;
|
||||
const original = {
|
||||
width: container.offsetWidth,
|
||||
height: container.offsetHeight,
|
||||
left: container.offsetLeft,
|
||||
top: container.offsetTop
|
||||
};
|
||||
const minWidth = option.minWidth ?? 200;
|
||||
const minHeight = option.minHeight ?? 200;
|
||||
const move = e => {
|
||||
const offsetX = e.clientX - originalX;
|
||||
const offsetY = e.clientY - originalY;
|
||||
let width = original.width;
|
||||
let height = original.height;
|
||||
let x = original.left;
|
||||
let y = original.top;
|
||||
if ((mod & ResizeMods.right) === ResizeMods.right) {
|
||||
width += offsetX;
|
||||
if (width < minWidth) {
|
||||
width = minWidth;
|
||||
}
|
||||
}
|
||||
if ((mod & ResizeMods.bottom) === ResizeMods.bottom) {
|
||||
height += offsetY;
|
||||
if (height < minHeight) {
|
||||
height = minHeight;
|
||||
}
|
||||
}
|
||||
if ((mod & ResizeMods.left) === ResizeMods.left) {
|
||||
width -= offsetX;
|
||||
if (width < minWidth) {
|
||||
width = minWidth;
|
||||
x = originalX + original.width - minWidth;
|
||||
} else {
|
||||
x += offsetX;
|
||||
}
|
||||
}
|
||||
if ((mod & ResizeMods.top) === ResizeMods.top) {
|
||||
height -= offsetY;
|
||||
if (height < minHeight) {
|
||||
height = minHeight;
|
||||
y = originalY + original.height - minHeight;
|
||||
} else {
|
||||
y += offsetY;
|
||||
}
|
||||
}
|
||||
if (typeof option.onResizing === 'function') {
|
||||
option.onResizing.call(this, x, y, width, height);
|
||||
} else {
|
||||
container.style.cssText += `left: ${x}px; top: ${y}px; width: ${width}px; height: ${height}px`;
|
||||
}
|
||||
}
|
||||
const parent = option.mask === false ? mask.parentElement : mask;
|
||||
parent.addEventListener('mousemove', move, { passive: false });
|
||||
parent.addEventListener('mouseup', () => {
|
||||
parent.removeEventListener('mousemove', move, { passive: false });
|
||||
// mask.style.cursor = this.#cursor;
|
||||
if (typeof option.onResizeEnded === 'function') {
|
||||
option.onResizeEnded.call(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Popup;
|
||||
|
Reference in New Issue
Block a user