add: getText
compatibility.
add: `AssetSelector` and `TemplateSelector`. add: `popup-selector` style class. add: `ui.resolvePopup` function. add: `switch` in checkbox. add: `GridColumn.filterTemplate` supports. add: add `action` callback in `createIcon`. change: replace `setTimeout(..., 0)` with `requestAnimationFrame`. change: Popup result structure adjustment ({ result: any, popup: Popup }). change: complete add work order flow. change: reduce Popup title height. fix: Grid column sort in number.
This commit is contained in:
183
lib/ui/popup.js
183
lib/ui/popup.js
@@ -1,9 +1,10 @@
|
||||
import "./css/popup.scss";
|
||||
import { r } from "../utility/lgres";
|
||||
import { r as lang } from "../utility/lgres";
|
||||
import { nullOrEmpty } from "../utility/strings";
|
||||
import { global } from "../utility";
|
||||
import { createElement } from "../functions";
|
||||
import { createIcon, changeIcon } from "./icon";
|
||||
import { requestAnimationFrame } from "../ui";
|
||||
|
||||
const ResizeMods = {
|
||||
right: 1,
|
||||
@@ -51,6 +52,30 @@ export class Popup {
|
||||
|
||||
get container() { return this._var.mask.querySelector('.ui-popup-container') }
|
||||
|
||||
get title() { return this._var.option.title }
|
||||
set title(title) {
|
||||
const element = this._var.mask?.querySelector('.ui-popup-container .ui-popup-header .ui-popup-header-title');
|
||||
if (element != null) {
|
||||
element.innerText = title;
|
||||
}
|
||||
this._var.option.title = title;
|
||||
}
|
||||
|
||||
get loading() { return this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading')?.style?.visibility === 'visible' }
|
||||
set loading(flag) {
|
||||
let loading = this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading');
|
||||
if (loading == null) {
|
||||
return;
|
||||
}
|
||||
if (flag === false) {
|
||||
loading.style.visibility = 'hidden';
|
||||
loading.style.opacity = 0;
|
||||
} else {
|
||||
loading.style.visibility = 'visible';
|
||||
loading.style.opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
get rect() {
|
||||
const container = this.container;
|
||||
if (container == null) {
|
||||
@@ -105,25 +130,41 @@ export class Popup {
|
||||
}
|
||||
}
|
||||
|
||||
close(animation = true) {
|
||||
close(result = null, animation = true) {
|
||||
const option = this._var.option;
|
||||
const mask = this._var.mask;
|
||||
const doClose = () => {
|
||||
if (option.persistent) {
|
||||
mask.style.display = 'none';
|
||||
} else {
|
||||
mask.remove();
|
||||
this._var.mask = null;
|
||||
}
|
||||
}
|
||||
if (animation) {
|
||||
mask.classList.add('ui-popup-active');
|
||||
mask.style.opacity = 0;
|
||||
setTimeout(() => { mask.remove(); }, 120);
|
||||
setTimeout(() => { doClose(); }, 120);
|
||||
} else {
|
||||
mask.remove();
|
||||
doClose();
|
||||
}
|
||||
if (typeof this._var.option.onMasking === 'function') {
|
||||
this._var.option.onMasking.call(this, false);
|
||||
if (typeof option.onMasking === 'function') {
|
||||
option.onMasking.call(this, false);
|
||||
}
|
||||
if (typeof this._var.option.resolve === 'function') {
|
||||
this._var.option.resolve();
|
||||
if (typeof option.resolve === 'function') {
|
||||
option.resolve.call(this, {
|
||||
result,
|
||||
popup: this
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Popup 面板
|
||||
* @returns {HTMLDivElement} 返回遮罩元素(顶层元素)
|
||||
*/
|
||||
create() {
|
||||
const mask = createElement('div', 'ui-popup-mask');
|
||||
const mask = createElement('div', 'ui-popup-mask ui-popup-active');
|
||||
const option = this._var.option;
|
||||
if (option.mask === false) {
|
||||
mask.classList.add('ui-popup-transparent');
|
||||
@@ -286,14 +327,14 @@ export class Popup {
|
||||
if (typeof result?.then === 'function') {
|
||||
result.then(r => {
|
||||
if (r !== false) {
|
||||
this.close();
|
||||
this.close(r);
|
||||
}
|
||||
}).catch(reason => console.warn(reason));
|
||||
} else if (result !== false) {
|
||||
this.close();
|
||||
this.close(result);
|
||||
}
|
||||
} else {
|
||||
this.close();
|
||||
this.close(b.key ?? i);
|
||||
}
|
||||
});
|
||||
return button;
|
||||
@@ -357,24 +398,33 @@ export class Popup {
|
||||
return mask;
|
||||
}
|
||||
|
||||
show(parent = document.body) {
|
||||
show(parent = document.body, hidden = false) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
let mask = this._var.mask ?? this.create();
|
||||
// const exists = [...parent.children].filter(e => e.classList.contains('ui-popup-mask'));
|
||||
const exists = parent.querySelectorAll('.ui-popup-mask');
|
||||
let zindex = 0;
|
||||
for (let ex of exists) {
|
||||
let z = parseInt(ex.style.zIndex);
|
||||
if (!isNaN(z) && z > zindex) {
|
||||
zindex = z;
|
||||
let mask = this._var.mask;
|
||||
if (mask == null) {
|
||||
mask = this._var.mask = this.create();
|
||||
}
|
||||
if (mask.parentElement == null) {
|
||||
// const exists = [...parent.children].filter(e => e.classList.contains('ui-popup-mask'));
|
||||
const exists = parent.querySelectorAll('.ui-popup-mask');
|
||||
let zindex = 0;
|
||||
for (let ex of exists) {
|
||||
let z = parseInt(global.getComputedStyle(ex).zIndex);
|
||||
if (!isNaN(z) && z > zindex) {
|
||||
zindex = z;
|
||||
}
|
||||
}
|
||||
if (zindex > 0) {
|
||||
mask.style.zIndex = String(zindex + 1);
|
||||
}
|
||||
parent.appendChild(mask);
|
||||
if (hidden === true) {
|
||||
mask.style.display = 'none';
|
||||
return Promise.resolve(mask);
|
||||
}
|
||||
}
|
||||
if (zindex > 0) {
|
||||
mask.style.zIndex = String(zindex + 1);
|
||||
}
|
||||
parent.appendChild(mask);
|
||||
if (this._var.option.mask === false) {
|
||||
// calculator position
|
||||
const container = this.container;
|
||||
@@ -382,29 +432,16 @@ export class Popup {
|
||||
container.style.top = String((parent.offsetHeight - container.offsetHeight) / 2) + 'px';
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
mask.style.display = '';
|
||||
requestAnimationFrame(() => {
|
||||
mask.classList.remove('ui-popup-active');
|
||||
mask.style.opacity = 1;
|
||||
this.container.focus();
|
||||
resolve(mask);
|
||||
}, 0);
|
||||
setTimeout(() => resolve(mask), 120);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get loading() { return this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading')?.style?.visibility === 'visible' }
|
||||
set loading(flag) {
|
||||
let loading = this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading');
|
||||
if (loading == null) {
|
||||
return;
|
||||
}
|
||||
if (flag === false) {
|
||||
loading.style.visibility = 'hidden';
|
||||
loading.style.opacity = 0;
|
||||
} else {
|
||||
loading.style.visibility = 'visible';
|
||||
loading.style.opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
_resize(mod, e) {
|
||||
if (e.buttons !== 1) {
|
||||
return;
|
||||
@@ -500,6 +537,43 @@ export function createPopup(title, content, ...buttons) {
|
||||
return popup;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析对话框元素
|
||||
* @param {HTMLElement | string} wrapper - 解析该 `.dialog` 元素
|
||||
* @param {Function} [callback] - 关闭对话框时的回调
|
||||
* @param {boolean} [removable] - 是否可移除
|
||||
* @param {number} [zIndex] - 对话框默认 `z-index`
|
||||
* @returns {Popup} 返回弹出框字典
|
||||
*/
|
||||
export function resolvePopup(wrapper, callback, removable, zIndex) {
|
||||
if (typeof wrapper === 'string') {
|
||||
wrapper = document.querySelector(wrapper);
|
||||
}
|
||||
if (wrapper == null) {
|
||||
return null;
|
||||
}
|
||||
if (!wrapper.classList.contains('dialog')) {
|
||||
return null;
|
||||
}
|
||||
const title = wrapper.querySelector('.dialog-title>.title')?.innerText;
|
||||
const content = wrapper.querySelector('.dialog-title+div');
|
||||
const buttons = [...wrapper.querySelectorAll('.dialog-func>input[type="button"]')].reverse().map(b => ({
|
||||
tabIndex: b.tabIndex,
|
||||
text: b.value,
|
||||
trigger: b.onclick == null ? null : (popup => (b.onclick.call(popup), false))
|
||||
}));
|
||||
const popup = new Popup({
|
||||
title,
|
||||
content,
|
||||
persistent: !removable,
|
||||
resolve: typeof callback === 'function' ? (result => callback(result)) : null,
|
||||
zIndex: wrapper.zIndex ?? zIndex,
|
||||
buttons
|
||||
});
|
||||
popup.show(document.body, true);
|
||||
return popup;
|
||||
}
|
||||
|
||||
const iconTypes = {
|
||||
'info': 'info-circle',
|
||||
'information': 'info-circle',
|
||||
@@ -510,6 +584,7 @@ const iconTypes = {
|
||||
}
|
||||
|
||||
export function showAlert(title, message, iconType = 'info', parent = document.body) {
|
||||
const r = typeof GetTextByKey === 'function' ? GetTextByKey : lang;
|
||||
return new Promise(resolve => {
|
||||
const popup = new Popup({
|
||||
title,
|
||||
@@ -519,7 +594,7 @@ export function showAlert(title, message, iconType = 'info', parent = document.b
|
||||
),
|
||||
resolve,
|
||||
buttons: [
|
||||
{ text: r('ok', 'OK'), trigger: resolve }
|
||||
{ text: r('ok', 'OK') }
|
||||
]
|
||||
});
|
||||
popup.show(parent).then(mask => {
|
||||
@@ -530,6 +605,7 @@ export function showAlert(title, message, iconType = 'info', parent = document.b
|
||||
}
|
||||
|
||||
export function showConfirm(title, content, buttons, iconType = 'question', parent = document.body) {
|
||||
const r = typeof GetTextByKey === 'function' ? GetTextByKey : lang;
|
||||
return new Promise(resolve => {
|
||||
const wrapper = createElement('div', 'message-wrapper');
|
||||
if (!nullOrEmpty(iconType)) {
|
||||
@@ -542,34 +618,23 @@ export function showConfirm(title, content, buttons, iconType = 'question', pare
|
||||
title,
|
||||
content: wrapper,
|
||||
resolve,
|
||||
buttons: buttons?.map(b => {
|
||||
buttons: buttons?.map((b, i) => {
|
||||
return {
|
||||
text: b.text,
|
||||
trigger: p => {
|
||||
let result;
|
||||
if (typeof b.trigger === 'function') {
|
||||
result = b.trigger(p, b);
|
||||
if (typeof result?.then === 'function') {
|
||||
return result.then(r => {
|
||||
r !== false && resolve(r);
|
||||
return r;
|
||||
});
|
||||
}
|
||||
result !== false && resolve(result);
|
||||
} else {
|
||||
result = {
|
||||
key: b.key,
|
||||
popup: p
|
||||
};
|
||||
resolve(result);
|
||||
result = b.key ?? i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}) ??
|
||||
[
|
||||
{ text: r('yes', 'Yes'), trigger: p => resolve({ key: 'yes', popup: p }) },
|
||||
{ text: r('no', 'No'), trigger: p => resolve({ key: 'no', popup: p }) }
|
||||
{ key: 'yes', text: r('yes', 'Yes') },
|
||||
{ key: 'no', text: r('no', 'No') }
|
||||
]
|
||||
});
|
||||
popup.show(parent).then(mask => {
|
||||
|
Reference in New Issue
Block a user