mirror of
https://github.com/boxgaming/qbjs.git
synced 2024-09-20 04:24:45 +00:00
435 lines
10 KiB
JavaScript
435 lines
10 KiB
JavaScript
/**
|
|
* class Dialog {
|
|
*
|
|
* author: nemo
|
|
* date: 2017-06-20
|
|
* v: 1.1
|
|
* }
|
|
*/
|
|
{
|
|
'use strict';
|
|
|
|
class Dialog {
|
|
|
|
constructor(opt) {
|
|
Object.assign(this.option = {
|
|
caption: '',
|
|
message: '',
|
|
content: undefined,
|
|
buttons: Dialog.buttons.NONE,
|
|
|
|
resize: 'none',
|
|
|
|
cancelable: true,
|
|
|
|
showHeader: true,
|
|
showClose: true,
|
|
showFooter: false,
|
|
|
|
// handler
|
|
abortHandler: undefined,
|
|
cancelHandler: () => { this.close(); },
|
|
ignoreHandler: undefined,
|
|
noHandler: undefined,
|
|
okHandler: () => { this.close(); },
|
|
retryHandler: undefined,
|
|
yesHandler: undefined,
|
|
|
|
// events
|
|
beforeClosing: () => { return true; }, // set to false to prevent close
|
|
closed: undefined,
|
|
}, opt);
|
|
this.init();
|
|
}
|
|
|
|
/**
|
|
* START init
|
|
*/
|
|
init() {
|
|
return this
|
|
.initLayout()
|
|
.initAttributes()
|
|
.initContent()
|
|
.initEvents();
|
|
}
|
|
|
|
initLayout() {
|
|
this.dialog = create('dialog', 'dialog');
|
|
this.dialog.style.resize = this.option.resize,
|
|
appendTo(this.dialog, document.body);
|
|
this.show();
|
|
|
|
this.container = this.dialog;
|
|
|
|
this.header = create('header', 'header');
|
|
this.caption = create('h3', 'caption');
|
|
this.closeButton = create('em', 'close-button');
|
|
|
|
this.body = create('div', 'body');
|
|
this.content = create('section', 'content');
|
|
this.buttonArea = create('div', 'button-area');
|
|
|
|
this.footer = create('footer', 'footer');
|
|
|
|
// assembly dom
|
|
this.header.appendChild(this.caption);
|
|
if (this.option.showClose)
|
|
this.header.appendChild(this.closeButton);
|
|
if (this.option.showHeader)
|
|
this.dialog.appendChild(this.header);
|
|
|
|
this.body.appendChild(this.content);
|
|
this.body.appendChild(this.buttonArea);
|
|
this.assemblyButtons();
|
|
this.dialog.appendChild(this.body);
|
|
|
|
if (this.option.showFooter)
|
|
this.dialog.appendChild(this.footer);
|
|
|
|
return this;
|
|
}
|
|
|
|
initAttributes() {
|
|
this.dialog.wrapper = this;
|
|
|
|
this.cancelable = this.option.cancelable;
|
|
|
|
return this;
|
|
}
|
|
|
|
assemblyButtons() {
|
|
switch (this.option.buttons) {
|
|
case Dialog.buttons.ABORT_RETRY_IGNORE:
|
|
new DialogButton(this, Dialog.button.ABORT).assembly();
|
|
new DialogButton(this, Dialog.button.RETRY).assembly().focus();
|
|
new DialogButton(this, Dialog.button.IGNORE).assembly();
|
|
break;
|
|
case Dialog.buttons.OK:
|
|
new DialogButton(this, Dialog.button.OK).assembly().focus();
|
|
break;
|
|
case Dialog.buttons.OK_CANCEL:
|
|
new DialogButton(this, Dialog.button.OK).assembly();
|
|
new DialogButton(this, Dialog.button.CANCEL).assembly().focus();
|
|
break;
|
|
case Dialog.buttons.RETRY_CANCEL:
|
|
new DialogButton(this, Dialog.button.RETRY).assembly().focus();
|
|
new DialogButton(this, Dialog.button.CANCEL).assembly();
|
|
break;
|
|
case Dialog.buttons.YES_NO:
|
|
new DialogButton(this, Dialog.button.YES).assembly();
|
|
new DialogButton(this, Dialog.button.NO).assembly().focus();
|
|
break;
|
|
case Dialog.buttons.YES_NO_CANCEL:
|
|
new DialogButton(this, Dialog.button.YES).assembly();
|
|
new DialogButton(this, Dialog.button.NO).assembly();
|
|
new DialogButton(this, Dialog.button.CANCEL).assembly().focus();
|
|
break;
|
|
default:
|
|
// no button
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
appendButton(btn) {
|
|
this.buttonArea.appendChild(btn.button);
|
|
return this;
|
|
}
|
|
|
|
removeButton(btn) {
|
|
this.buttonArea.removeChild(btn.button);
|
|
return this;
|
|
}
|
|
|
|
initContent() {
|
|
this.caption.innerText = this.option.caption;
|
|
if (this.option.content == undefined) {
|
|
this.content.innerText = this.option.message;
|
|
} else {
|
|
this.content.innerHTML = this.option.content;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
initEvents() {
|
|
this.closeButton.addEventListener('click', () => {
|
|
this.close();
|
|
});
|
|
|
|
// prevent esc
|
|
this.dialog.addEventListener('cancel', (e) => {
|
|
!this.cancelable && e.preventDefault();
|
|
});
|
|
|
|
return this;
|
|
}
|
|
/**
|
|
* END init
|
|
*/
|
|
|
|
//:~
|
|
|
|
trigger(type) {
|
|
switch (type) {
|
|
case Dialog.button.ABORT:
|
|
callHandler(this.option.abortHandler, this);
|
|
break;
|
|
case Dialog.button.CANCEL:
|
|
callHandler(this.option.cancelHandler, this);
|
|
break;
|
|
case Dialog.button.IGNORE:
|
|
callHandler(this.option.ignoreHandler, this);
|
|
break;
|
|
case Dialog.button.NO:
|
|
callHandler(this.option.noHandler, this);
|
|
break;
|
|
case Dialog.button.OK:
|
|
callHandler(this.option.okHandler, this);
|
|
break;
|
|
case Dialog.button.RETRY:
|
|
callHandler(this.option.retryHandler, this);
|
|
break;
|
|
case Dialog.button.YES:
|
|
callHandler(this.option.yesHandler, this);
|
|
break;
|
|
default:
|
|
console.log(`Unknown type:${type}`);
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
beforeClosing(func) {
|
|
this.option.beforeClosing = func;
|
|
|
|
return this;
|
|
}
|
|
|
|
closed(func) {
|
|
this.dialog.addEventListener('close', func);
|
|
|
|
return this;
|
|
}
|
|
|
|
get cancelable() {
|
|
return this.option.cancelable;
|
|
}
|
|
|
|
set cancelable(value) {
|
|
this.option.cancelable = !!value;
|
|
}
|
|
|
|
show() {
|
|
if (this.dialog.open)
|
|
return this;
|
|
|
|
try {
|
|
this.dialog.showModal();
|
|
} catch (e) {
|
|
appendTo(this.dialog, document.body);
|
|
this.dialog.showModal();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
hide(dispose = true) {
|
|
if (!this.dialog.open)
|
|
return this;
|
|
|
|
if (typeof this.option.beforeClosing != 'function' ||
|
|
!!this.option.beforeClosing()) {
|
|
this.dialog.close();
|
|
|
|
try {
|
|
dispose && document.body.removeChild(this.dialog);
|
|
} finally { }
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
close(dispose = true) {
|
|
return this.hide(dispose);
|
|
}
|
|
|
|
addClass(className) {
|
|
addClass(this.dialog, className);
|
|
}
|
|
|
|
//:~
|
|
|
|
/**
|
|
* START static helper
|
|
*/
|
|
static alert(message, caption = '') {
|
|
return new Dialog({
|
|
caption: `${caption}`,
|
|
message: `${message}`,
|
|
buttons: Dialog.buttons.OK,
|
|
});
|
|
}
|
|
|
|
static confirm(message, caption = '', ok, cancel) {
|
|
return new Dialog({
|
|
caption: `${caption}`,
|
|
message: `${message}`,
|
|
buttons: Dialog.buttons.OK_CANCEL,
|
|
okHandler: ok,
|
|
cancelHandler: cancel,
|
|
});
|
|
}
|
|
|
|
static template(dom, caption = '') {
|
|
return new Dialog({
|
|
caption: `${caption}`,
|
|
content: dom.innerHTML,
|
|
});
|
|
}
|
|
|
|
static templet(dom, caption) {
|
|
return template(dom, caption);
|
|
}
|
|
|
|
static iframe(src, caption = '', width = 'auto', height = 'auto') {
|
|
let dlg = new Dialog({
|
|
caption: `${caption}`,
|
|
content: `<iframe style="border: none;" src="${src}"></iframe>`,
|
|
});
|
|
let iframe = dlg.content.childNodes[0];
|
|
iframe.style.width = width;
|
|
iframe.style.height = height;
|
|
}
|
|
/**
|
|
* END static helper
|
|
*/
|
|
}
|
|
|
|
class DialogButton {
|
|
constructor(dialog, type) {
|
|
this.dialog = dialog;
|
|
this.type = type;
|
|
|
|
this.button = create('button', `btn-${type}`);
|
|
this.button.type = 'button';
|
|
this.button.innerText = Dialog.buttonText[type];
|
|
|
|
this.click(() => {
|
|
this.dialog.trigger(this.type);
|
|
});
|
|
}
|
|
|
|
assembly() {
|
|
this.dialog.appendButton(this);
|
|
|
|
return this;
|
|
}
|
|
|
|
click(func) {
|
|
this.button.addEventListener('click', func);
|
|
|
|
return this;
|
|
}
|
|
|
|
focus() {
|
|
window.setTimeout(() => {
|
|
this.button.focus();
|
|
}, 1);
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
Object.assign(Dialog, {
|
|
|
|
buttons: {
|
|
ABORT_RETRY_IGNORE: 1,
|
|
OK: 2,
|
|
OK_CANCEL: 3,
|
|
RETRY_CANCEL: 4,
|
|
YES_NO: 5,
|
|
YES_NO_CANCEL: 6,
|
|
},
|
|
|
|
button: {
|
|
NONE: 0,
|
|
ABORT: 1,
|
|
CANCEL: 2,
|
|
IGNORE: 3,
|
|
NO: 4,
|
|
OK: 5,
|
|
RETRY: 6,
|
|
YES: 7,
|
|
},
|
|
|
|
buttonText: [
|
|
undefined,
|
|
'Abort',
|
|
'Cancel',
|
|
'Ignore',
|
|
'NO',
|
|
'OK',
|
|
'Retry',
|
|
'Yes',
|
|
],
|
|
});
|
|
|
|
let callHandler = (func, dlg) => {
|
|
return typeof func == 'function' ?
|
|
func(dlg) : undefined;
|
|
}
|
|
|
|
let cls = (cls) => {
|
|
return `dlg-${cls}`;
|
|
}
|
|
|
|
let addClass = (dom, className) => {
|
|
let c = dom.className;
|
|
let add = cls(className);
|
|
if (c == '') {
|
|
return add;
|
|
} else {
|
|
return c + ' ' + add;
|
|
}
|
|
}
|
|
|
|
let prependTo = (sub, base) => {
|
|
if (base.hasChildNodes()) {
|
|
base.insertBefore(sub, base.firstChild);
|
|
} else {
|
|
base.appendChild(sub);
|
|
}
|
|
}
|
|
|
|
let appendTo = (sub, base) => {
|
|
base.appendChild(sub);
|
|
}
|
|
|
|
let show = (dom, display = 'block') => {
|
|
visible(dom, true, display);
|
|
}
|
|
|
|
let hide = (dom) => {
|
|
visible(dom, true);
|
|
}
|
|
|
|
let visible = (dom, v, display) => {
|
|
if (dom == undefined || dom.style == undefined)
|
|
return;
|
|
else
|
|
dom.style.display = v ? display : 'none';
|
|
}
|
|
|
|
let create = (name, className) => {
|
|
let e = document.createElement(name);
|
|
if (typeof className == 'string')
|
|
e.className = cls(className);
|
|
return e;
|
|
}
|
|
|
|
// export { Dialog } // ES6
|
|
window['Dialog'] = Dialog;
|
|
}
|