// Copyright 2017-2018 Xuan Sang LE // AnTOS Web desktop is is licensed under the GNU General Public // License v3.0, see the LICENCE file for more information // This program is free software: you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // You should have received a copy of the GNU General Public License //along with this program. If not, see https://www.gnu.org/licenses/. namespace OS { export namespace GUI { /** * the SubWindow class is the abstract prototype of all * modal windows or dialogs definition in AntOS * * @export * @abstract * @class SubWindow * @extends {BaseModel} */ export abstract class SubWindow extends BaseModel { /** * Placeholder indicates whether the sub window is in * modal mode. This value is reserver for future use * * @type {boolean} * @memberof SubWindow */ modal: boolean; /** * Reference to the parent of the current sub-window * * @type {(BaseModel | typeof GUI)} * @memberof SubWindow */ parent: BaseModel | typeof GUI; /** *Creates an instance of SubWindow. * @param {string} name SubWindow (class) name * @memberof SubWindow */ constructor(name: string) { super(name, null); this.parent = undefined; this.modal = false; } /** * Exit the sub-window * * @returns {void} * @memberof SubWindow */ quit(): void { const evt = new BaseEvent("exit", false); this.onexit(evt); if (!evt.prevent) { delete this._observable; if (this.scheme) { $(this.scheme).remove(); } if (this.dialog) { return this.dialog.quit(); } } } /** * Init the sub-window, this function is called * on creation of the sub-window object. It is used * to render the sub-window UI. * * Need to be implemented by subclasses * * @abstract * @memberof SubWindow */ abstract init(): void; /** * Main entry point after rendering of the sub-window * * @abstract * @memberof SubWindow */ abstract main(): void; /** * Return the parent meta-data of the current * sub-window * * @returns {API.PackageMetaType} * @memberof SubWindow */ meta(): API.PackageMetaType { const p = this.parent as BaseModel; if (p && p.meta) { return p.meta(); } } /** * Show the sub-window * * @memberof SubWindow */ show(): void { this.trigger("focus"); $(this.scheme).css("z-index", GUI.zindex + 2); } /** * Hide the sub-window * * @returns {void} * @memberof SubWindow */ hide(): void { return this.trigger("hide"); } } SubWindow.type = ModelType.SubWindow; /** * Abstract prototype of all AntOS dialogs widget * * @export * @abstract * @class BaseDialog * @extends {SubWindow} */ export abstract class BaseDialog extends SubWindow { /** * Placeholder for the dialog callback on exit * * @memberof BaseDialog */ handle: (d: any) => void; /** * Placeholder of the dialog input data * * @type {GenericObject} * @memberof BaseDialog */ data: GenericObject; /** *Creates an instance of BaseDialog. * @param {string} name Dialog (class) name * @memberof BaseDialog */ constructor(name: string) { super(name); this.handle = undefined; } /** * Function called when dialog exits * * @protected * @param {BaseEvent} e * @returns {void} * @memberof BaseDialog */ protected onexit(e: BaseEvent): void { if (this.parent) { return (this.parent.dialog = undefined); } } } /** * A basic dialog renders a dialog widget using the UI * scheme provided in it constructor or defined in its * class variable `scheme` * * @export * @class BasicDialog * @extends {BaseDialog} */ export class BasicDialog extends BaseDialog { /** * Placeholder for the UI scheme to be rendered. This can * be either the string definition of the scheme or * the VFS file handle of the scheme file * * @private * @type {(string | OS.API.VFS.BaseFileHandle)} * @memberof BasicDialog */ private markup: string | OS.API.VFS.BaseFileHandle; /** * If the `markup` variable is not provided, then * the [[init]] function will find the scheme definition * in this class variable * * @static * @type {string} * @memberof BasicDialog */ static scheme: string; /** *Creates an instance of BasicDialog. * @param {string} name dialog name * @param {(string | OS.API.VFS.BaseFileHandle)} [markup] UI scheme definition * @memberof BasicDialog */ constructor( name: string, markup?: string | OS.API.VFS.BaseFileHandle ) { super(name); this.markup = markup; } /** * Render the dialog using the UI scheme provided by either * the `markup` instance variable or the `scheme` class variable * * @returns {void} * @memberof BasicDialog */ init(): void { if (this.markup) { if (typeof this.markup === "string") { return GUI.htmlToScheme(this.markup, this, this.host); } else { // a file handle return this.render(this.markup.path); } } else if ( GUI.dialogs[this.name] && GUI.dialogs[this.name].scheme ) { const html: string = GUI.dialogs[this.name].scheme; return GUI.htmlToScheme(html.trim(), this, this.host); } else { this.error(__("Unable to find dialog scheme")); } } /** * Main entry point for the dialog * * @memberof BasicDialog */ main(): void { const win = this.scheme as tag.WindowTag; if (this.data && this.data.title) { win.apptitle = this.data.title; } win.resizable = false; win.minimizable = false; } } /** * The namespace `dialogs` is dedicated to all Dialog definition * in AntOS */ export namespace dialogs { /** * Simple prompt dialog to get user input text. * The input date of the dialog: * * ```typescript * { * title: string, // window title * label: string, // label text * value: string, // user input text * type: string // input type: text or password * } * ``` * * The data passing from the dialog to the callback function is * in the string text of the user input value * * @export * @class PromptDialog * @extends {BasicDialog} */ export class PromptDialog extends BasicDialog { /** *Creates an instance of PromptDialog. * @memberof PromptDialog */ constructor() { super("PromptDialog"); } /** * Main entry point * * @memberof PromptDialog */ main(): void { super.main(); const $input = $(this.find("txtInput")); if (this.data && this.data.label) { (this.find( "lbl" ) as tag.LabelTag).text = this.data.label; } if (this.data && this.data.value) { $input.val(this.data.value); } if (this.data && this.data.type) { ($input[0] as HTMLInputElement).type = this.data.type } (this.find("btnOk") as tag.ButtonTag).onbtclick = (e) => { if (this.handle) { this.handle($input.val()); } return this.quit(); }; (this.find("btnCancel") as tag.ButtonTag).onbtclick = ( e ) => { return this.quit(); }; $input.keyup((e) => { if (e.which !== 13) { return; } if (this.handle) { this.handle($input.val()); } return this.quit(); }); $input.focus(); } } /** * Scheme definition of the Prompt dialog */ PromptDialog.scheme = `\
\ `; /** * A text dialog is similar to a [[PromptDialog]] nut allows * user to input multi-line text. * * Refer to [[PromptDialog]] for the definition of input and callback data * of the dialog * * @export * @class TextDialog * @extends {BasicDialog} */ export class TextDialog extends BasicDialog { /** *Creates an instance of TextDialog. * @memberof TextDialog */ constructor() { super("TextDialog"); } /** * Main entry point * * @memberof TextDialog */ main(): void { super.main(); const $input = $(this.find("txtInput")); if (this.data && this.data.value) { $input.val(this.data.value); } (this.find("btnOk") as tag.ButtonTag).onbtclick = (e) => { const value = $input.val(); if (!value || value === "") { return; } if (this.handle) { this.handle(value); } return this.quit(); }; (this.find("btnCancel") as tag.ButtonTag).onbtclick = ( e ): void => { return this.quit(); }; $input.focus(); } } /** * Scheme definition */ TextDialog.scheme = `\