diff --git a/Makefile b/Makefile index e2833be..3802212 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ tags = dist/core/tags/tag.js \ dist/core/tags/FileViewTag.js \ dist/core/tags/OverlayTag.js \ dist/core/tags/AppDockTag.js \ - dist/core/tags/SystemPanelTag.js + dist/core/tags/SystemPanelTag.js \ + dist/core/tags/DesktopTag.js javascripts= dist/core/core.js \ dist/core/settings.js \ diff --git a/d.ts/antos.d.ts b/d.ts/antos.d.ts index d098131..02b393b 100644 --- a/d.ts/antos.d.ts +++ b/d.ts/antos.d.ts @@ -710,6 +710,20 @@ declare namespace OS { * @param {boolean} force force to clear the system theme before applying the new one */ function loadTheme(name: string, force: boolean): void; + /** + * Get the system dock tag + * + * @export + * @return {*} {GUI.tag.AppDockTag} + */ + function systemDock(): GUI.tag.AppDockTag; + /** + * Get the current virtual desktop + * + * @export + * @return {*} {GUI.tag.DesktopTag} + */ + function desktop(): GUI.tag.DesktopTag; /** * Open a system dialog. * @@ -4463,10 +4477,10 @@ declare namespace OS { * The HTML element ID of the virtual desktop * * @protected - * @type {string} + * @type {HTMLElement} * @memberof BaseModel */ - protected host: string; + protected host: HTMLElement; /** * The process number of the current model. * For sub-window this number is the number @@ -4702,7 +4716,6 @@ declare namespace OS { /** * trigger a local event * - * @protected * @param {string} e event name * @param {*} [d] event data * @returns {void} @@ -5526,6 +5539,89 @@ declare namespace OS { } } } +declare namespace OS { + namespace GUI { + namespace tag { + /** + * Meta tag that represents the virtual desktop environment. + * In near future, we may have multiple virtual desktop environments. + * Each desktop environment has a simple file manager and a window + * manager that render the window in a specific order. + * + * @export + * @class DesktopTag + * @extends {FloatListTag} + */ + class DesktopTag extends FloatListTag { + /** + * internal handle to the desktop file location + * + * @private + * @type {API.VFS.BaseFileHandle} + * @memberof DesktopTag + */ + private file; + /** + * local observer that detect if a new child element is + * added or removed + * + * @private + * @type {MutationObserver} + * @memberof DesktopTag + */ + private observer; + /** + * Internal list of the current opened window + * + * @private + * @type {Set} + * @memberof DesktopTag + */ + private window_list; + /** + * Creates an instance of DesktopTag. + * @memberof DesktopTag + */ + constructor(); + /** + * Mount the virtual desktop to the DOM tree + * + * @protected + * @memberof DesktopTag + */ + protected mount(): void; + /** + * Display all files and folders in the specific desktop location + * + * @return {*} {Promise} + * @memberof DesktopTag + */ + refresh(): Promise; + /** + * Remove this element from its parent + * + * @memberof DesktopTag + */ + remove(): void; + /** + * Active a window above all other windows + * + * @private + * @param {WindowTag} win + * @memberof DesktopTag + */ + private selectWindow; + /** + * Render all windows in order from bottom to top + * + * @private + * @memberof DesktopTag + */ + private render; + } + } + } +} declare namespace OS { namespace GUI { namespace tag { @@ -7988,10 +8084,6 @@ declare namespace OS { * Tag event callback type */ type TagEventCallback = (e: TagEventType) => void; - /** - * Top most element z index value, start by 10 - */ - var zindex: number; /** * Base abstract class for tag implementation, any AFX tag should be * subclass of this class diff --git a/release/antos-1.2.1.tar.gz b/release/antos-1.2.1.tar.gz index bcb039d..96ad9a6 100644 Binary files a/release/antos-1.2.1.tar.gz and b/release/antos-1.2.1.tar.gz differ diff --git a/src/core/BaseApplication.ts b/src/core/BaseApplication.ts index d010295..4d89195 100644 --- a/src/core/BaseApplication.ts +++ b/src/core/BaseApplication.ts @@ -109,6 +109,7 @@ namespace OS { ): void => { return this.trigger("menuselect", d); }; + this.trigger("focused", undefined); if (this.dialog) { return this.dialog.show(); } diff --git a/src/core/BaseDialog.ts b/src/core/BaseDialog.ts index 94b223d..55acb80 100644 --- a/src/core/BaseDialog.ts +++ b/src/core/BaseDialog.ts @@ -116,7 +116,7 @@ namespace OS { */ show(): void { this.trigger("focus"); - $(this.scheme).css("z-index", GUI.zindex + 2); + this.trigger("focused", undefined); if (this.dialog) { this.dialog.show(); } diff --git a/src/core/BaseModel.ts b/src/core/BaseModel.ts index 067261f..167551a 100644 --- a/src/core/BaseModel.ts +++ b/src/core/BaseModel.ts @@ -193,10 +193,10 @@ namespace OS { * The HTML element ID of the virtual desktop * * @protected - * @type {string} + * @type {HTMLElement} * @memberof BaseModel */ - protected host: string; + protected host: HTMLElement; /** * The process number of the current model. @@ -294,7 +294,7 @@ namespace OS { this._gui = GUI; this.systemsetting = setting; this.on("exit", () => this.quit(false)); - this.host = this._gui.workspace; + this.host = this._gui.desktop(); this.dialog = undefined; } @@ -504,7 +504,6 @@ namespace OS { /** * trigger a local event * - * @protected * @param {string} e event name * @param {*} [d] event data * @returns {void} diff --git a/src/core/gui.ts b/src/core/gui.ts index 6567f89..80fff81 100644 --- a/src/core/gui.ts +++ b/src/core/gui.ts @@ -119,12 +119,12 @@ namespace OS { app: BaseModel, parent: Element | string ): void { - const scheme = $.parseHTML(html); + const scheme = $.parseHTML(html)[0]; if (app.scheme) { $(app.scheme).remove(); } - $(parent as GenericObject).append(scheme); - app.scheme = scheme[0] as HTMLElement; + (parent as HTMLElement).append(scheme); + app.scheme = scheme as HTMLElement; app.scheme.uify(app.observable, true); app.main(); app.show(); @@ -182,6 +182,28 @@ namespace OS { $("head link#ostheme").attr("href", path); } + + /** + * Get the system dock tag + * + * @export + * @return {*} {GUI.tag.AppDockTag} + */ + export function systemDock(): GUI.tag.AppDockTag + { + return $("#sysdock")[0] as tag.AppDockTag; + } + + /** + * Get the current virtual desktop + * + * @export + * @return {*} {GUI.tag.DesktopTag} + */ + export function desktop(): GUI.tag.DesktopTag + { + return $(workspace)[0] as tag.DesktopTag; + } /** * Open a system dialog. * @@ -452,25 +474,19 @@ namespace OS { const srv = arr[1]; const app = arr[0]; try { - if (application[srv]) { - const d = await OS.PM.createProcess( - srv, - application[srv] - ); - return resolve(d); - } else { + if (!application[srv]) { await loadApp(app); if (!application[srv]) { return reject( API.throwe(__("Service not found: {0}", ph)) ); } - const d_1 = await PM.createProcess( - srv, - application[srv] - ); - return resolve(d_1); } + const d = await PM.createProcess( + srv, + application[srv] + ); + return resolve(d); } catch (e) { return reject(__e(e)); @@ -811,50 +827,6 @@ namespace OS { .css("left", left + "px"); } - /** - * Refresh the content of the virtual desktop - * - * @param {tag.FloatListTag} desktop - */ - function dkfetch(desktop: tag.FloatListTag): void { - const file = setting.desktop.path.asFileHandle(); - const fn = () => - file.read().then(function (d) { - if (d.error) { - return announcer.osfail(d.error, API.throwe(d.error)); - } - const items = []; - $.each(d.result, function (i, v) { - if ( - v.filename[0] === "." && - !setting.desktop.showhidden - ) { - return; - } - v.text = v.filename; - //v.text = v.text.substring(0,9) + "..." ifv.text.length > 10 - v.iconclass = v.type; - return items.push(v); - }); - desktop.data = items; - return desktop.calibrate(); - }); - - file.onready() - .then(() => fn()) - .catch(async function (e) { - // try to create the path - console.log(`${file.path} not found`); - const name = file.basename; - try { - const r = await file.parent().asFileHandle().mk(name); - return API.throwe("OS.VFS"); - } catch (e_1) { - return announcer.osfail(e_1.toString(), e_1); - } - }); - } - /** * Init the virtual desktop on boot: * @@ -927,119 +899,8 @@ namespace OS { e ); }); - - const fp = setting.desktop.path.asFileHandle(); - // desktop default file manager - const desktop = $(workspace)[0] as tag.FloatListTag; - - desktop.onready = function (e: tag.FloatListTag) { - e.observable = OS.announcer.observable; - window.onresize = function () { - announcer.trigger("desktopresize", undefined); - return e.calibrate(); - }; - - desktop.onlistselect = function ( - d: TagEventType - ) { - ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; - }; - - desktop.onlistdbclick = function ( - d: TagEventType - ) { - ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; - const it = desktop.selectedItem; - return openWith(it.data as AppArgumentsType); - }; - - //($ "#workingenv").on "click", (e) -> - // desktop[0].set "selected", -1 - - $(desktop).on("click", function (e) { - let el: any = $(e.target).closest("afx-app-window")[0]; - if (el) { - return; - } - el = $(e.target).parent(); - if (!(el.length > 0)) { - return; - } - el = el.parent(); - if (!(el.length > 0)) { - return; - } - if (el[0] !== desktop) { - return; - } - desktop.unselect(); - ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; - }); - - desktop.contextmenuHandle = function (e, m) { - if (e.target.tagName.toUpperCase() === "UL") { - desktop.unselect(); - } - ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; - let menu = [ - { text: __("Open"), dataid: "desktop-open" }, - { text: __("Refresh"), dataid: "desktop-refresh" }, - ]; - menu = menu.concat( - (() => { - const result = []; - for (let k in setting.desktop.menu) { - const v = setting.desktop.menu[k]; - result.push(v); - } - return result; - })() - ); - m.items = menu; - m.onmenuselect = function ( - evt: TagEventType - ) { - if (!evt.data || !evt.data.item) return; - const item = evt.data.item.data; - switch (item.dataid) { - case "desktop-open": - var it = desktop.selectedItem; - if (it) { - return openWith( - it.data as AppArgumentsType - ); - } - let arg = setting.desktop.path.asFileHandle() as AppArgumentsType; - arg.mime = "dir"; - arg.type = "dir"; - return openWith(arg); - case "desktop-refresh": - return dkfetch(desktop); - default: - if (item.app) { - return launch(item.app, item.args); - } - } - }; - return m.show(e); - }; - - dkfetch(desktop); - announcer.observable.on("VFS", function (d: API.AnnouncementDataType) { - if (["read", "publish", "download"].includes(d.message as string)) { - return; - } - if ( - d.u_data.hash() === fp.hash() || - d.u_data.parent().hash() === fp.hash() - ) { - return dkfetch(desktop); - } - }); - return announcer.ostrigger("desktoploaded", undefined); - }; // mount it - desktop.uify(undefined); + desktop().uify(undefined); } /** @@ -1048,7 +909,7 @@ namespace OS { * @export */ export function refreshDesktop(): void { - dkfetch($(workspace)[0] as tag.FloatListTag); + desktop().refresh(); } /** @@ -1184,7 +1045,7 @@ namespace OS {
- +
diff --git a/src/core/tags/DesktopTag.ts b/src/core/tags/DesktopTag.ts new file mode 100644 index 0000000..ba52396 --- /dev/null +++ b/src/core/tags/DesktopTag.ts @@ -0,0 +1,273 @@ +namespace OS { + export namespace GUI { + export namespace tag { + + /** + * Meta tag that represents the virtual desktop environment. + * In near future, we may have multiple virtual desktop environments. + * Each desktop environment has a simple file manager and a window + * manager that render the window in a specific order. + * + * @export + * @class DesktopTag + * @extends {FloatListTag} + */ + export class DesktopTag extends FloatListTag { + + + /** + * internal handle to the desktop file location + * + * @private + * @type {API.VFS.BaseFileHandle} + * @memberof DesktopTag + */ + private file: API.VFS.BaseFileHandle; + + /** + * local observer that detect if a new child element is + * added or removed + * + * @private + * @type {MutationObserver} + * @memberof DesktopTag + */ + private observer: MutationObserver; + + /** + * Internal list of the current opened window + * + * @private + * @type {Set} + * @memberof DesktopTag + */ + private window_list: Set; + + /** + * Creates an instance of DesktopTag. + * @memberof DesktopTag + */ + constructor() { + super(); + this.observer = undefined; + this.window_list = new Set(); + } + + + /** + * Mount the virtual desktop to the DOM tree + * + * @protected + * @memberof DesktopTag + */ + protected mount(): void { + if(this.observer) + { + this.observer.disconnect(); + this.observer = undefined; + } + this.observer = new MutationObserver((mutations_list) =>{ + mutations_list.forEach((mutation) => { + mutation.removedNodes.forEach((removed_node) =>{ + if((removed_node as HTMLElement).tagName === "AFX-APP-WINDOW") + { + this.window_list.delete(removed_node as WindowTag); + } + }); + mutation.addedNodes.forEach((added_node) =>{ + if((added_node as HTMLElement).tagName === "AFX-APP-WINDOW") + { + this.selectWindow(added_node as WindowTag); + } + }); + }); + }); + this.observer.observe(this, { subtree: false, childList: true }); + + this.onready = (_) => { + this.observable = OS.announcer.observable; + window.onresize = () => { + announcer.trigger("desktopresize", undefined); + this.calibrate(); + }; + + this.onlistselect = (d: TagEventType) => { + GUI.systemDock().selectedApp = null; + }; + + this.onlistdbclick = (d: TagEventType) => { + GUI.systemDock().selectedApp = null; + const it = this.selectedItem; + return GUI.openWith(it.data as AppArgumentsType); + }; + + //($ "#workingenv").on "click", (e) -> + // desktop[0].set "selected", -1 + + $(this).on("click", (e) => { + let el: any = $(e.target).closest("afx-app-window")[0]; + if (el) { + return; + } + el = $(e.target).parent(); + if (!(el.length > 0)) { + return; + } + el = el.parent(); + if (!(el.length > 0)) { + return; + } + if (el[0] !== this) { + return; + } + this.unselect(); + GUI.systemDock().selectedApp = null; + }); + + this.contextmenuHandle = (e, m) => { + if (e.target.tagName.toUpperCase() === "UL") { + this.unselect(); + } + GUI.systemDock().selectedApp = null; + let menu = [ + { text: __("Open"), dataid: "desktop-open" } as GUI.BasicItemType, + { text: __("Refresh"), dataid: "desktop-refresh" } as GUI.BasicItemType, + ]; + menu = menu.concat(setting.desktop.menu.map(e => e)); + m.items = menu; + m.onmenuselect = (evt: TagEventType) => { + if (!evt.data || !evt.data.item) return; + const item = evt.data.item.data; + switch (item.dataid) { + case "desktop-open": + var it = this.selectedItem; + if (it) { + return GUI.openWith( + it.data as AppArgumentsType + ); + } + let arg = setting.desktop.path.asFileHandle() as AppArgumentsType; + arg.mime = "dir"; + arg.type = "dir"; + return GUI.openWith(arg); + case "desktop-refresh": + return this.refresh(); + default: + if (item.app) { + return GUI.launch(item.app, item.args); + } + } + }; + return m.show(e); + }; + + this.refresh(); + announcer.observable.on("VFS", (d: API.AnnouncementDataType) => { + if (["read", "publish", "download"].includes(d.message as string)) { + return; + } + if (d.u_data.hash() === this.file.hash() || d.u_data.parent().hash() === this.file.hash()) { + return this.refresh(); + } + }); + return announcer.ostrigger("desktoploaded", undefined); + }; + super.mount(); + } + + + /** + * Display all files and folders in the specific desktop location + * + * @return {*} {Promise} + * @memberof DesktopTag + */ + + refresh(): Promise { + return new Promise(async (resolve, reject) => { + try { + this.file = setting.desktop.path.asFileHandle(); + await this.file.onready(); + const d = await this.file.read(); + if (d.error) { + throw new Error(d.error); + } + const items = []; + $.each(d.result, function (i, v) { + if (v.filename[0] === "." && !setting.desktop.showhidden) { + return; + } + v.text = v.filename; + //v.text = v.text.substring(0,9) + "..." ifv.text.length > 10 + v.iconclass = v.type; + return items.push(v); + }); + this.data = items; + this.calibrate(); + } + catch (err) { + announcer.osfail(err.toString(), err); + reject(__e(err)); + } + }); + } + + /** + * Remove this element from its parent + * + * @memberof DesktopTag + */ + remove(): void { + if(this.observer) + { + this.observer.disconnect(); + } + super.remove(); + } + + + /** + * Active a window above all other windows + * + * @private + * @param {WindowTag} win + * @memberof DesktopTag + */ + private selectWindow(win: WindowTag) + { + if(this.window_list.has(win)) + { + this.window_list.delete(win); + } + else + { + win.observable.on("focused",(_)=>{ + this.selectWindow(win); + }); + } + this.window_list.add(win); + console.log("number of windows", this.window_list.size); + this.render(); + } + + + /** + * Render all windows in order from bottom to top + * + * @private + * @memberof DesktopTag + */ + private render(){ + let zindex = 10; + for(let win of this.window_list) + { + $(win).css("z-index", zindex++); + } + } + + } + + define("afx-desktop", DesktopTag); + } + } +} \ No newline at end of file diff --git a/src/core/tags/WindowTag.ts b/src/core/tags/WindowTag.ts index 22debe5..06746e2 100644 --- a/src/core/tags/WindowTag.ts +++ b/src/core/tags/WindowTag.ts @@ -284,7 +284,7 @@ namespace OS { .css("position", "absolute") .css("left", `${left}px`) .css("top", `${top}px`) - .css("z-index", Ant.OS.GUI.zindex++); + .css("z-index", 10); $(this).on("mousedown", (e) => { if (this._shown) { return; @@ -301,10 +301,8 @@ namespace OS { this.observable.on("resize", (e) => this.resize()); this.observable.on("focus", () => { - Ant.OS.GUI.zindex++; $(this) .show() - .css("z-index", Ant.OS.GUI.zindex) .removeClass("unactive"); this._shown = true; $(this.refs.win_overlay).hide(); diff --git a/src/core/tags/tag.ts b/src/core/tags/tag.ts index 5b0010a..3c80c98 100644 --- a/src/core/tags/tag.ts +++ b/src/core/tags/tag.ts @@ -247,11 +247,6 @@ namespace OS { * Tag event callback type */ export type TagEventCallback = (e: TagEventType) => void; - /** - * Top most element z index value, start by 10 - */ - export var zindex: number = 10; - /** * Base abstract class for tag implementation, any AFX tag should be * subclass of this class diff --git a/src/themes/system/afx-float-list.css b/src/themes/system/afx-float-list.css index 4ce7599..28a6eb8 100644 --- a/src/themes/system/afx-float-list.css +++ b/src/themes/system/afx-float-list.css @@ -1,11 +1,11 @@ -afx-float-list div.list-container > ul{ +afx-desktop div.list-container > ul, afx-float-list div.list-container > ul{ padding: 0; margin: 0; background-color: transparent; } -afx-float-list div.list-container > ul li{ +afx-desktop div.list-container > ul li, afx-float-list div.list-container > ul li{ padding: 0; margin: 0; background-color: transparent;