From fb462fe31b14c092ef145c0e184ac71a7a85705b Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Thu, 4 Jun 2020 17:49:48 +0200 Subject: [PATCH] add more type, all defaults apps are now in typescript --- Makefile | 2 +- src/core/BaseApplication.ts | 66 ++- src/core/BaseDialog.ts | 8 +- src/core/BaseModel.ts | 100 +++- src/core/BaseService.ts | 16 +- src/core/core.ts | 6 +- src/core/gui.ts | 36 +- src/core/handles/RemoteHandle.ts | 2 +- src/core/tags/AppDockTag.ts | 12 +- src/core/tags/ButtonTag.ts | 7 +- src/core/tags/CalendarTag.ts | 6 +- src/core/tags/ColorPickerTag.ts | 4 +- src/core/tags/FileViewTag.ts | 22 +- src/core/tags/GridViewTag.ts | 34 +- src/core/tags/ListViewTag.ts | 55 +- src/core/tags/MenuTag.ts | 23 +- src/core/tags/NSpinnerTag.ts | 4 +- src/core/tags/SliderTag.ts | 8 +- src/core/tags/SwitchTag.ts | 6 +- src/core/tags/TabBarTag.ts | 10 +- src/core/tags/TabContainerTag.ts | 44 +- src/core/tags/TreeViewTag.ts | 18 +- src/core/tags/tag.ts | 22 +- src/core/vfs.ts | 12 +- src/packages/CodePad/AntOSDK.ts | 4 +- src/packages/CodePad/BaseExtension.ts | 6 +- src/packages/CodePad/ExtensionMaker.ts | 12 +- src/packages/CodePad/main.ts | 72 ++- src/packages/Files/Makefile | 2 +- src/packages/Files/main.js | 424 -------------- src/packages/Files/main.ts | 699 +++++++++++++++++++++++ src/packages/MarketPlace/Makefile | 2 +- src/packages/MarketPlace/dialog.js | 100 ---- src/packages/MarketPlace/dialog.ts | 108 ++++ src/packages/MarketPlace/main.css | 2 +- src/packages/MarketPlace/main.js | 433 -------------- src/packages/MarketPlace/main.ts | 614 ++++++++++++++++++++ src/packages/MarketPlace/scheme.html | 2 +- src/packages/Setting/AppearanceHandle.js | 126 ---- src/packages/Setting/AppearanceHandle.ts | 206 +++++++ src/packages/Setting/LocaleHandle.js | 49 -- src/packages/Setting/LocaleHandle.ts | 77 +++ src/packages/Setting/StartupHandle.js | 110 ---- src/packages/Setting/StartupHandle.ts | 155 +++++ src/packages/Setting/VFSHandle.js | 173 ------ src/packages/Setting/VFSHandle.ts | 246 ++++++++ src/packages/Setting/main.js | 61 -- src/packages/Setting/main.ts | 136 +++++ src/packages/Syslog/Calendar.ts | 2 +- src/packages/Syslog/PushNotification.ts | 2 +- 50 files changed, 2612 insertions(+), 1734 deletions(-) delete mode 100644 src/packages/Files/main.js create mode 100644 src/packages/Files/main.ts delete mode 100644 src/packages/MarketPlace/dialog.js create mode 100644 src/packages/MarketPlace/dialog.ts delete mode 100644 src/packages/MarketPlace/main.js create mode 100644 src/packages/MarketPlace/main.ts delete mode 100644 src/packages/Setting/AppearanceHandle.js create mode 100644 src/packages/Setting/AppearanceHandle.ts delete mode 100644 src/packages/Setting/LocaleHandle.js create mode 100644 src/packages/Setting/LocaleHandle.ts delete mode 100644 src/packages/Setting/StartupHandle.js create mode 100644 src/packages/Setting/StartupHandle.ts delete mode 100644 src/packages/Setting/VFSHandle.js create mode 100644 src/packages/Setting/VFSHandle.ts delete mode 100644 src/packages/Setting/main.js create mode 100644 src/packages/Setting/main.ts diff --git a/Makefile b/Makefile index 2856a11..7f08b8f 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ javascripts= dist/core/core.js \ dist/core/pm.js \ dist/bootstrap.js -packages = Syslog CodePad#Files Setting MarketPlace +packages = Syslog CodePad Files MarketPlace Setting main: initd build_javascripts build_themes libs build_packages languages - cp src/index.html $(BUILDDIR)/ diff --git a/src/core/BaseApplication.ts b/src/core/BaseApplication.ts index e60441d..2087340 100644 --- a/src/core/BaseApplication.ts +++ b/src/core/BaseApplication.ts @@ -35,7 +35,7 @@ namespace OS { */ export abstract class BaseApplication extends BaseModel { setting: GenericObject; - keycomb: GUI.ShortcutType; + protected keycomb: GUI.ShortcutType; sysdock: GUI.tag.AppDockTag; appmenu: GUI.tag.MenuTag; @@ -57,6 +57,12 @@ namespace OS { SHIFT: {}, META: {}, }; + this.subscribe("appregistry", (m) => { + if (m.name === this.name) { + this.applySetting(m.data.m); + } + }); + } /** @@ -70,11 +76,10 @@ namespace OS { this.on("exit", () => this.quit(false)); // first register some base event to the app this.on("focus", () => { - console.log("focus"); this.sysdock.selectedApp = this; this.appmenu.pid = this.pid; this.appmenu.items= this.baseMenu() || []; - this.appmenu.onmenuselect=(d: GUI.TagEventType): void => { + this.appmenu.onmenuselect=(d: GUI.tag.MenuEventData): void => { return this.trigger("menuselect", d); } if (this.dialog) { @@ -102,26 +107,30 @@ namespace OS { return this.loadScheme(); } + /** * * + * @protected * @returns {void} * @memberof BaseApplication */ - loadScheme(): void { + protected loadScheme(): void { //now load the scheme const path = `${this.meta().path}/scheme.html`; return this.render(path); } + /** * * + * @protected * @param {Promise} promise * @returns {Promise} * @memberof BaseApplication */ - load(promise: Promise): Promise { + protected load(promise: Promise): Promise { const q = this._api.mid(); return new Promise(async (resolve, reject) => { this._api.loading(q, this.name); @@ -136,15 +145,17 @@ namespace OS { }); } + /** * * + * @protected * @param {string} k * @param {(e: JQuery.MouseDownEvent) => void} f * @returns {void} * @memberof BaseApplication */ - bindKey(k: string, f: (e: JQuery.MouseDownEvent) => void): void { + protected bindKey(k: string, f: (e: JQuery.MouseDownEvent) => void): void { const arr = k.split("-"); if (arr.length !== 2) { return; @@ -157,14 +168,16 @@ namespace OS { this.keycomb[fnk][c] = f; } + /** * * + * @private * @param {string} name * @returns {void} * @memberof BaseApplication */ - updateLocale(name: string): void { + protected updateLocale(name: string): void { const meta = this.meta(); if (!meta || !meta.locales) { return; @@ -204,35 +217,41 @@ namespace OS { return false; } + /** * * + * @protected * @param {string} k * @memberof BaseApplication */ - applySetting(k: string): void {} + protected applySetting(k: string): void {} + /** * * + * @protected * @memberof BaseApplication */ - applyAllSetting(): void { + protected applyAllSetting(): void { for (let k in this.setting) { const v = this.setting[k]; this.applySetting(k); } } + /** * * + * @protected * @param {string} k * @param {*} v * @returns {void} * @memberof BaseApplication */ - registry(k: string, v: any): void { + protected registry(k: string, v: any): void { this.setting[k] = v; return this.publish("appregistry", k); } @@ -290,13 +309,15 @@ namespace OS { return (this.scheme as GUI.tag.WindowTag).apptitle; } + /** * * + * @protected * @param {BaseEvent} evt * @memberof BaseApplication */ - onexit(evt: BaseEvent): void { + protected onexit(evt: BaseEvent): void { this.cleanup(evt); if (!evt.prevent) { if (this.pid === this.appmenu.pid) { @@ -316,13 +337,15 @@ namespace OS { return application[this.name].meta; } + /** * * - * @returns {BasicItemType[]} + * @protected + * @returns {GUI.BasicItemType[]} * @memberof BaseApplication */ - baseMenu(): GUI.BasicItemType[] { + protected baseMenu(): GUI.BasicItemType[] { let mn: GUI.BasicItemType[] = [ { text: application[this.name].meta.name, @@ -346,32 +369,29 @@ namespace OS { //main program // implement by subclasses + /** * * - * @returns {BasicItemType[]} + * @protected + * @returns {GUI.BasicItemType[]} * @memberof BaseApplication */ - menu(): GUI.BasicItemType[] { + protected menu(): GUI.BasicItemType[] { // implement by subclasses // to add menu to application return []; } + /** * * - * @memberof BaseApplication - */ - open(): void {} - - /** - * - * + * @protected * @param {BaseEvent} e * @memberof BaseApplication */ - cleanup(e: BaseEvent): void {} + protected cleanup(e: BaseEvent): void {} } BaseApplication.type = ModelType.Application; diff --git a/src/core/BaseDialog.ts b/src/core/BaseDialog.ts index 98c7fa0..028cc78 100644 --- a/src/core/BaseDialog.ts +++ b/src/core/BaseDialog.ts @@ -58,7 +58,7 @@ namespace OS { const evt = new BaseEvent("exit", false); this.onexit(evt); if (!evt.prevent) { - delete this.observable; + delete this._observable; if (this.scheme) { $(this.scheme).remove(); } @@ -143,14 +143,16 @@ namespace OS { this.handle = undefined; } + /** * * + * @protected * @param {BaseEvent} e * @returns {void} * @memberof BaseDialog */ - onexit(e: BaseEvent): void { + protected onexit(e: BaseEvent): void { if (this.parent) { return (this.parent.dialog = undefined); } @@ -672,7 +674,7 @@ namespace OS { if (this.data && this.data.data) { listview.data = this.data.data; } - const fn = (e: TagEventType) => { + const fn = (e: TagEventType) => { const data = listview.selectedItem; if (!data) { return this.notify(__("Please select an item")); diff --git a/src/core/BaseModel.ts b/src/core/BaseModel.ts index b32adf1..5c1db19 100644 --- a/src/core/BaseModel.ts +++ b/src/core/BaseModel.ts @@ -34,16 +34,16 @@ namespace OS { [propName: string]: any; } /** - * - * - * @export - * @enum {number} - */ - export enum ModelType { - Application, - Service, - SubWindow - }; + * + * + * @export + * @enum {number} + */ + export enum ModelType { + Application, + Service, + SubWindow, + } /** * * @@ -89,14 +89,14 @@ namespace OS { export abstract class BaseModel { name: string; args: AppArgumentsType[]; - observable: API.Announcer; - _api: typeof API; - _gui: typeof GUI; + protected _observable: API.Announcer; + protected _api: typeof API; + protected _gui: typeof GUI; dialog: GUI.BaseDialog; - host: string; + protected host: string; pid: number; scheme: HTMLElement; - systemsetting: typeof setting; + protected systemsetting: typeof setting; birth: number; static type: ModelType; static singleton: boolean; @@ -113,23 +113,40 @@ namespace OS { constructor(name: string, args: AppArgumentsType[]) { this.name = name; this.args = args; - this.observable = new API.Announcer(); + this._observable = new API.Announcer(); this._api = API; this._gui = GUI; this.systemsetting = setting; this.on("exit", () => this.quit(false)); this.host = this._gui.workspace; this.dialog = undefined; + this.subscribe("systemlocalechange", (name) => { + this.updateLocale(name); + return this.update(); + }); } + get observable(): API.Announcer + { + return this._observable; + } /** * * + * @protected + * @param {string} name + * @memberof BaseModel + */ + protected updateLocale(name: string) {} + /** + * + * + * @protected * @param {string} p * @returns {void} * @memberof BaseModel */ - render(p: string): void { + protected render(p: string): void { return GUI.loadScheme(p, this, this.host); } @@ -145,7 +162,7 @@ namespace OS { this.onexit(evt); if (!evt.prevent) { this.observable.off("*"); - delete this.observable; + delete this._observable; if (this.dialog) { this.dialog.quit(); } @@ -177,25 +194,27 @@ namespace OS { } // call a server side script + /** * * + * @protected * @param {GenericObject} cmd * @returns {Promise} * @memberof BaseModel */ - call(cmd: GenericObject): Promise { + protected call(cmd: GenericObject): Promise { return this._api.apigateway(cmd, false); } - // get a stream /** * * + * @protected * @returns {Promise} * @memberof BaseModel */ - stream(): Promise { + protected stream(): Promise { return this._api.apigateway(null, true) as Promise; } @@ -232,58 +251,68 @@ namespace OS { abstract hide(): void; //implement by sub class + /** * * + * @protected * @abstract * @param {BaseEvent} e * @memberof BaseModel */ - abstract onexit(e: BaseEvent): void; + protected abstract onexit(e: BaseEvent): void; //implement by subclass + /** * * + * @protected * @param {string} e * @param {(d: any) => void} f * @returns {void} * @memberof BaseModel */ - one(e: string, f: (d: any) => void): void { + protected one(e: string, f: (d: any) => void): void { return this.observable.one(e, f); } + /** * * + * @protected * @param {string} e * @param {(d: any) => void} f * @returns {void} * @memberof BaseModel */ - on(e: string, f: (d: any) => void): void { + protected on(e: string, f: (d: any) => void): void { return this.observable.on(e, f); } + /** * * + * @protected * @param {string} e * @param {(d: any) => void} [f] * @returns {void} * @memberof BaseModel */ - off(e: string, f?: (d: any) => void): void { + protected off(e: string, f?: (d: any) => void): void { if (!f) { return this.observable.off(e); } return this.observable.off(e, f); } + /** * * + * @protected * @param {string} e * @param {*} [d] * @returns {void} @@ -293,9 +322,11 @@ namespace OS { return this.observable.trigger(e, d); } + /** * * + * @protected * @param {string} e * @param {(d: any) => void} f * @returns {void} @@ -305,10 +336,11 @@ namespace OS { return announcer.on(e, f, this); } + /** * * - * @param {(BaseDialog | string)} d + * @param {(GUI.BaseDialog | string)} d * @param {GenericObject} [data] * @returns {Promise} * @memberof BaseModel @@ -346,24 +378,30 @@ namespace OS { /** * * + * @protected * @param {GenericObject} data * @returns {Promise} * @memberof BaseModel */ - ask(data: GenericObject): Promise { + protected ask(data: GenericObject): Promise { return this._gui.openDialog("YesNoDialog", data); } /** * * + * @protected * @param {string} t * @param {(string | FormatedString)} m * @param {Error} [e] * @returns {void} * @memberof BaseModel */ - publish(t: string, m: string | FormatedString, e?: Error): void { + protected publish( + t: string, + m: string | FormatedString, + e?: Error + ): void { const mt = this.meta(); let icon: string = undefined; if (mt.icon) { @@ -452,11 +490,12 @@ namespace OS { /** * * + * @protected * @param {string} id * @returns {HTMLElement} * @memberof BaseModel */ - find(id: string): HTMLElement { + protected find(id: string): HTMLElement { if (this.scheme) { return $(`[data-id='${id}']`, this.scheme)[0]; } @@ -465,11 +504,12 @@ namespace OS { /** * * + * @protected * @param {string} sel * @returns {HTMLElement} * @memberof BaseModel */ - select(sel: string): HTMLElement { + protected select(sel: string): HTMLElement { if (this.scheme) { return $(sel, this.scheme)[0]; } diff --git a/src/core/BaseService.ts b/src/core/BaseService.ts index a539970..c21092d 100644 --- a/src/core/BaseService.ts +++ b/src/core/BaseService.ts @@ -38,7 +38,7 @@ namespace OS { domel: HTMLElement; private timer: number; holder: HTMLElement; - onmenuselect: (d: OS.GUI.TagEventType) => void; + onmenuselect: (d: OS.GUI.TagEventType) => void; /** *Creates an instance of BaseService. @@ -105,15 +105,17 @@ namespace OS { this.holder = h; } + /** * * + * @protected * @param {number} t * @param {() => void} f * @returns {number} * @memberof BaseService */ - watch(t: number, f: () => void): number { + protected watch(t: number, f: () => void): number { var func = () => { f(); return (this.timer = setTimeout(() => func(), t)); @@ -121,14 +123,16 @@ namespace OS { return func(); } + /** * * + * @protected * @param {BaseEvent} evt * @returns * @memberof BaseService */ - onexit(evt: BaseEvent) { + protected onexit(evt: BaseEvent) { if (this.timer) { console.log("clean timer"); } @@ -162,16 +166,18 @@ namespace OS { * @param {GUI.TagEventType} e * @memberof BaseService */ - abstract awake(e: GUI.TagEventType): void; + abstract awake(e: GUI.TagEventType): void; //implement by user to tart the service + /** * * + * @protected * @param {BaseEvent} evt * @memberof BaseService */ - cleanup(evt: BaseEvent) {} + protected cleanup(evt: BaseEvent) {} } //implemeted by user BaseService.type = ModelType.Service; diff --git a/src/core/core.ts b/src/core/core.ts index edb3dfc..7c3e2ac 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -992,14 +992,14 @@ namespace OS { } } + /** * * * @export - * @param {*} f * @returns {Promise} */ - export function setting(f: any): Promise { + export function setting(): Promise { return API.handle.setting(); } @@ -1137,7 +1137,7 @@ namespace OS { * @export * @returns {*} */ - export function switcher(): any { + export function switcher(...args: string[]): any { let k: any, v: any; const o: any = {}; const p = {}; diff --git a/src/core/gui.ts b/src/core/gui.ts index 23f91a4..6d76fd4 100644 --- a/src/core/gui.ts +++ b/src/core/gui.ts @@ -83,7 +83,7 @@ namespace OS { } $(parent as GenericObject).append(scheme); app.scheme = scheme[0] as HTMLElement; - app.scheme.uify(app.observable); + app.scheme.uify(app.observable, true); app.main(); app.show(); } @@ -305,12 +305,14 @@ namespace OS { return launch(app, args); } + /** * * + * @export * @param {string} app */ - function unloadApp(app: string): void { + export function unloadApp(app: string): void { PM.killAll(app, true); if (app[app] && app[app].style) { $(app[app].style).remove(); @@ -522,22 +524,13 @@ namespace OS { } const dock = $("#sysdock")[0] as tag.AppDockTag; app.init(); - return app.one("rendered", function () { - dock.newapp(data); + app.observable.one("rendered", function () { app.sysdock = dock; app.appmenu = $( "[data-id = 'appmenu']", "#syspanel" )[0] as tag.MenuTag; - app.subscribe("systemlocalechange", function (name) { - app.updateLocale(name); - return app.update(); - }); - return app.subscribe("appregistry", function (m) { - if (m.name === app.name) { - return app.applySetting(m.data.m); - } - }); + dock.newapp(data); }); } @@ -598,7 +591,6 @@ namespace OS { export function attachservice(srv: application.BaseService): void { ($("#syspanel")[0] as tag.SystemPanelTag).attachservice(srv); srv.init(); - return srv.subscribe("systemlocalechange", (name) => srv.update()); } /** @@ -666,7 +658,7 @@ namespace OS { * @export * @param {setting.WPSettingType} obj */ - export function wallpaper(obj: setting.WPSettingType): void { + export function wallpaper(obj?: setting.WPSettingType): void { if (obj) { setting.appearance.wp = obj; } @@ -851,11 +843,11 @@ namespace OS { return e.calibrate(); }; - desktop.onlistselect = function (d: TagEventType) { + desktop.onlistselect = function (d: TagEventType) { ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; }; - desktop.onlistdbclick = function (d: TagEventType) { + desktop.onlistdbclick = function (d: TagEventType) { ($("#sysdock")[0] as tag.AppDockTag).selectedApp = null; const it = desktop.selectedItem; return openWith(it.data as AppArgumentsType); @@ -900,7 +892,7 @@ namespace OS { })() ); m.items = menu; - m.onmenuselect = function (evt: TagEventType) { + m.onmenuselect = function (evt: TagEventType) { if(!evt.data || !evt.data.item) return; const item = evt.data.item.data; switch (item.dataid) { @@ -1048,9 +1040,11 @@ namespace OS { } return result; })() - ); - return - setting.system.startup.apps.map((a) => launch(a, [])); + ).then(function(){ + setting.system.startup.apps.map((a) => { + launch(a, []); + }); + }) }); } }); diff --git a/src/core/handles/RemoteHandle.ts b/src/core/handles/RemoteHandle.ts index dcce70b..4faaf74 100644 --- a/src/core/handles/RemoteHandle.ts +++ b/src/core/handles/RemoteHandle.ts @@ -158,7 +158,7 @@ namespace OS { export function setting(): Promise { const p = `${API.REST}/system/settings`; - return API.post(p, setting); + return API.post(p, OS.setting); } export function dbquery( diff --git a/src/core/tags/AppDockTag.ts b/src/core/tags/AppDockTag.ts index 0519a24..7cddd93 100644 --- a/src/core/tags/AppDockTag.ts +++ b/src/core/tags/AppDockTag.ts @@ -28,7 +28,7 @@ namespace OS { */ export class AppDockTag extends AFXTag { - private _onappselect: TagEventCallback; + private _onappselect: TagEventCallback; private _items: AppDockItemType[]; private _selectedApp: application.BaseApplication; @@ -137,11 +137,13 @@ namespace OS { el.appendTo(this); el[0].uify(this.observable); bt.set(item); + bt.data = item.app; el.attr("tooltip", `cr:${item.app.title()}`); item.domel = bt; bt.onbtclick = (e) => { e.id = this.aid; - e.data.item = item; + //e.data.item = item; + this._onappselect(e); item.app.show(); }; this.selectedApp = item.app; @@ -182,15 +184,15 @@ namespace OS { if (e.target === this) { return; } - const bt = $(e.target).closest("afx-button"); - const app = bt[0].get("app"); + const bt = $(e.target).closest("afx-button")[0] as any as ButtonTag; + const app = bt.data; m.items = [ { text: "__(Show)", dataid: "show" }, { text: "__(Hide)", dataid: "hide" }, { text: "__(Close)", dataid: "quit" }, ]; m.onmenuselect = function (evt) { - const item = evt.data.item.get("data"); + const item = evt.data.item.data; if (app[item.dataid]) { return app[item.dataid](); } diff --git a/src/core/tags/ButtonTag.ts b/src/core/tags/ButtonTag.ts index e72cdcc..92b7ac6 100644 --- a/src/core/tags/ButtonTag.ts +++ b/src/core/tags/ButtonTag.ts @@ -8,11 +8,12 @@ namespace OS { export namespace tag { export class ButtonTag extends AFXTag { private _selected: boolean; - private _onbtclick: TagEventCallback; + private _onbtclick: TagEventCallback; + data: GenericObject; constructor() { super(); } - set onbtclick(v: TagEventCallback) + set onbtclick(v: TagEventCallback) { this._onbtclick = v; } @@ -61,7 +62,7 @@ namespace OS { protected mount() { $(this.refs.button).click((e) => { - const evt: TagEventType = { + const evt: TagEventType = { id: this.aid, data: e, }; diff --git a/src/core/tags/CalendarTag.ts b/src/core/tags/CalendarTag.ts index 1e7a00e..bf2f87f 100644 --- a/src/core/tags/CalendarTag.ts +++ b/src/core/tags/CalendarTag.ts @@ -20,7 +20,7 @@ namespace OS { private _month: number; private _year: number; private _selectedDate: Date; - private _ondateselect: TagEventCallback; + private _ondateselect: TagEventCallback; /** *Creates an instance of CalendarTag. @@ -71,7 +71,7 @@ namespace OS { * * @memberof CalendarTag */ - set ondateselect(v: TagEventCallback) { + set ondateselect(v: TagEventCallback) { this._ondateselect = v; } @@ -111,7 +111,7 @@ namespace OS { * @returns {void} * @memberof CalendarTag */ - private dateselect(e: TagEventType): void { + private dateselect(e: TagEventType>): void { if (!e.data.item) { return; } diff --git a/src/core/tags/ColorPickerTag.ts b/src/core/tags/ColorPickerTag.ts index da37c9a..ba5c475 100644 --- a/src/core/tags/ColorPickerTag.ts +++ b/src/core/tags/ColorPickerTag.ts @@ -29,7 +29,7 @@ namespace OS { */ export class ColorPickerTag extends AFXTag { private _selectedColor: ColorType; - private _oncolorselect: TagEventCallback; + private _oncolorselect: TagEventCallback; /** *Creates an instance of ColorPickerTag. @@ -73,7 +73,7 @@ namespace OS { * * @memberof ColorPickerTag */ - set oncolorselect(v: TagEventCallback) { + set oncolorselect(v: TagEventCallback) { this._oncolorselect = v; } diff --git a/src/core/tags/FileViewTag.ts b/src/core/tags/FileViewTag.ts index ec01c93..3640bd1 100644 --- a/src/core/tags/FileViewTag.ts +++ b/src/core/tags/FileViewTag.ts @@ -14,8 +14,8 @@ namespace OS { * @extends {AFXTag} */ export class FileViewTag extends AFXTag { - private _onfileselect: TagEventCallback; - private _onfileopen: TagEventCallback; + private _onfileselect: TagEventCallback; + private _onfileopen: TagEventCallback; private _selectedFile: API.FileInfoType; private _data: API.FileInfoType[]; private _path: string; @@ -72,7 +72,7 @@ namespace OS { * * @memberof FileViewTag */ - set onfileselect(e: TagEventCallback) { + set onfileselect(e: TagEventCallback) { this._onfileselect = e; } @@ -81,7 +81,7 @@ namespace OS { * * @memberof FileViewTag */ - set onfileopen(e: TagEventCallback) { + set onfileopen(e: TagEventCallback) { this._onfileopen = e; } @@ -248,7 +248,7 @@ namespace OS { * * @memberof FileViewTag */ - set ondragndrop(v: TagEventCallback) { + set ondragndrop(v: TagEventCallback>) { (this.refs.treeview as TreeViewTag).ondragndrop = v; (this.refs.listview as ListViewTag).ondragndrop = v; } @@ -525,25 +525,25 @@ namespace OS { list.dragndrop = true; // even handles list.onlistselect = (e) => { - this.fileselect(e.data.item.data); + this.fileselect(e.data.item.data as API.FileInfoType); }; grid.onrowselect = (e) => { this.fileselect( - $(e.data.item).children()[0].data + $(e.data.item).children()[0].data as API.FileInfoType ); }; tree.ontreeselect = (e) => { - this.fileselect(e.data.item.data); + this.fileselect(e.data.item.data as API.FileInfoType); }; // dblclick list.onlistdbclick = (e) => { - this.filedbclick(e.data.item.data); + this.filedbclick(e.data.item.data as API.FileInfoType); }; grid.oncelldbclick = (e) => { - this.filedbclick(e.data.item.data); + this.filedbclick(e.data.item.data as API.FileInfoType); }; tree.ontreedbclick = (e) => { - this.filedbclick(e.data.item.data); + this.filedbclick(e.data.item.data as API.FileInfoType); }; this.switchView(); } diff --git a/src/core/tags/GridViewTag.ts b/src/core/tags/GridViewTag.ts index 9af055d..fb44934 100644 --- a/src/core/tags/GridViewTag.ts +++ b/src/core/tags/GridViewTag.ts @@ -27,20 +27,20 @@ namespace OS { protected calibrate(): void {} protected reload(d?: any): void {} } - + export type CellEventData = TagEventDataType; export abstract class GridCellPrototype extends AFXTag { - private _oncellselect: TagEventCallback; - private _oncelldbclick: TagEventCallback; + private _oncellselect: TagEventCallback; + private _oncelldbclick: TagEventCallback; private _data: GenericObject; constructor() { super(); } - set oncellselect(v: TagEventCallback) { + set oncellselect(v: TagEventCallback) { this._oncellselect = v; } - set oncelldbclick(v: TagEventCallback) { + set oncelldbclick(v: TagEventCallback) { this._oncelldbclick = v; } set data(v: GenericObject) { @@ -77,7 +77,7 @@ namespace OS { protected mount(): void { $(this).attr("class", "afx-grid-cell"); this.oncelldbclick = this.oncellselect = ( - e: TagEventType + e: TagEventType ): void => {}; this.selected = false; $(this).css("display", "block"); @@ -91,7 +91,7 @@ namespace OS { }); } - private cellselect(e: TagEventType, flag: boolean): void { + private cellselect(e: TagEventType, flag: boolean): void { const evt = { id: this.aid, data: { item: e.data } }; if (!flag) { return this._oncellselect(evt); @@ -128,9 +128,9 @@ namespace OS { private _selectedRow: GridRowTag; private _selectedRows: GridRowTag[]; private _selectedCell: GridCellPrototype; - private _oncellselect: TagEventCallback; - private _onrowselect: TagEventCallback; - private _oncelldbclick: TagEventCallback; + private _oncellselect: TagEventCallback; + private _onrowselect: TagEventCallback; + private _oncelldbclick: TagEventCallback; constructor() { super(); } @@ -143,17 +143,17 @@ namespace OS { this._selectedRow = undefined; this._rows = []; this._oncellselect = this._onrowselect = this._oncelldbclick = ( - e: TagEventType + e: TagEventType ): void => {}; } protected reload(d?: any): void {} - set oncellselect(v: TagEventCallback) { + set oncellselect(v: TagEventCallback) { this._oncellselect = v; } - set onrowselect(v: TagEventCallback) { + set onrowselect(v: TagEventCallback) { this._onrowselect = v; } - set oncelldbclick(v: TagEventCallback) { + set oncelldbclick(v: TagEventCallback) { this._oncelldbclick = v; } set headeritem(v: string) { @@ -282,7 +282,7 @@ namespace OS { this.push(row, true); } - cellselect(e: TagEventType, flag: boolean): void { + cellselect(e: TagEventType, flag: boolean): void { e.id = this.aid; // return if e.data.item is selectedCell and not flag if (this.selectedCell) { @@ -300,7 +300,7 @@ namespace OS { } } - rowselect(e: TagEventType): void { + rowselect(e: TagEventType): void { if (!e.data.item) { return; } @@ -311,7 +311,7 @@ namespace OS { items: [], }, }; - const row = $(e.data.item).parent()[0]; + const row = $(e.data.item).parent()[0] as any as GridRowTag; if (this.multiselect) { if (this.selectedRows.includes(row)) { this.selectedRows.splice( diff --git a/src/core/tags/ListViewTag.ts b/src/core/tags/ListViewTag.ts index d54bdcb..376ad98 100644 --- a/src/core/tags/ListViewTag.ts +++ b/src/core/tags/ListViewTag.ts @@ -8,6 +8,7 @@ namespace OS { export namespace GUI { export namespace tag { + export type ListItemEventData = TagEventDataType /** * * @@ -18,11 +19,11 @@ namespace OS { */ export abstract class ListViewItemTag extends AFXTag { private _data: GenericObject; - private _onselect: TagEventCallback; - private _onctxmenu: TagEventCallback; - private _onclick: TagEventCallback; - private _ondbclick: TagEventCallback; - private _onclose: TagEventCallback; + private _onselect: TagEventCallback; + private _onctxmenu: TagEventCallback; + private _onclick: TagEventCallback; + private _ondbclick: TagEventCallback; + private _onclose: TagEventCallback; /** *Creates an instance of ListViewItemTag. @@ -56,7 +57,7 @@ namespace OS { * * @memberof ListViewItemTag */ - set onitemselect(v: TagEventCallback) { + set onitemselect(v: TagEventCallback) { this._onselect = v; } @@ -83,7 +84,7 @@ namespace OS { * * @memberof ListViewItemTag */ - set onctxmenu(v: TagEventCallback) { + set onctxmenu(v: TagEventCallback) { this._onctxmenu = v; } @@ -92,7 +93,7 @@ namespace OS { * * @memberof ListViewItemTag */ - set onitemclick(v: TagEventCallback) { + set onitemclick(v: TagEventCallback) { this._onclick = v; } @@ -101,7 +102,7 @@ namespace OS { * * @memberof ListViewItemTag */ - set onitemdbclick(v: TagEventCallback) { + set onitemdbclick(v: TagEventCallback) { this._ondbclick = v; } @@ -110,7 +111,7 @@ namespace OS { * * @memberof ListViewItemTag */ - set onitemclose(v: TagEventCallback) { + set onitemclose(v: TagEventCallback) { this._onclose = v; } @@ -283,10 +284,10 @@ namespace OS { * @extends {AFXTag} */ export class ListViewTag extends AFXTag { - private _onlistselect: TagEventCallback; - private _onlistdbclick: TagEventCallback; - private _ondragndrop: TagEventCallback; - private _onitemclose: (e: TagEventType) => boolean; + private _onlistselect: TagEventCallback; + private _onlistdbclick: TagEventCallback; + private _ondragndrop: TagEventCallback>; + private _onitemclose: (e: TagEventType) => boolean; private _onmousedown: (e: JQuery.MouseEventBase) => void; private _onmouseup: (e: JQuery.MouseEventBase) => void; private _onmousemove: (e: JQuery.MouseEventBase) => void; @@ -302,9 +303,9 @@ namespace OS { constructor() { super(); this._onlistdbclick = this._onlistselect = this._ondragndrop = ( - e: TagEventType + e: TagEventType ) => {}; - this._onitemclose = (e: TagEventType) => { + this._onitemclose = (e: TagEventType) => { return true; }; this._onmousedown = this._onmouseup = this._onmousemove = ( @@ -384,7 +385,7 @@ namespace OS { * * @memberof ListViewTag */ - set ondragndrop(v: TagEventCallback) { + set ondragndrop(v: TagEventCallback>) { this._ondragndrop = v; } @@ -393,7 +394,7 @@ namespace OS { * * @memberof ListViewTag */ - set onlistselect(v: TagEventCallback) { + set onlistselect(v: TagEventCallback) { this._onlistselect = v; } @@ -402,7 +403,7 @@ namespace OS { * * @memberof ListViewTag */ - set onlistdbclick(v: TagEventCallback) { + set onlistdbclick(v: TagEventCallback) { this._onlistdbclick = v; } @@ -411,7 +412,7 @@ namespace OS { * * @memberof ListViewTag */ - set onitemclose(v: (e: TagEventType) => boolean) { + set onitemclose(v: (e: TagEventType) => boolean) { this._onitemclose = v; } @@ -500,6 +501,7 @@ namespace OS { for (let item of v) { $(this.refs.btlist).show(); const bt = $("").appendTo(this.refs.btlist); + bt[0].uify(this.observable); (bt[0] as ButtonTag).set(item); } } @@ -757,7 +759,7 @@ namespace OS { v.selected = false; } this._selectedItems = []; - return (this._selectedItem = undefined); + this._selectedItem = undefined; } /** @@ -769,7 +771,7 @@ namespace OS { * @returns {void} * @memberof ListViewTag */ - private iclick(e: TagEventType, flag: boolean): void { + private iclick(e: TagEventType, flag: boolean): void { if (!e.data) { return; } @@ -790,8 +792,8 @@ namespace OS { * @returns * @memberof ListViewTag */ - private idbclick(e: TagEventType) { - const evt = { id: this.aid, data: { item: e.data } }; + private idbclick(e: TagEventType) { + const evt: TagEventType = { id: this.aid, data: { item: e.data } }; this._onlistdbclick(evt); return this.observable.trigger("listdbclick", evt); } @@ -804,7 +806,7 @@ namespace OS { * @returns * @memberof ListViewTag */ - private iselect(e: TagEventType) { + private iselect(e: TagEventType) { if (!e.data) { return; } @@ -853,7 +855,6 @@ namespace OS { label.set(e.data.data); $(this.refs.mlist).hide(); } - const evt = { id: this.aid, data: edata }; this._onlistselect(evt); return this.observable.trigger("listselect", evt); @@ -939,7 +940,7 @@ namespace OS { * @returns {void} * @memberof ListViewTag */ - private iclose(e: TagEventType): void { + private iclose(e: TagEventType): void { if (!e.data) { return; } diff --git a/src/core/tags/MenuTag.ts b/src/core/tags/MenuTag.ts index d1a2404..e6a7927 100644 --- a/src/core/tags/MenuTag.ts +++ b/src/core/tags/MenuTag.ts @@ -8,6 +8,7 @@ namespace OS { export namespace GUI { export namespace tag { + export type MenuEventData = TagEventDataType; /** * * @@ -18,8 +19,8 @@ namespace OS { */ export abstract class MenuEntryTag extends AFXTag { private _data: GenericObject; - private _onmenuselect: TagEventCallback; - private _onchildselect: TagEventCallback; + private _onmenuselect: TagEventCallback; + private _onchildselect: TagEventCallback; parent: MenuEntryTag; root: MenuTag; @@ -30,7 +31,7 @@ namespace OS { constructor() { super(); this._onmenuselect = this._onchildselect = ( - e: TagEventType + e: TagEventType ): void => {}; } @@ -48,7 +49,7 @@ namespace OS { * * @memberof MenuEntryTag */ - set onmenuselect(v: TagEventCallback) { + set onmenuselect(v: TagEventCallback) { this._onmenuselect = v; } @@ -57,7 +58,7 @@ namespace OS { * * @memberof MenuEntryTag */ - set onchildselect(v: TagEventCallback) { + set onchildselect(v: TagEventCallback) { this._onchildselect = v; } @@ -67,7 +68,7 @@ namespace OS { * @type {TagEventCallback} * @memberof MenuEntryTag */ - get onchildselect(): TagEventCallback { + get onchildselect(): TagEventCallback { return this._onchildselect; } /** @@ -462,7 +463,7 @@ namespace OS { parent: MenuEntryTag; root: MenuTag; pid: number; - private _onmenuselect: TagEventCallback; + private _onmenuselect: TagEventCallback; private _items: GenericObject[]; /** @@ -483,7 +484,7 @@ namespace OS { this.contentag = "afx-menu-entry"; this.context = false; this._items = []; - this._onmenuselect = (e: TagEventType): void => {}; + this._onmenuselect = (e: TagEventType): void => {}; } /** @@ -554,7 +555,7 @@ namespace OS { * * @memberof MenuTag */ - set onmenuselect(v: TagEventCallback) { + set onmenuselect(v: TagEventCallback) { this._onmenuselect = v; } @@ -584,7 +585,7 @@ namespace OS { * @type {TagEventCallback} * @memberof MenuTag */ - get onmenuitemselect(): TagEventCallback { + get onmenuitemselect(): TagEventCallback { return this.handleselect; } @@ -595,7 +596,7 @@ namespace OS { * @param {TagEventType} e * @memberof MenuTag */ - private handleselect(e: TagEventType): void { + private handleselect(e: TagEventType): void { if (this.context) { $(this).hide(); } diff --git a/src/core/tags/NSpinnerTag.ts b/src/core/tags/NSpinnerTag.ts index 37e9a24..356c5c1 100644 --- a/src/core/tags/NSpinnerTag.ts +++ b/src/core/tags/NSpinnerTag.ts @@ -15,7 +15,7 @@ namespace OS { * @extends {AFXTag} */ export class NSpinnerTag extends AFXTag { - private _onchange: TagEventCallback; + private _onchange: TagEventCallback; private _value: number; step: number; @@ -50,7 +50,7 @@ namespace OS { * * @memberof NSpinnerTag */ - set onvaluechange(f: TagEventCallback) { + set onvaluechange(f: TagEventCallback) { this._onchange = f; } diff --git a/src/core/tags/SliderTag.ts b/src/core/tags/SliderTag.ts index 4c2f857..53f54e3 100644 --- a/src/core/tags/SliderTag.ts +++ b/src/core/tags/SliderTag.ts @@ -15,8 +15,8 @@ namespace OS { class SliderTag extends AFXTag { private _max: number; private _value: number; - private _onchange: TagEventCallback; - private _onchanging: TagEventCallback; + private _onchange: TagEventCallback; + private _onchanging: TagEventCallback; /** *Creates an instance of SliderTag. @@ -53,7 +53,7 @@ namespace OS { * * @memberof SliderTag */ - set onvaluechange(f: TagEventCallback) { + set onvaluechange(f: TagEventCallback) { this._onchange = f; } @@ -62,7 +62,7 @@ namespace OS { * * @memberof SliderTag */ - set onvaluechanging(f: TagEventCallback) { + set onvaluechanging(f: TagEventCallback) { this._onchanging = f; } diff --git a/src/core/tags/SwitchTag.ts b/src/core/tags/SwitchTag.ts index e5020e3..a534639 100644 --- a/src/core/tags/SwitchTag.ts +++ b/src/core/tags/SwitchTag.ts @@ -7,8 +7,8 @@ namespace OS { export namespace GUI { export namespace tag { export class SwitchTag extends AFXTag { - private _onchange: TagEventCallback; - private _onchanging: TagEventCallback; + private _onchange: TagEventCallback; + private _onchanging: TagEventCallback; constructor() { super(); @@ -34,7 +34,7 @@ namespace OS { return this.hasattr("enable"); } - set onswchange(v: TagEventCallback) { + set onswchange(v: TagEventCallback) { this._onchange = v; } diff --git a/src/core/tags/TabBarTag.ts b/src/core/tags/TabBarTag.ts index b4329b1..6333c9a 100644 --- a/src/core/tags/TabBarTag.ts +++ b/src/core/tags/TabBarTag.ts @@ -7,7 +7,7 @@ namespace OS { export namespace GUI { export namespace tag { - + type TabEventData = TagEventDataType; /** * * @@ -17,8 +17,8 @@ namespace OS { */ export class TabBarTag extends AFXTag { private _selected: number; - private _ontabclose: (e: TagEventType) => boolean; - private _ontabselect: TagEventCallback; + private _ontabclose: (e: TagEventType) => boolean; + private _ontabselect: TagEventCallback; /** *Creates an instance of TabBarTag. @@ -146,7 +146,7 @@ namespace OS { * * @memberof TabBarTag */ - set ontabclose(v: (e: TagEventType) => boolean) { + set ontabclose(v: (e: TagEventType) => boolean) { this._ontabclose = v; } @@ -155,7 +155,7 @@ namespace OS { * * @memberof TabBarTag */ - set ontabselect(v: TagEventCallback) { + set ontabselect(v: TagEventCallback) { this._ontabselect = v; } diff --git a/src/core/tags/TabContainerTag.ts b/src/core/tags/TabContainerTag.ts index 2cb648b..32e2760 100644 --- a/src/core/tags/TabContainerTag.ts +++ b/src/core/tags/TabContainerTag.ts @@ -19,7 +19,7 @@ namespace OS { */ export class TabContainerTag extends AFXTag { private _selectedTab: TabContainerTabType; - private _ontabselect: TagEventCallback; + private _ontabselect: TagEventCallback; /** *Creates an instance of TabContainerTag. @@ -27,7 +27,6 @@ namespace OS { */ constructor() { super(); - this.dir = "column"; // or row this._ontabselect = (e) => {}; } @@ -38,7 +37,9 @@ namespace OS { * @protected * @memberof TabContainerTag */ - protected init(): void {} + protected init(): void { + this.dir = "column"; // or row + } /** * @@ -54,7 +55,7 @@ namespace OS { * * @memberof TabContainerTag */ - set ontabselect(f: TagEventCallback) { + set ontabselect(f: TagEventCallback) { this._ontabselect = f; } @@ -145,22 +146,25 @@ namespace OS { this.selectedTab = data; return this._ontabselect({ data: data, id: this.aid }); }; - $(this.children).each((i, e) => { - const item = {} as GenericObject; - if ($(e).attr("tabname")) { - item.text = $(e).attr("tabname"); - } - if ($(e).attr("icon")) { - item.icon = $(e).attr("icon"); - } - if ($(e).attr("iconclass")) { - item.iconclass = $(e).attr("iconclass"); - } - item.container = e; - $(e).css("width", "100%").css("height", "100%"); - const el = (this.refs.bar as TabBarTag).push(item); - el.selected = true; - }); + this.observable.one("mounted", (id)=>{ + $(this.refs.yield).children().each((i, e) => { + const item = {} as GenericObject; + if ($(e).attr("tabname")) { + item.text = $(e).attr("tabname"); + } + if ($(e).attr("icon")) { + item.icon = $(e).attr("icon"); + } + if ($(e).attr("iconclass")) { + item.iconclass = $(e).attr("iconclass"); + } + item.container = e; + $(e).css("width", "100%").css("height", "100%").hide(); + const el = (this.refs.bar as TabBarTag).push(item); + el.selected = true; + }); + }) + this.observable.on("resize", (e) => this.calibrate()); this.calibrate(); } diff --git a/src/core/tags/TreeViewTag.ts b/src/core/tags/TreeViewTag.ts index e6dfcaf..a82cb9e 100644 --- a/src/core/tags/TreeViewTag.ts +++ b/src/core/tags/TreeViewTag.ts @@ -21,7 +21,7 @@ namespace OS { selected?: boolean; [propName: string]: any; } - + export type TreeItemEventData = TagEventDataType; /** * * @@ -31,7 +31,7 @@ namespace OS { export abstract class TreeViewItemPrototype extends AFXTag { private _data: TreeViewDataType; private _indent: number; - private _evt: TagEventType; + private _evt: TagEventType; treeroot: TreeViewTag; treepath: string; parent: TreeViewTag; @@ -418,9 +418,9 @@ namespace OS { */ export class TreeViewTag extends AFXTag { private _selectedItem: TreeViewItemPrototype; - private _ontreeselect: TagEventCallback; - private _ontreedbclick: TagEventCallback; - private _ondragndrop: TagEventCallback; + private _ontreeselect: TagEventCallback; + private _ontreedbclick: TagEventCallback; + private _ondragndrop: TagEventCallback>; private _data: TreeViewDataType; private _treemousedown: (e: JQuery.MouseEventBase) => void; private _treemouseup: (e: JQuery.MouseEventBase) => void; @@ -504,7 +504,7 @@ namespace OS { * * @memberof TreeViewTag */ - set ontreeselect(v: TagEventCallback) { + set ontreeselect(v: TagEventCallback) { this._ontreeselect = v; } @@ -513,7 +513,7 @@ namespace OS { * * @memberof TreeViewTag */ - set ontreedbclick(v: TagEventCallback) { + set ontreedbclick(v: TagEventCallback) { this._ontreedbclick = v; } @@ -605,7 +605,7 @@ namespace OS { * @returns {void} * @memberof TreeViewTag */ - itemclick(e: TagEventType): void { + itemclick(e: TagEventType): void { if (!e || !e.data) { return; } @@ -656,7 +656,7 @@ namespace OS { * * @memberof TreeViewTag */ - set ondragndrop(v: TagEventCallback) { + set ondragndrop(v: TagEventCallback>) { this._ondragndrop = v; } diff --git a/src/core/tags/tag.ts b/src/core/tags/tag.ts index 153c919..1a21d00 100644 --- a/src/core/tags/tag.ts +++ b/src/core/tags/tag.ts @@ -9,7 +9,7 @@ interface HTMLElement { contextmenuHandle(e: JQuery.MouseEventBase, m: OS.GUI.tag.MenuTag): void; sync(): void; afxml(o: OS.API.Announcer): void; - uify(o: OS.API.Announcer): void; + uify(o: OS.API.Announcer, flag?: boolean): void; mozRequestFullScreen: any; webkitRequestFullscreen: any; msRequestFullscreen: any; @@ -32,12 +32,21 @@ namespace OS { width?: number; height?: number; } - export interface TagEventType { + export interface TagEventDataType { + item?: T, + [propName:string]: any; + } + export interface TagEventType{ id: number | string; - data: any; + data: T; } - export type TagEventCallback = (e: TagEventType) => void; + export interface DnDEventDataType { + from: T; + to: T; + } + + export type TagEventCallback = (e: TagEventType) => void; export var zindex: number = 10; export abstract class AFXTag extends HTMLElement { @@ -91,7 +100,6 @@ namespace OS { return; } this._mounted = true; - // reflect attributes this.mount(); super.sync(); } @@ -221,9 +229,11 @@ namespace OS { return this.afxml(o); }); } - HTMLElement.prototype.uify = function(o: API.Announcer): void { + HTMLElement.prototype.uify = function(o: API.Announcer, toplevel?: boolean): void { this.afxml(o); this.sync(); + if(o && toplevel) + o.trigger("mounted", this.aid); } export namespace tag { diff --git a/src/core/vfs.ts b/src/core/vfs.ts index 9543bef..ca0493e 100644 --- a/src/core/vfs.ts +++ b/src/core/vfs.ts @@ -134,6 +134,7 @@ namespace OS { basename: string; info: FileInfoType; ext: string; + type: string; /** *Creates an instance of BaseFileHandle. * @param {string} path @@ -187,13 +188,22 @@ namespace OS { * @returns {string} * @memberof BaseFileHandle */ - filename(): string { + get filename(): string { if (!this.basename) { return "Untitled"; } return this.basename; } + /** + * + * + * @memberof BaseFileHandle + */ + set filename(v: string) + { + this.basename = v; + } /** * * diff --git a/src/packages/CodePad/AntOSDK.ts b/src/packages/CodePad/AntOSDK.ts index efec049..399bce9 100644 --- a/src/packages/CodePad/AntOSDK.ts +++ b/src/packages/CodePad/AntOSDK.ts @@ -373,9 +373,9 @@ namespace OS { v.iconclass = "fa fa-adn"; } this.notify(__("Installing...")); - this.app.systemsetting.system.packages[meta.name] = v; + setting.system.packages[meta.name] = v; this.notify(__("Running {0}...", meta.name)); - return this.app._gui.forceLaunch(meta.name, []); + return GUI.forceLaunch(meta.name, []); }); } } diff --git a/src/packages/CodePad/BaseExtension.ts b/src/packages/CodePad/BaseExtension.ts index f2d8ec9..d501873 100644 --- a/src/packages/CodePad/BaseExtension.ts +++ b/src/packages/CodePad/BaseExtension.ts @@ -347,7 +347,7 @@ namespace OS { .parent() .mk(path.basename) .then((d: any) => { - this.app.trigger("filechange", { + this.app.observable.trigger("filechange", { file: path.parent(), type: "dir", }); @@ -414,7 +414,7 @@ namespace OS { return new Promise((resolve, reject) => { if (!this.app.currdir) { return reject( - this.app._api.throwe(__("Current folder is not found")) + API.throwe(__("Current folder is not found")) ); } `${this.app.currdir.path}/${file}` @@ -423,7 +423,7 @@ namespace OS { .then((data) => resolve(data)) .catch((e) => { return reject( - this.app._api.throwe(__("Unable to read meta-data")) + API.throwe(__("Unable to read meta-data")) ); }); }); diff --git a/src/packages/CodePad/ExtensionMaker.ts b/src/packages/CodePad/ExtensionMaker.ts index 7097eb6..2e8e12f 100644 --- a/src/packages/CodePad/ExtensionMaker.ts +++ b/src/packages/CodePad/ExtensionMaker.ts @@ -282,11 +282,11 @@ namespace OS { private run(meta: GenericObject): Promise { return new Promise(async (resolve, reject) => { const path = `${meta.root}/build/debug/${meta.meta.name}.js`; - if (this.app._api.shared[path]) { - delete this.app._api.shared[path]; + if (API.shared[path]) { + delete API.shared[path]; } try { - await this.app._api.requires(path); + await API.requires(path); let v: GenericObject; if (this.app.extensions[meta.meta.name]) { this.app.extensions[meta.meta.name].child = []; @@ -306,9 +306,9 @@ namespace OS { this.app.extensions[meta.meta.name] ); this.app.extensions[meta.meta.name].onchildselect( - (e: GUI.TagEventType) => { + (e: GUI.TagEventType) => { return this.app.loadAndRunExtensionAction( - e.data.item.data + e.data.item.data as any ); } ); @@ -334,7 +334,7 @@ namespace OS { return new Promise((resolve, reject) => { const idx = files.indexOf("extension.json"); if (idx < 0) { - reject(this.app._api.throwe(__("No meta-data found"))); + reject(API.throwe(__("No meta-data found"))); } const metafile = files.splice(idx, 1)[0]; // read the meta file diff --git a/src/packages/CodePad/main.ts b/src/packages/CodePad/main.ts index 9dae4a2..f75b668 100644 --- a/src/packages/CodePad/main.ts +++ b/src/packages/CodePad/main.ts @@ -178,7 +178,9 @@ namespace OS { if (e.data.type === "dir") { return; } - return this.openFile(e.data.path.asFileHandle()); + return this.openFile( + e.data.path.asFileHandle() as CodePadFileHandle + ); }; this.fileview.onfileselect = (e) => { @@ -188,7 +190,9 @@ namespace OS { if (e.data.type === "dir") { return; } - const i = this.findTabByFile(e.data.path.asFileHandle()); + const i = this.findTabByFile( + e.data.path.asFileHandle() as CodePadFileHandle + ); if (i !== -1) { return (this.tabbar.selected = i); } @@ -202,7 +206,9 @@ namespace OS { m.items = [ { text: __("Command palete"), - onmenuselect: (e: GUI.TagEventType) => { + onmenuselect: ( + e: GUI.TagEventType + ) => { return this.spotlight.run(this); }, }, @@ -237,17 +243,19 @@ namespace OS { .then(function (d: any) { const p1 = des; const p2 = src.parent().path; - if(p1.length < p2.length) - { + if (p1.length < p2.length) { e.data.to.update(p1); - e.data.from.parent.update(p2); - } - else - { - e.data.from.parent.update(p2); + (e.data + .from as GUI.tag.TreeViewTag).parent.update( + p2 + ); + } else { + (e.data + .from as GUI.tag.TreeViewTag).parent.update( + p2 + ); e.data.to.update(p1); } - }) .catch((e: Error) => this.error(__("Unable to move file/folder"), e) @@ -268,7 +276,6 @@ namespace OS { return this.openFile(this.currfile); } - /** * * @@ -443,7 +450,6 @@ namespace OS { this.langstat.text = this.currfile.langmode.caption; } - /** * * @@ -500,7 +506,7 @@ namespace OS { cmdtheme.addAction({ text: v.caption, theme: v.theme }); } cmdtheme.onchildselect(function ( - d: GUI.TagEventType, + d: GUI.TagEventType, r: CodePad ) { const data = d.data.item.data; @@ -513,7 +519,7 @@ namespace OS { cmdmode.addAction({ text: v.caption, mode: v.mode }); } cmdmode.onchildselect(function ( - d: GUI.TagEventType, + d: GUI.TagEventType, r: CodePad ) { const data = d.data.item.data; @@ -529,7 +535,6 @@ namespace OS { this.addAction(CMDMenu.fromMenu(this.fileMenu())); } - /** * * @@ -558,9 +563,13 @@ namespace OS { this.extensions[ext.name] ); this.extensions[ext.name].onchildselect( - (e: GUI.TagEventType) => { + ( + e: GUI.TagEventType< + GUI.tag.ListItemEventData + > + ) => { return this.loadAndRunExtensionAction( - e.data.item.data + e.data.item.data as any ); } ); @@ -601,7 +610,6 @@ namespace OS { }); } - /** * * @@ -660,7 +668,10 @@ namespace OS { shortcut: "A-W", }, ], - onchildselect: (e: GUI.TagEventType, r: CodePad) => { + onchildselect: ( + e: GUI.TagEventType, + r: CodePad + ) => { return this.menuAction(e.data.item.data.dataid, r); }, }; @@ -674,7 +685,9 @@ namespace OS { * @returns {void} * @memberof CodePad */ - private ctxFileMenuHandle(e: GUI.TagEventType): void { + private ctxFileMenuHandle( + e: GUI.TagEventType + ): void { const el = e.data.item as GUI.tag.MenuEntryTag; if (!el) { return; @@ -949,7 +962,7 @@ namespace OS { }, ], onchildselect: ( - e: GUI.TagEventType, + e: GUI.TagEventType, r: CodePadFileHandle ) => { return this.spotlight.run(this); @@ -969,7 +982,10 @@ namespace OS { private shortcut: string; nodes: GenericObject[]; parent: CMDMenu; - private select: (e: GUI.TagEventType, r: CodePad) => void; + private select: ( + e: GUI.TagEventType, + r: CodePad + ) => void; static fromMenu: (mn: GUI.BasicItemType) => CMDMenu; /** @@ -1017,7 +1033,10 @@ namespace OS { * @memberof CMDMenu */ onchildselect( - f: (e: GUI.TagEventType, r: CodePad) => void + f: ( + e: GUI.TagEventType, + r: CodePad + ) => void ): CMDMenu { this.select = f; return this; @@ -1093,7 +1112,10 @@ namespace OS { const offset = $(".afx-window-content", win).offset(); const pw = win.width / 5; (this.scheme as GUI.tag.WindowTag).width = 3 * pw; - $(this.scheme).offset({ top: offset.top - 2, left: offset.left + pw }); + $(this.scheme).offset({ + top: offset.top - 2, + left: offset.left + pw, + }); var cb = (e: JQuery.MouseEventBase) => { if ($(e.target).closest(this.scheme).length > 0) { return $(this.find("searchbox")).focus(); diff --git a/src/packages/Files/Makefile b/src/packages/Files/Makefile index 71eb285..0fc8539 100644 --- a/src/packages/Files/Makefile +++ b/src/packages/Files/Makefile @@ -7,5 +7,5 @@ cssfiles = main.css copyfiles = scheme.html package.json -PKG_NAME=ActivityFile +PKG_NAME=Files include ../pkg.mk \ No newline at end of file diff --git a/src/packages/Files/main.js b/src/packages/Files/main.js deleted file mode 100644 index a315445..0000000 --- a/src/packages/Files/main.js +++ /dev/null @@ -1,424 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS208: Avoid top-level this - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class Files extends this.OS.GUI.BaseApplication { - constructor(args) { - super("Files", args); - } - - main() { - this.scheme.set("apptitle", "Files manager"); - this.view = this.find("fileview"); - this.navinput = this.find("navinput"); - this.navbar = this.find("nav-bar"); - if (this.args && (this.args.length > 0)) { - this.currdir = this.args[0].path.asFileHandle(); - } else { - this.currdir = "home://".asFileHandle(); - } - this.favo = this.find("favouri"); - this.clipboard = undefined; - this.viewType = this._api.switcher("icon", "list", "tree"); - this.viewType.list = true; - - this.view.contextmenuHandle = (e, m) => { - const file = this.view.get("selectedFile"); - if (!file) { return; } - const apps = []; - if (file.type === "dir") { file.mime = "dir"; } - - for (let v of Array.from(this._gui.appsByMime(file.mime))) { - apps.push({ - text: v.text, - app: v.app, - icon: v.icon, - iconclass: v.iconclass - }); - } - - m.set("items", [ - { - text: "__(Open with)", - child: apps, - onchildselect: e => { - if (!e) { return; } - const it = e.data.item.get("data"); - return this._gui.launch(it.app, [file]); - } - }, - this.mnFile(), - this.mnEdit() - ]); - return m.show(e); - }; - - this.view.set("onfileopen", e => { - if (!e.data) { return; } - if (e.data.type === "dir") { return; } - return this._gui.openWith(e.data); - }); - - this.favo.set("onlistselect", e => { - return this.view.set("path", e.data.item.get("data").path); - }); - - ($(this.find("btback"))).click(() => { - if (this.currdir.isRoot()) { return; } - const p = this.currdir.parent(); - this.favo.set("selected", -1); - return this.view.set("path", p.path); - }); - - ($(this.navinput)).keyup(e => { - if (e.keyCode === 13) { return this.view.set("path", ($(this.navinput)).val()); } - }); //enter - - this.view.set("fetch", path => { - return new Promise((resolve, reject) => { - let dir = path; - if (typeof path === "string") { dir = path.asFileHandle(); } - return dir.read().then(d => { - if (d.error) { return reject(d.error); } - if (!dir.isRoot()) { - const p = dir.parent(); - p.filename = "[..]"; - p.type = "dir"; - d.result.unshift(p); - } - this.currdir = dir; - ($(this.navinput)).val(dir.path); - return resolve(d.result); - }).catch(e => reject(__e(e))); - }); - }); - - this.vfs_event_flag = true; - this.view.set("ondragndrop", e => { - if (!e) { return; } - const src = e.data.from.get("data"); - const des = e.data.to.get("data"); - if (des.type === "file") { return; } - const file = src.path.asFileHandle(); - // disable the vfs event on - // we update it manually - this.vfs_event_flag = false; - return file.move(`${des.path}/${file.basename}`) - .then(() => { - if (this.view.get("view") === "icon") { - this.view.set("path", this.view.get("path")); - } else { - this.view.update(file.parent().path); - this.view.update(des.path); - } - //reenable the vfs event - return this.vfs_event_flag = true; - }).catch(e => { - // reenable the vfs event - this.vfs_event_flag = true; - return this.error(__("Unable to move: {0} -> {1}", src.path, des.path), e); - }); - }); - - // application setting - if (this.setting.sidebar === undefined) { this.setting.sidebar = true; } - if (this.setting.nav === undefined) { this.setting.nav = true; } - if (this.setting.showhidden === undefined) { this.setting.showhidden = false; } - this.applyAllSetting(); - - // VFS mount point and event - const mntpoints = this.systemsetting.VFS.mountpoints; - for (let i = 0; i < mntpoints.length; i++) { const el = mntpoints[i]; el.selected = false; } - this.favo.set("data", mntpoints); - //@favo.set "selected", -1 - if (this.setting.view) { this.view.set("view", this.setting.view); } - this.subscribe("VFS", d => { - if (!this.vfs_event_flag) { return; } - if (["read", "publish", "download"].includes(d.data.m)) { return; } - if ((d.data.file.hash() === this.currdir.hash()) || - (d.data.file.parent().hash() === this.currdir.hash())) { - return this.view.set("path", this.currdir); - } - }); - - // bind keyboard shortcut - this.bindKey("CTRL-F", () => this.actionFile(`${this.name}-mkf`)); - this.bindKey("CTRL-D", () => this.actionFile(`${this.name}-mkdir`)); - this.bindKey("CTRL-U", () => this.actionFile(`${this.name}-upload`)); - this.bindKey("CTRL-S", () => this.actionFile(`${this.name}-share`)); - this.bindKey("CTRL-I", () => this.actionFile(`${this.name}-info`)); - - this.bindKey("CTRL-R", () => this.actionEdit(`${this.name}-mv`)); - this.bindKey("CTRL-M", () => this.actionEdit(`${this.name}-rm`)); - this.bindKey("CTRL-X", () => this.actionEdit(`${this.name}-cut`)); - this.bindKey("CTRL-C", () => this.actionEdit(`${this.name}-copy`)); - this.bindKey("CTRL-P", () => this.actionEdit(`${this.name}-paste`)); - - (this.find("btgrid")).set("onbtclick", e => { - this.view.set('view', "icon"); - return this.viewType.icon = true; - }); - - (this.find("btlist")).set("onbtclick", e => { - this.view.set('view', "list"); - return this.viewType.list = true; - }); - return this.view.set("path", this.currdir); - } - - applySetting(k) { - // view setting - switch (k) { - case "showhidden": return this.view.set("showhidden", this.setting.showhidden); - case "nav": return this.toggleNav(this.setting.nav); - case "sidebar": return this.toggleSidebar(this.setting.sidebar); - } - } - - mnFile() { - //console.log file - const arr = { - text: "__(File)", - child: [ - { text: "__(New file)", dataid: `${this.name}-mkf`, shortcut: 'C-F' }, - { text: "__(New folder)", dataid: `${this.name}-mkdir`, shortcut: 'C-D' }, - { text: "__(Upload)", dataid: `${this.name}-upload`, shortcut: 'C-U' }, - { text: "__(Download)", dataid: `${this.name}-download` }, - { text: "__(Share file)", dataid: `${this.name}-share`, shortcut: 'C-S' }, - { text: "__(Properties)", dataid: `${this.name}-info`, shortcut: 'C-I' } - ], onchildselect: e => this.actionFile(e.data.item.get("data").dataid) - }; - return arr; - } - mnEdit() { - return { - text: "__(Edit)", - child: [ - { text: "__(Rename)", dataid: `${this.name}-mv`, shortcut: 'C-R' }, - { text: "__(Delete)", dataid: `${this.name}-rm`, shortcut: 'C-M' }, - { text: "__(Cut)", dataid: `${this.name}-cut`, shortcut: 'C-X' }, - { text: "__(Copy)", dataid: `${this.name}-copy`, shortcut: 'C-C' }, - { text: "__(Paste)", dataid: `${this.name}-paste`, shortcut: 'C-P' } - ], onchildselect: e => this.actionEdit(e.data.item.get("data").dataid) - }; - } - menu() { - - const menu = [ - this.mnFile(), - this.mnEdit(), - { - text: "__(View)", - child: [ - { text: "__(Refresh)", dataid: `${this.name}-refresh` }, - { text: "__(Sidebar)", switch: true, checked: this.setting.sidebar, dataid: `${this.name}-side` }, - { text: "__(Navigation bar)", switch: true, checked: this.setting.nav, dataid: `${this.name}-nav` }, - { text: "__(Hidden files)", switch: true, checked: this.setting.showhidden, dataid: `${this.name}-hidden` }, - { text: "__(Type)", child: [ - { text: "__(Icon view)", radio: true, checked: this.viewType.icon, dataid: `${this.name}-icon`, type: 'icon' }, - { text: "__(List view)", radio:true, checked: this.viewType.list, dataid: `${this.name}-list`, type: 'list' }, - { text: "__(Tree view)", radio:true, checked: this.viewType.tree, dataid: `${this.name}-tree`, type: 'tree' } - ], onchildselect: e => { - const { - type - } = e.data.item.get("data"); - this.view.set('view', type); - return this.viewType[type] = true; - } - }, - ], onchildselect: e => this.actionView(e) - }, - ]; - return menu; - } - - toggleSidebar(b) { - if (b) { ($(this.favo)).show(); } else { ($(this.favo)).hide(); } - return this.trigger("resize"); - } - - toggleNav(b) { - if (b) { ($(this.navbar)).show(); } else { ($(this.navbar)).hide(); } - return this.trigger("resize"); - } - - actionView(e) { - const data = e.data.item.get("data"); - switch (data.dataid) { - case `${this.name}-hidden`: - //@.view.set "showhidden", e.item.data.checked - return this.registry("showhidden", data.checked); - //@.setting.showhidden = e.item.data.checked - case `${this.name}-refresh`: - return this.chdir(null); - case `${this.name}-side`: - return this.registry("sidebar", data.checked); - //@setting.sidebar = e.item.data.checked - //@toggleSidebar e.item.data.checked - case `${this.name}-nav`: - return this.registry("nav", data.checked); - } - } - //@setting.nav = e.item.data.checked - //@toggleNav e.item.data.checked - - actionEdit(e) { - const file = this.view.get("selectedFile"); - switch (e) { - case `${this.name}-mv`: - if (!file) { return; } - return this.openDialog("PromptDialog", { - title: "__(Rename)", - label: "__(File name)", - value: file.filename - }) - .then(d => { - if (d === file.filename) { return; } - return file.path.asFileHandle().move(`${this.currdir.path}/${d}`) - .catch(e => { - return this.error(__("Fail to rename: {0}", file.path), e); - }); - }); - - case `${this.name}-rm`: - if (!file) { return; } - return this.openDialog("YesNoDialog", { - title: "__(Delete)", - iconclass: "fa fa-question-circle", - text: __("Do you really want to delete: {0}?", file.filename) - }) - .then(d => { - if (!d) { return; } - return file.path.asFileHandle().remove() - .catch(e => { - return this.error(__("Fail to delete: {0}", file.path), e); - }); - }); - - case `${this.name}-cut`: - if (!file) { return; } - this.clipboard = { - cut: true, - file: file.path.asFileHandle() - }; - return this.notify(__("File {0} cut", file.filename)); - - case `${this.name}-copy`: - if (!file && (file.type !== "dir")) { return; } - this.clipboard = { - cut: false, - file: file.path.asFileHandle() - }; - return this.notify(__("File {0} copied", file.filename)); - - case `${this.name}-paste`: - if (!this.clipboard) { return; } - if (this.clipboard.cut) { - return this.clipboard.file.move(`${this.currdir.path}/${this.clipboard.file.basename}`) - .then(r => { - return this.clipboard = undefined; - }).catch(e => { - return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e); - }); - } else { - return this.clipboard.file.read("binary") - .then(d => { - const blob = new Blob([d], { type: this.clipboard.file.info.mime }); - const fp = `${this.currdir.path}/${this.clipboard.file.basename}`.asFileHandle(); - fp.cache = blob; - return fp.write(this.clipboard.file.info.mime) - .then(r => { - return this.clipboard = undefined; - }).catch(e => { - return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e); - }); - }).catch(e => { - return this.error(__("Fail to read: {0}", this.clipboard.file.path), e); - }); - } - default: - return this._api.handle.setting(); - } - } - - actionFile(e) { - const file = this.view.get("selectedFile"); - switch (e) { - case `${this.name}-mkdir`: - return this.openDialog("PromptDialog", { - title: "__(New folder)", - label: "__(Folder name)" - }) - .then(d => { - return this.currdir.mk(d) - .catch(e => { - return this.error(__("Fail to create: {0}", d), e); - }); - }); - - case `${this.name}-mkf`: - return this.openDialog("PromptDialog", { - title: "__(New file)", - label: "__(File name)" - }) - .then(d => { - const fp = `${this.currdir.path}/${d}`.asFileHandle(); - return fp.write("text/plain") - .catch(e => { - return this.error(__("Fail to create: {0}", fp.path)); - }); - }); - - case `${this.name}-info`: - if (!file) { return; } - return this.openDialog("InfoDialog", file); - - case `${this.name}-upload`: - return this.currdir.upload() - .catch(e => { - return this.error(__("Fail to upload: {0}", e.toString()), e); - }); - - case `${this.name}-share`: - if (!file || (file.type !== "file")) { return; } - return file.path.asFileHandle().publish() - .then(r => { - return this.notify(__("Shared url: {0}", r.result)); - }).catch(e => { - return this.error(__("Fail to publish: {0}", file.path), e); - }); - - case `${this.name}-download`: - if (file.type !== "file") { return; } - return file.path.asFileHandle().download() - .catch(e => { - return this.error(__("Fail to download: {0}", file.path), e); - }); - default: - return console.log(e); - } - } -} - -this.OS.register("Files", Files); \ No newline at end of file diff --git a/src/packages/Files/main.ts b/src/packages/Files/main.ts new file mode 100644 index 0000000..fce7a05 --- /dev/null +++ b/src/packages/Files/main.ts @@ -0,0 +1,699 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS208: Avoid top-level this + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 application { + + interface FilesClipboardType { + cut: boolean; + file: API.VFS.BaseFileHandle; + } + interface FilesViewType { + icon: boolean; + list: boolean; + tree: boolean; + } + /** + * + * + * @export + * @class Files + * @extends {BaseApplication} + */ + export class Files extends BaseApplication { + private view: GUI.tag.FileViewTag; + private navinput: HTMLInputElement; + private navbar: GUI.tag.HBoxTag; + private currdir: API.VFS.BaseFileHandle; + private favo: GUI.tag.ListViewTag; + private clipboard: FilesClipboardType; + private viewType: FilesViewType; + private vfs_event_flag: boolean; + constructor(args: AppArgumentsType[]) { + super("Files", args); + } + + + /** + * + * + * @returns + * @memberof Files + */ + main(): void { + this.view = this.find("fileview") as GUI.tag.FileViewTag; + this.navinput = this.find("navinput") as HTMLInputElement; + this.navbar = this.find("nav-bar") as GUI.tag.HBoxTag; + if (this.args && this.args.length > 0) { + this.currdir = this.args[0].path.asFileHandle(); + } else { + this.currdir = "home://".asFileHandle(); + } + this.favo = this.find("favouri") as GUI.tag.ListViewTag; + this.clipboard = undefined; + this.viewType = this._api.switcher("icon", "list", "tree"); + this.viewType.list = true; + + this.view.contextmenuHandle = (e, m) => { + const file = this.view.selectedFile; + if (!file) { + return; + } + const apps = []; + if (file.type === "dir") { + file.mime = "dir"; + } + + for (let v of this._gui.appsByMime(file.mime)) { + apps.push({ + text: v.text, + app: v.app, + icon: v.icon, + iconclass: v.iconclass, + }); + } + + m.items = [ + { + text: "__(Open with)", + nodes: apps, + onchildselect: (e: GUI.TagEventType) => { + if (!e) { + return; + } + const it = e.data.item.data; + return this._gui.launch(it.app, [file]); + }, + }, + this.mnFile(), + this.mnEdit(), + ]; + m.show(e); + }; + + this.view.onfileopen = (e) => { + if (!e.data) { + return; + } + if (e.data.type === "dir") { + return; + } + return this._gui.openWith(e.data); + }; + + this.favo.onlistselect = (e) => { + return this.view.path = e.data.item.data.path; + }; + + (this.find("btback") as GUI.tag.ButtonTag).onbtclick = () => { + if (this.currdir.isRoot()) { + return; + } + const p = this.currdir.parent(); + this.favo.selected = -1; + return this.view.path = p.path; + }; + + $(this.navinput).keyup((e) => { + if (e.keyCode === 13) { + return this.view.path = $(this.navinput).val() as string; + } + }); //enter + + this.view.fetch = (path) => { + return new Promise((resolve, reject) => { + let dir = path.asFileHandle(); + dir + .read() + .then((d) => { + if (d.error) { + return reject(d.error); + } + if (!dir.isRoot()) { + const p = dir.parent(); + p.filename = "[..]"; + p.type = "dir"; + d.result.unshift(p); + } + this.currdir = dir; + $(this.navinput).val(dir.path); + return resolve(d.result); + }) + .catch((e) => reject(__e(e))); + }); + }; + + this.vfs_event_flag = true; + this.view.ondragndrop = (e) => { + if (!e) { + return; + } + const src = e.data.from.data; + const des = e.data.to.data; + if (des.type === "file") { + return; + } + const file = src.path.asFileHandle(); + // disable the vfs event on + // we update it manually + this.vfs_event_flag = false; + return file + .move(`${des.path}/${file.basename}`) + .then(() => { + if (this.view.view === "icon") { + this.view.path = this.view.path; + } else { + this.view.update(file.parent().path); + this.view.update(des.path); + } + //reenable the vfs event + return (this.vfs_event_flag = true); + }) + .catch((e: Error) => { + // reenable the vfs event + this.vfs_event_flag = true; + return this.error( + __( + "Unable to move: {0} -> {1}", + src.path, + des.path + ), + e + ); + }); + }; + + // application setting + if (this.setting.sidebar === undefined) { + this.setting.sidebar = true; + } + if (this.setting.nav === undefined) { + this.setting.nav = true; + } + if (this.setting.showhidden === undefined) { + this.setting.showhidden = false; + } + this.applyAllSetting(); + + // VFS mount point and event + const mntpoints = []; + for(let v of this.systemsetting.VFS.mountpoints) + { + mntpoints.push({ + text: v.text, + path: v.path, + selected: false + }); + } + this.favo.data = mntpoints; + //@favo.set "selected", -1 + if (this.setting.view) { + this.view.view = this.setting.view; + } + this.subscribe("VFS", (d) => { + if (!this.vfs_event_flag) { + return; + } + if (["read", "publish", "download"].includes(d.data.m)) { + return; + } + if ( + d.data.file.hash() === this.currdir.hash() || + d.data.file.parent().hash() === this.currdir.hash() + ) { + return this.view.path = this.currdir.path; + } + }); + + // bind keyboard shortcut + this.bindKey("CTRL-F", () => + this.actionFile(`${this.name}-mkf`) + ); + this.bindKey("CTRL-D", () => + this.actionFile(`${this.name}-mkdir`) + ); + this.bindKey("CTRL-U", () => + this.actionFile(`${this.name}-upload`) + ); + this.bindKey("CTRL-S", () => + this.actionFile(`${this.name}-share`) + ); + this.bindKey("CTRL-I", () => + this.actionFile(`${this.name}-info`) + ); + + this.bindKey("CTRL-R", () => + this.actionEdit(`${this.name}-mv`) + ); + this.bindKey("CTRL-M", () => + this.actionEdit(`${this.name}-rm`) + ); + this.bindKey("CTRL-X", () => + this.actionEdit(`${this.name}-cut`) + ); + this.bindKey("CTRL-C", () => + this.actionEdit(`${this.name}-copy`) + ); + this.bindKey("CTRL-P", () => + this.actionEdit(`${this.name}-paste`) + ); + + (this.find("btgrid") as GUI.tag.ButtonTag).onbtclick = (e) => { + this.view.view = "icon"; + this.viewType.icon = true; + }; + + (this.find("btlist") as GUI.tag.ButtonTag).onbtclick = (e) => { + this.view.view = "list"; + this.viewType.list = true; + }; + this.view.path = this.currdir.path; + } + + protected applySetting(k: string): void{ + // view setting + switch (k) { + case "showhidden": + return this.view.showhidden = this.setting.showhidden; + case "nav": + return this.toggleNav(this.setting.nav); + case "sidebar": + return this.toggleSidebar(this.setting.sidebar); + } + } + + private mnFile(): GUI.BasicItemType{ + //console.log file + const arr: GUI.BasicItemType = { + text: "__(File)", + nodes: [ + { + text: "__(New file)", + dataid: `${this.name}-mkf`, + shortcut: "C-F", + }, + { + text: "__(New folder)", + dataid: `${this.name}-mkdir`, + shortcut: "C-D", + }, + { + text: "__(Upload)", + dataid: `${this.name}-upload`, + shortcut: "C-U", + }, + { + text: "__(Download)", + dataid: `${this.name}-download`, + }, + { + text: "__(Share file)", + dataid: `${this.name}-share`, + shortcut: "C-S", + }, + { + text: "__(Properties)", + dataid: `${this.name}-info`, + shortcut: "C-I", + }, + ], + onchildselect: (e: GUI.TagEventType) => + this.actionFile(e.data.item.data.dataid), + }; + return arr; + } + private mnEdit(): GUI.BasicItemType{ + return { + text: "__(Edit)", + nodes: [ + { + text: "__(Rename)", + dataid: `${this.name}-mv`, + shortcut: "C-R", + }, + { + text: "__(Delete)", + dataid: `${this.name}-rm`, + shortcut: "C-M", + }, + { + text: "__(Cut)", + dataid: `${this.name}-cut`, + shortcut: "C-X", + }, + { + text: "__(Copy)", + dataid: `${this.name}-copy`, + shortcut: "C-C", + }, + { + text: "__(Paste)", + dataid: `${this.name}-paste`, + shortcut: "C-P", + }, + ], + onchildselect: (e: GUI.TagEventType) => + this.actionEdit(e.data.item.data.dataid), + }; + } + protected menu(): GUI.BasicItemType[]{ + const menu = [ + this.mnFile(), + this.mnEdit(), + { + text: "__(View)", + nodes: [ + { + text: "__(Refresh)", + dataid: `${this.name}-refresh`, + }, + { + text: "__(Sidebar)", + switch: true, + checked: this.setting.sidebar, + dataid: `${this.name}-side`, + }, + { + text: "__(Navigation bar)", + switch: true, + checked: this.setting.nav, + dataid: `${this.name}-nav`, + }, + { + text: "__(Hidden files)", + switch: true, + checked: this.setting.showhidden, + dataid: `${this.name}-hidden`, + }, + { + text: "__(Type)", + nodes: [ + { + text: "__(Icon view)", + radio: true, + checked: this.viewType.icon, + dataid: `${this.name}-icon`, + type: "icon", + }, + { + text: "__(List view)", + radio: true, + checked: this.viewType.list, + dataid: `${this.name}-list`, + type: "list", + }, + { + text: "__(Tree view)", + radio: true, + checked: this.viewType.tree, + dataid: `${this.name}-tree`, + type: "tree", + }, + ], + onchildselect: (e: GUI.TagEventType) => { + const { type } = e.data.item.data; + this.view.view = type; + return (this.viewType[type] = true); + }, + }, + ], + onchildselect: (e: GUI.TagEventType) => this.actionView(e), + }, + ]; + return menu; + } + + private toggleSidebar(b: boolean): void { + if (b) { + $(this.favo).show(); + } else { + $(this.favo).hide(); + } + return this.trigger("resize"); + } + + private toggleNav(b: boolean): void { + if (b) { + $(this.navbar).show(); + } else { + $(this.navbar).hide(); + } + return this.trigger("resize"); + } + + private actionView(e: GUI.TagEventType): void{ + const data = e.data.item.data; + switch (data.dataid) { + case `${this.name}-hidden`: + //@.view.set "showhidden", e.item.data.checked + return this.registry("showhidden", data.checked); + //@.setting.showhidden = e.item.data.checked + case `${this.name}-refresh`: + this.view.path = this.currdir.path; + return; + case `${this.name}-side`: + return this.registry("sidebar", data.checked); + //@setting.sidebar = e.item.data.checked + //@toggleSidebar e.item.data.checked + case `${this.name}-nav`: + return this.registry("nav", data.checked); + } + } + //@setting.nav = e.item.data.checked + //@toggleNav e.item.data.checked + + private actionEdit(e: string): void{ + const file = this.view.selectedFile; + switch (e) { + case `${this.name}-mv`: + if (!file) { + return; + } + this.openDialog("PromptDialog", { + title: "__(Rename)", + label: "__(File name)", + value: file.filename, + }).then(async (d) => { + if (d === file.filename) { + return; + } + try { + return file.path + .asFileHandle() + .move(`${this.currdir.path}/${d}`); + } + catch (e) { + return this.error(__("Fail to rename: {0}", file.path), e); + } + }); + break; + + case `${this.name}-rm`: + if (!file) { + return; + } + this.openDialog("YesNoDialog", { + title: "__(Delete)", + iconclass: "fa fa-question-circle", + text: __( + "Do you really want to delete: {0}?", + file.filename + ), + }).then(async (d) => { + if (!d) { + return; + } + try { + return file.path + .asFileHandle() + .remove(); + } + catch (e) { + return this.error(__("Fail to delete: {0}", file.path), e); + } + }); + break; + + case `${this.name}-cut`: + if (!file) { + return; + } + this.clipboard = { + cut: true, + file: file.path.asFileHandle(), + }; + return this.notify(__("File {0} cut", file.filename)); + + case `${this.name}-copy`: + if (!file && file.type !== "dir") { + return; + } + this.clipboard = { + cut: false, + file: file.path.asFileHandle(), + }; + return this.notify( + __("File {0} copied", file.filename) + ); + + case `${this.name}-paste`: + if (!this.clipboard) { + return; + } + if (this.clipboard.cut) { + this.clipboard.file + .move( + `${this.currdir.path}/${this.clipboard.file.basename}` + ) + .then((r) => { + return (this.clipboard = undefined); + }) + .catch((e) => { + return this.error( + __( + "Fail to paste: {0}", + this.clipboard.file.path + ), + e + ); + }); + } else { + this.clipboard.file + .read("binary") + .then(async (d) => { + const blob = new Blob([d], { + type: this.clipboard.file.info.mime, + }); + const fp = `${this.currdir.path}/${this.clipboard.file.basename}`.asFileHandle(); + fp.cache = blob; + try { + const r = await fp.write(this.clipboard.file.info.mime); + return (this.clipboard = undefined); + } + catch (e) { + return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e); + } + }) + .catch((e) => { + return this.error( + __( + "Fail to read: {0}", + this.clipboard.file.path + ), + e + ); + }); + } + break; + default: + this._api.handle.setting(); + } + } + + private actionFile(e: string): void{ + const file = this.view.selectedFile; + switch (e) { + case `${this.name}-mkdir`: + this.openDialog("PromptDialog", { + title: "__(New folder)", + label: "__(Folder name)", + }).then(async (d) => { + try { + return this.currdir.mk(d); + } + catch (e) { + return this.error(__("Fail to create: {0}", d), e); + } + }); + break; + case `${this.name}-mkf`: + this.openDialog("PromptDialog", { + title: "__(New file)", + label: "__(File name)", + }).then(async (d) => { + const fp = `${this.currdir.path}/${d}`.asFileHandle(); + try { + return fp.write("text/plain"); + } + catch (e) { + return this.error(__("Fail to create: {0}", fp.path)); + } + }); + break; + case `${this.name}-info`: + if (!file) { + return; + } + this.openDialog("InfoDialog", file); + break; + + case `${this.name}-upload`: + this.currdir.upload().catch((e) => { + return this.error( + __("Fail to upload: {0}", e.toString()), + e + ); + }); + break; + + case `${this.name}-share`: + if (!file || file.type !== "file") { + return; + } + file.path + .asFileHandle() + .publish() + .then((r) => { + return this.notify( + __("Shared url: {0}", r.result) + ); + }) + .catch((e) => { + return this.error( + __("Fail to publish: {0}", file.path), + e + ); + }); + break; + case `${this.name}-download`: + if (file.type !== "file") { + return; + } + file.path + .asFileHandle() + .download() + .catch((e) => { + return this.error( + __("Fail to download: {0}", file.path), + e + ); + }); + break; + default: + return console.log(e); + } + } + } + } +} diff --git a/src/packages/MarketPlace/Makefile b/src/packages/MarketPlace/Makefile index c7bcf80..45ca716 100644 --- a/src/packages/MarketPlace/Makefile +++ b/src/packages/MarketPlace/Makefile @@ -1,4 +1,4 @@ -module_files = dialog.js main.js +module_files = main.js dialog.js libfiles = diff --git a/src/packages/MarketPlace/dialog.js b/src/packages/MarketPlace/dialog.js deleted file mode 100644 index 49ae90a..0000000 --- a/src/packages/MarketPlace/dialog.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class RepositoryDialog extends this.OS.GUI.subwindows.SelectionDialog { - constructor() { - super(); - } - - main() { - super.main(); - this.list = this.find("list"); - $((this.find("btnOk"))).hide(); - return this.list.set("buttons", [ - { - text: "+", - onbtclick: () => { - return this.openDialog("PromptDialog", { - title: __("Add repository"), - label: __("Format : [name] url") - }).then(e => { - const m = e.match(/\[([^\]]*)\]\s*(.+)/); - if (!m || (m.length !== 3)) { - return this.error(__("Wrong format: it should be [name] url")); - } - const repo = { - url: m[2], - text: m[1] - }; - this.systemsetting.system.repositories.push(repo); - return this.list.push(repo); - }); - } - }, - { - text: "-", - onbtclick: () => { - const el = this.list.get("selectedItem"); - if (!el) { return; } - const selidx = $(el).index(); - if (!(selidx >= 0)) { return; } - this.systemsetting.system.repositories.splice(selidx, selidx); - return this.list.remove(el); - } - }, - { - iconclass: "fa fa-pencil", - onbtclick: () => this.editRepo() - } - - ]); - } - - editRepo() { - const el = this.list.get("selectedItem"); - if (!el) { return; } - const selidx = $(el).index(); - if (!(selidx >= 0)) { return; } - const data = el.get("data"); - const sel = this.systemsetting.system.repositories[selidx]; - return this.openDialog("PromptDialog", { - title: __("Edit repository"), - label: __("Format : [name] url"), - value: `[${data.text}] ${data.url}` - }).then(e => { - const m = e.match(/\[([^\]]*)\]\s*(.+)/); - if (!m || (m.length !== 3)) { - return this.error(__("Wrong format: it should be [name] url")); - } - data.text = m[1]; - data.url = m[2]; - this.list.update(); - return this.list.unselect(); - }); - } - - onexit(e) { - this.parent.refreshRepoList(); - return super.onexit(e); - } -} \ No newline at end of file diff --git a/src/packages/MarketPlace/dialog.ts b/src/packages/MarketPlace/dialog.ts new file mode 100644 index 0000000..d70eb70 --- /dev/null +++ b/src/packages/MarketPlace/dialog.ts @@ -0,0 +1,108 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 { + const App = OS.application.MarketPlace; + export type MarketPlaceRepoDialog = typeof RepositoryDialog; + class RepositoryDialog extends OS.GUI.dialogs.SelectionDialog { + private list: GUI.tag.ListViewTag; + + + constructor() { + super(); + } + + main() { + super.main(); + this.list = this.find("list") as GUI.tag.ListViewTag; + $((this.find("btnOk"))).hide(); + return this.list.buttons = [ + { + text: "+", + onbtclick: () => { + return this.openDialog("PromptDialog", { + title: __("Add repository"), + label: __("Format : [name] url") + }).then(e => { + const m = e.match(/\[([^\]]*)\]\s*(.+)/); + if (!m || (m.length !== 3)) { + return this.error(__("Wrong format: it should be [name] url")); + } + const repo = { + url: m[2], + text: m[1] + }; + this.systemsetting.system.repositories.push(repo); + return this.list.push(repo); + }); + } + }, + { + text: "-", + onbtclick: () => { + const el = this.list.selectedItem; + if (!el) { return; } + const selidx = $(el).index(); + if (!(selidx >= 0)) { return; } + this.systemsetting.system.repositories.splice(selidx, selidx); + return this.list.delete(el); + } + }, + { + iconclass: "fa fa-pencil", + onbtclick: () => this.editRepo() + } + + ]; + } + + private editRepo(): void{ + const el = this.list.selectedItem; + if (!el) { return; } + const selidx = $(el).index(); + if (!(selidx >= 0)) { return; } + const data = el.data; + const sel = this.systemsetting.system.repositories[selidx]; + this.openDialog("PromptDialog", { + title: __("Edit repository"), + label: __("Format : [name] url"), + value: `[${data.text}] ${data.url}` + }).then(e => { + const m = e.match(/\[([^\]]*)\]\s*(.+)/); + if (!m || (m.length !== 3)) { + return this.error(__("Wrong format: it should be [name] url")); + } + data.text = m[1]; + data.url = m[2]; + this.list.update(undefined); + return this.list.unselect(); + }); + } + + protected onexit(e: BaseEvent): void{ + (this.parent as OS.application.MarketPlace).refreshRepoList(); + return super.onexit(e); + } + } + + App.RepoDialog = RepositoryDialog; +} diff --git a/src/packages/MarketPlace/main.css b/src/packages/MarketPlace/main.css index cf210c9..928df79 100644 --- a/src/packages/MarketPlace/main.css +++ b/src/packages/MarketPlace/main.css @@ -9,7 +9,7 @@ afx-app-window[data-id="marketplace-win"] afx-vbox[data-id='container'] { afx-app-window[data-id="marketplace-win"] afx-vbox[data-id='container'] afx-hbox { padding-left: 10px; } -afx-app-window[data-id="marketplace-win"] div[data-id='appname'] { +afx-app-window[data-id="marketplace-win"] afx-label[data-id='appname'] i.label-text{ font-weight: bold; font-size: 20px; padding: 10px; diff --git a/src/packages/MarketPlace/main.js b/src/packages/MarketPlace/main.js deleted file mode 100644 index e735c71..0000000 --- a/src/packages/MarketPlace/main.js +++ /dev/null @@ -1,433 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS205: Consider reworking code to avoid use of IIFEs - * DS208: Avoid top-level this - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class MarketPlace extends this.OS.GUI.BaseApplication { - constructor(args) { - super("MarketPlace", args); - } - - main() { - this.installdir = this.systemsetting.system.pkgpaths.user; - // test repository - this.apps_meta = []; - this.repo = this.find("repo"); - this.repo.set("onlistselect", e => { - const data = e.data.item.get("data"); - if (!data) { return; } - return this.fetchApps(data); - }); - - this.refreshRepoList(); - - this.applist = this.find("applist"); - this.applist.set("onlistselect", e => { - const data = e.data.item.get("data"); - return this.appDetail(data); - }); - - this.container = this.find("container"); - this.appname = this.find("appname"); - this.appdesc = this.find("app-desc"); - this.appdetail = this.find("app-detail"); - this.btinstall = this.find("bt-install"); - this.btremove = this.find("bt-remove"); - this.btexec = this.find("bt-exec"); - this.searchbox = this.find("searchbox"); - ($(this.container)).css("visibility", "hidden"); - this.btexec.set("onbtclick", e => { - const el = this.applist.get("selectedItem"); - if (!el) { return; } - const app = el.get("data"); - if (app.pkgname) { return this._gui.launch(app.pkgname); } - }); - - this.btinstall.set("onbtclick", e => { - if (this.btinstall.get("dirty")) { - return this.updatePackage() - .then(() => this.notify(__("Package updated"))) - .catch(e => this.error(e.toString(), e)); - } - return this.remoteInstall() - .then(n => this.notify(__("Package installed: {0}", n))) - .catch(e => this.error(e.toString(), e)); - }); - - this.btremove.set("onbtclick", e => { - return this.uninstall() - .then(() => this.notify(__("Packaged uninstalled"))) - .catch(e => this.error(e.toString(), e)); - }); - - this.bindKey("CTRL-R", () => { - return this.menuOptionsHandle("repos"); - }); - - return $(this.searchbox).keyup(e => this.search(e)); - } - - refreshRepoList() { - const list = (Array.from(this.systemsetting.system.repositories)); - list.unshift({ - text: "Installed" - }); - return this.repo.set("data", list); - } - - search(e) { - let v; - switch (e.which) { - case 37: - return e.preventDefault(); - case 38: - this.applist.selectPrev(); - return e.preventDefault(); - case 39: - return e.preventDefault(); - case 40: - this.applist.selectNext(); - return e.preventDefault(); - case 13: - return e.preventDefault(); - default: - var text = this.searchbox.value; - if (text.length === 2) { this.applist.set("data", ((() => { - const result1 = []; - for (v of Array.from(this.apps_meta)) { result1.push(v); - } - return result1; - })())); } - if (text.length < 3) { return; } - var result = []; - var term = new RegExp(text, 'i'); - for (v of Array.from(this.apps_meta)) { if (v.text.match(term)) { result.push(v); } } - return this.applist.set("data", result); - } - } - - - fetchApps(data) { - let v; - if (!data.url) { - const pkgcache = this.systemsetting.system.packages; - const list = []; - for (let k in pkgcache) { - v = pkgcache[k]; - list.push({ - pkgname: v.pkgname ? v.pkgname : v.app, - name: v.name, - text: v.name, - icon: v.icon, - iconclass: v.iconclass, - category: v.category, - author: v.info.author, - version: v.version, - description: `${v.path}/REAME.md` - }); - } - this.apps_meta = list; - this.applist.set("data", list); - return; - } - - return this._api.get((data.url + "?_=" + (new Date().getTime())) , "json") - .then(d => { - for (v of Array.from(d)) { - v.text = v.name; - v.iconclass = "fa fa-adn"; - } - this.apps_meta = d; - return this.applist.set("data", d); - }).catch(e => { - return this.error(__("Fail to fetch packages list from: {0}", data.url), e); - }); - } - - appDetail(d) { - ($(this.container)).css("visibility", "visible"); - ( $(this.appname) ).html(d.name); - (this.find("vstat")).set("text", ""); - if (d.description) { - d.description.asFileHandle().read().then(text => { - const converter = new showdown.Converter(); - return ($(this.appdesc)).html(converter.makeHtml(text)); - }).catch(e => { - this.notify(__("Unable to read package description")); - return ($(this.appdesc)).empty(); - }); - } else { - ($(this.appdesc)).empty(); - } - const pkgcache = this.systemsetting.system.packages; - this.btinstall.set("text", "__(Install)"); - this.btinstall.set("dirty", false); - if (pkgcache[d.pkgname]) { - let vs = pkgcache[d.pkgname].version; - let ovs = d.version; - ($(this.btinstall)).hide(); - if (vs && ovs) { - vs = vs.__v(); - ovs = ovs.__v(); - if (ovs.nt(vs)) { - this.btinstall.set("dirty", true); - this.btinstall.set("text", "__(Update)"); - ($(this.btinstall)).show(); - (this.find("vstat")).set("text", - __("Your application version is older ({0} < {1})", vs, ovs)); - } - } - ($(this.btremove)).show(); - ($(this.btexec)).show(); - } else { - ($(this.btinstall)).show(); - ($(this.btremove)).hide(); - ($(this.btexec)).hide(); - } - - ($(this.appdetail)).empty(); - return (() => { - const result = []; - for (let k in d) { - const v = d[k]; - if ((k !== "name") && (k !== "description") && (k !== "domel")) { - result.push(($(this.appdetail)).append( - $("
  • ") - .append(($("")).html(k)) - .append($("").html(v)) - )); - } - } - return result; - })(); - } - - menu() { - return [ - { - text: "__(Options)", child: [ - { text: "__(Repositories)", shortcut: "C-R", id: "repos" }, - { text: "__(Install from zip)", shortcut: "C-I", id: "install" } - ] , onchildselect: e => { - return this.menuOptionsHandle(e.data.item.get("data").id); - } - } - ]; - } - - menuOptionsHandle(id) { - switch (id) { - case "repos": - return this.openDialog(new RepositoryDialog(), { - title: __("Repositories"), - data: this.systemsetting.system.repositories - }); - case "install": - return this.localInstall().then(n => { - return this.notify(__("Package installed: {0}", n)); - }).catch(e => this.error(__("Unable to install package"), e)); - default: - } - } - - remoteInstall() { - const el = this.applist.get("selectedItem"); - if (!el) { return; } - const app = el.get("data"); - if (!app) { return; } - // get blob file - return new Promise((resolve, reject) => { - return this._api.blob(app.download + "?_=" + (new Date().getTime())) - .then(data => { - return this.install(data, app) - .then(n => resolve(n)) - .catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - } - - localInstall() { - return new Promise((resolve, reject) => { - return this.openDialog("FileDialog", { - title: "__(Select package archive)", - mimes: [".*/zip"] - }).then(d => { - return d.file.path.asFileHandle().read("binary").then(data => { - return this.install(data) - .then(n => { - this.repo.unselect(); - this.repo.set("selected", 0); - const apps = (Array.from(this.applist.get("data")).map((v) => v.pkgname)); - const idx = apps.indexOf(n); - if (idx >= 0) { - this.applist.set("selected", idx); - } - return resolve(n); - }).catch(e => reject(__e(e))) - .catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - }); - } - - install(data, meta) { - return new Promise((resolve, reject) => { - return JSZip.loadAsync(data).then(zip => { - return zip.file("package.json").async("string").then(d => { - let name; - const v = JSON.parse(d); - const pth = `${this.installdir}/${v.app}`; - const dir = [pth]; - const files = []; - for (name in zip.files) { - const file = zip.files[name]; - if (file.dir) { - dir.push(pth + "/" + name); - } else { - files.push(name); - } - } - // create all directory - return this.mkdirs(dir).then(() => { - return this.installFile(v.app, zip, files).then(() => { - const app_meta = { - pkgname: v.app, - name: v.name, - text: v.name, - icon: v.icon, - iconclass: v.iconclass, - category: v.category, - author: v.info.author, - version: v.version, - description: meta ? meta.description : undefined, - download: meta ? meta.download : undefined - }; - v.text = v.name; - v.filename = v.app; - v.type = "app"; - v.mime = "antos/app"; - if (!v.iconclass && !v.icon) { v.iconclass = "fa fa-adn"; } - v.path = pth; - this.systemsetting.system.packages[v.app] = v; - this.appDetail(app_meta); - return resolve(v.name); - }).catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }).catch(err => reject(__e(err))); - }).catch(e => reject(__e(e))); - }); - } - - uninstall() { - return new Promise((resolve, reject) => { - const el = this.applist.get("selectedItem"); - if (!el) { return; } - const sel = el.get("data"); - if (!sel) { return; } - const name = sel.pkgname; - const app = this.systemsetting.system.packages[sel.pkgname]; - if (!app) { return; } - return this.openDialog("YesNoDialog", { - title: __("Uninstall") , - text: __("Uninstall: {0}?", app.name) - }).then(d => { - if (!d) { return; } - return app.path.asFileHandle().remove().then(r => { - if (r.error) { - return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error))); - } - this.notify(__("Package uninstalled")); - // stop all the services if any - if (app.services) { - for (let srv of Array.from(app.services)) { - this._gui.unloadApp(srv); - } - } - - delete this.systemsetting.system.packages[name]; - this._gui.unloadApp(name); - if (sel.download) { - this.appDetail(sel); - } else { - this.applist.remove(el); - ($(this.container)).css("visibility", "hidden"); - } - return resolve(); - }).catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - } - - updatePackage() { - return new Promise((resolve, reject) => { - return this.uninstall().then(() => { - return this.remoteInstall() - .then(() => resolve()) - .catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - } - - mkdirs(list) { - return new Promise((resolve, reject) => { - if (list.length === 0) { return resolve(); } - const dir = (list.splice(0, 1))[0].asFileHandle(); - const path = dir.parent(); - const dname = dir.basename; - return path.asFileHandle().mk(dname) - .then(r => { - if (r.error) { return reject(this._api.throwe(__("Cannot create {0}", `${path}/${dir}`))); } - return this.mkdirs(list) - .then(() => resolve()) - .catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - } - - installFile(n, zip, files) { - return new Promise((resolve, reject) => { - if (files.length === 0) { return resolve(); } - const file = (files.splice(0, 1))[0]; - const path = `${this.installdir}/${n}/${file}`; - return zip.file(file).async("uint8array").then(d => { - const fp = path.asFileHandle(); - fp.cache = new Blob([d], { type: "octet/stream" }); - return fp.write("text/plain") - .then(r => { - if (r.error) { return reject(this._api.throwe(__("Cannot install {0}", path))); } - return this.installFile(n, zip, files) - .then(() => resolve()) - .catch(e => reject( __e(e))); - }).catch(e => reject(__e(e))); - }).catch(e => reject(__e(e))); - }); - } -} - -MarketPlace.dependencies = [ - "os://scripts/jszip.min.js", - "os://scripts/showdown.min.js" -]; -MarketPlace.singleton = true; -this.OS.register("MarketPlace", MarketPlace); \ No newline at end of file diff --git a/src/packages/MarketPlace/main.ts b/src/packages/MarketPlace/main.ts new file mode 100644 index 0000000..11888b7 --- /dev/null +++ b/src/packages/MarketPlace/main.ts @@ -0,0 +1,614 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * DS208: Avoid top-level this + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 application { + declare var showdown: any; + declare var JSZip: any; + export class MarketPlace extends BaseApplication { + private installdir: string; + private apps_meta: GenericObject[]; + private repo: GUI.tag.ListViewTag; + private applist: GUI.tag.ListViewTag; + private container: GUI.tag.VBoxTag; + private appname: GUI.tag.LabelTag; + private appdetail: HTMLUListElement; + private appdesc: HTMLParagraphElement; + private btinstall: GUI.tag.ButtonTag; + private btremove: GUI.tag.ButtonTag; + private btexec: GUI.tag.ButtonTag; + private searchbox: HTMLInputElement; + static RepoDialog: MarketPlaceRepoDialog; + constructor(args: AppArgumentsType[]) { + super("MarketPlace", args); + } + + main(): void { + this.installdir = this.systemsetting.system.pkgpaths.user; + // test repository + this.apps_meta = []; + this.repo = this.find("repo") as GUI.tag.ListViewTag; + this.repo.onlistselect = (e) => { + const data = e.data.item.data; + if (!data) { + return; + } + return this.fetchApps(data); + }; + + this.refreshRepoList(); + + this.applist = this.find("applist") as GUI.tag.ListViewTag; + this.applist.onlistselect = (e) => { + const data = e.data.item.data; + return this.appDetail(data); + }; + + this.container = this.find("container") as GUI.tag.VBoxTag; + this.appname = this.find("appname") as GUI.tag.LabelTag; + this.appdesc = this.find("app-desc") as HTMLParagraphElement; + this.appdetail = this.find("app-detail") as HTMLUListElement; + this.btinstall = this.find("bt-install") as GUI.tag.ButtonTag; + this.btremove = this.find("bt-remove") as GUI.tag.ButtonTag; + this.btexec = this.find("bt-exec") as GUI.tag.ButtonTag; + this.searchbox = this.find("searchbox") as HTMLInputElement; + $(this.container).css("visibility", "hidden"); + this.btexec.onbtclick = (e) => { + const el = this.applist.selectedItem; + if (!el) { + return; + } + const app = el.data; + if (app.pkgname) { + return this._gui.launch(app.pkgname, []); + } + }; + + this.btinstall.onbtclick = async () => { + if (this.btinstall.data.dirty) { + try { + await this.updatePackage(); + return this.notify(__("Package updated")); + } catch (e) { + return this.error(e.toString(), e); + } + } + try { + const n = await this.remoteInstall(); + return this.notify(__("Package installed: {0}", n)); + } catch (e_1) { + return this.error(e_1.toString(), e_1); + } + }; + + this.btremove.onbtclick = async () => { + try { + await this.uninstall(); + return this.notify(__("Packaged uninstalled")); + } catch (e) { + return this.error(e.toString(), e); + } + }; + + this.bindKey("CTRL-R", () => { + return this.menuOptionsHandle("repos"); + }); + + $(this.searchbox).keyup((e) => this.search(e)); + } + + refreshRepoList(): void { + const list = Array.from(this.systemsetting.system.repositories); + list.unshift({ + text: "Installed", + url: undefined, + }); + this.repo.data = list; + } + + private search(e: JQuery.KeyboardEventBase) { + let v: GenericObject; + switch (e.which) { + case 37: + return e.preventDefault(); + case 38: + this.applist.selectPrev(); + return e.preventDefault(); + case 39: + return e.preventDefault(); + case 40: + this.applist.selectNext(); + return e.preventDefault(); + case 13: + return e.preventDefault(); + default: + var text = this.searchbox.value; + if (text.length === 2) { + this.applist.data = (() => { + const result1 = []; + for (v of this.apps_meta) { + result1.push(v); + } + return result1; + })(); + } + if (text.length < 3) { + return; + } + var result = []; + var term = new RegExp(text, "i"); + for (v of this.apps_meta) { + if (v.text.match(term)) { + result.push(v); + } + } + this.applist.data = result; + } + } + + private fetchApps(data: GenericObject): void { + let v: API.PackageMetaType; + if (!data.url) { + const pkgcache = this.systemsetting.system.packages; + const list = []; + for (let k in pkgcache) { + v = pkgcache[k]; + list.push({ + pkgname: v.pkgname ? v.pkgname : v.app, + name: v.name, + text: v.name, + icon: v.icon, + iconclass: v.iconclass, + category: v.category, + author: v.info.author, + version: v.version, + description: `${v.path}/REAME.md`, + }); + } + this.apps_meta = list; + this.applist.data = list; + return; + } + + this._api + .get(data.url + "?_=" + new Date().getTime(), "json") + .then((d) => { + for (v of d) { + v.text = v.name; + v.iconclass = "fa fa-adn"; + } + this.apps_meta = d; + return (this.applist.data = d); + }) + .catch((e) => { + return this.error( + __( + "Fail to fetch packages list from: {0}", + data.url + ), + e + ); + }); + } + + private appDetail(d: GenericObject): void { + $(this.container).css("visibility", "visible"); + this.appname.text = d.name; + const status = this.find("vstat") as GUI.tag.LabelTag; + status.text = ""; + if (d.description) { + d.description + .asFileHandle() + .read() + .then((text) => { + const converter = new showdown.Converter(); + return $(this.appdesc).html( + converter.makeHtml(text) + ); + }) + .catch((e) => { + this.notify( + __("Unable to read package description") + ); + return $(this.appdesc).empty(); + }); + } else { + $(this.appdesc).empty(); + } + const pkgcache = this.systemsetting.system.packages; + this.btinstall.text = "__(Install)"; + this.btinstall.data = { dirty: false }; + if (pkgcache[d.pkgname]) { + let vs: Version, ovs: Version; + if (pkgcache[d.pkgname].version) + vs = pkgcache[d.pkgname].version.__v(); + if (d.version) ovs = d.version.__v(); + $(this.btinstall).hide(); + if (vs && ovs) { + if (ovs.nt(vs)) { + this.btinstall.data = { dirty: true }; + this.btinstall.text = "__(Update)"; + $(this.btinstall).show(); + status.text = __( + "Your application version is older ({0} < {1})", + vs, + ovs + ); + } + } + $(this.btremove).show(); + $(this.btexec).show(); + } else { + $(this.btinstall).show(); + $(this.btremove).hide(); + $(this.btexec).hide(); + } + + $(this.appdetail).empty(); + for (let k in d) { + const v = d[k]; + if (k !== "name" && k !== "description" && k !== "domel") { + $(this.appdetail).append( + $("
  • ") + .append( + $("").html(k) + ) + .append($("").html(v)) + ); + } + } + } + + protected menu(): GUI.BasicItemType[] { + return [ + { + text: "__(Options)", + nodes: [ + { + text: "__(Repositories)", + shortcut: "C-R", + id: "repos", + }, + { + text: "__(Install from zip)", + shortcut: "C-I", + id: "install", + }, + ], + onchildselect: ( + e: GUI.TagEventType + ) => { + return this.menuOptionsHandle(e.data.item.data.id); + }, + }, + ]; + } + + private menuOptionsHandle(id: string): void { + switch (id) { + case "repos": + this.openDialog(new MarketPlace.RepoDialog(), { + title: __("Repositories"), + data: this.systemsetting.system.repositories, + }); + break; + + case "install": + this.localInstall() + .then((n) => { + return this.notify( + __("Package installed: {0}", n) + ); + }) + .catch((e) => + this.error(__("Unable to install package"), e) + ); + break; + default: + } + } + + private remoteInstall(): Promise { + const el = this.applist.selectedItem; + if (!el) { + return; + } + const app = el.data; + if (!app) { + return; + } + // get blob file + return new Promise(async (resolve, reject) => { + try { + const data = await this._api.blob( + app.download + "?_=" + new Date().getTime() + ); + try { + const n = await this.install(data, app); + return resolve(n); + } catch (e) { + return reject(__e(e)); + } + } catch (e_1) { + return reject(__e(e_1)); + } + }); + } + + private localInstall(): Promise { + return new Promise((resolve, reject) => { + return this.openDialog("FileDialog", { + title: "__(Select package archive)", + mimes: [".*/zip"], + }).then((d) => { + return d.file.path + .asFileHandle() + .read("binary") + .then((data: Uint8Array) => { + return this.install(data) + .then((n) => { + this.repo.unselect(); + this.repo.selected = 0; + const apps = this.applist.data.map( + (v) => v.pkgname + ); + const idx = apps.indexOf(n); + if (idx >= 0) { + this.applist.selected = idx; + } + return resolve(n); + }) + .catch((e: Error) => reject(__e(e))) + .catch((e: Error) => reject(__e(e))); + }) + .catch((e: Error) => reject(__e(e))); + }); + }); + } + + private install( + data: ArrayBuffer, + meta?: GenericObject + ): Promise { + return new Promise((resolve, reject) => { + return JSZip.loadAsync(data) + .then((zip: any) => { + return zip + .file("package.json") + .async("string") + .then((d: string) => { + let name: string; + const v = JSON.parse(d); + const pth = `${this.installdir}/${v.app}`; + const dir = [pth]; + const files = []; + for (name in zip.files) { + const file = zip.files[name]; + if (file.dir) { + dir.push(pth + "/" + name); + } else { + files.push(name); + } + } + // create all directory + return this.mkdirs(dir) + .then(() => { + return this.installFile( + v.app, + zip, + files + ) + .then(() => { + const app_meta = { + pkgname: v.app, + name: v.name, + text: v.name, + icon: v.icon, + iconclass: v.iconclass, + category: v.category, + author: v.info.author, + version: v.version, + description: meta + ? meta.description + : undefined, + download: meta + ? meta.download + : undefined, + }; + v.text = v.name; + v.filename = v.app; + v.type = "app"; + v.mime = "antos/app"; + if ( + !v.iconclass && + !v.icon + ) { + v.iconclass = + "fa fa-adn"; + } + v.path = pth; + this.systemsetting.system.packages[ + v.app + ] = v; + this.appDetail(app_meta); + return resolve(v.name); + }) + .catch((e) => reject(__e(e))); + }) + .catch((e) => reject(__e(e))); + }) + .catch((err: Error) => reject(__e(err))); + }) + .catch((e: Error) => reject(__e(e))); + }); + } + + private uninstall(): Promise { + return new Promise(async (resolve, reject) => { + const el = this.applist.selectedItem; + if (!el) { + return; + } + const sel = el.data; + if (!sel) { + return; + } + const name = sel.pkgname; + const app = this.systemsetting.system.packages[sel.pkgname]; + if (!app) { + return; + } + try { + const d = await this.openDialog("YesNoDialog", { + title: __("Uninstall"), + text: __("Uninstall: {0}?", app.name), + }); + if (!d) { + return; + } + try { + const r = await app.path + .asFileHandle() + .remove(); + if (r.error) { + return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error))); + } + this.notify(__("Package uninstalled")); + // stop all the services if any + if (app.services) { + for (let srv of Array.from(app.services)) { + this._gui.unloadApp(srv); + } + } + delete this.systemsetting.system.packages[name]; + this._gui.unloadApp(name); + if (sel.download) { + this.appDetail(sel); + } + else { + this.applist.delete(el); + $(this.container).css("visibility", "hidden"); + } + return resolve(); + } + catch (e) { + return reject(__e(e)); + } + } + catch (e_1) { + return reject(__e(e_1)); + } + }); + } + + private updatePackage(): Promise{ + return new Promise(async (resolve, reject) => { + try { + await this.uninstall(); + try { + await this.remoteInstall(); + return resolve(); + } + catch (e) { + return reject(__e(e)); + } + } + catch (e_1) { + return reject(__e(e_1)); + } + }); + } + + private mkdirs(list: string[]): Promise { + return new Promise((resolve, reject) => { + if (list.length === 0) { + return resolve(); + } + const dir = list.splice(0, 1)[0].asFileHandle(); + const path = dir.parent(); + const dname = dir.basename; + return path + .asFileHandle() + .mk(dname) + .then((r) => { + if (r.error) { + return reject( + this._api.throwe( + __( + "Cannot create {0}", + `${path}/${dir}` + ) + ) + ); + } + return this.mkdirs(list) + .then(() => resolve()) + .catch((e) => reject(__e(e))); + }) + .catch((e) => reject(__e(e))); + }); + } + + private installFile(n: string, zip: any, files: string[]): Promise{ + return new Promise((resolve, reject) => { + if (files.length === 0) { + return resolve(); + } + const file = files.splice(0, 1)[0]; + const path = `${this.installdir}/${n}/${file}`; + return zip + .file(file) + .async("uint8array") + .then((d: Uint8Array) => { + const fp = path.asFileHandle(); + fp.cache = new Blob([d], { type: "octet/stream" }); + return fp + .write("text/plain") + .then((r) => { + if (r.error) { + return reject( + this._api.throwe( + __("Cannot install {0}", path) + ) + ); + } + return this.installFile(n, zip, files) + .then(() => resolve()) + .catch((e) => reject(__e(e))); + }) + .catch((e) => reject(__e(e))); + }) + .catch((e: Error) => reject(__e(e))); + }); + } + } + + MarketPlace.dependencies = [ + "os://scripts/jszip.min.js", + "os://scripts/showdown.min.js", + ]; + MarketPlace.singleton = true; + } +} diff --git a/src/packages/MarketPlace/scheme.html b/src/packages/MarketPlace/scheme.html index a1f872c..866c648 100644 --- a/src/packages/MarketPlace/scheme.html +++ b/src/packages/MarketPlace/scheme.html @@ -10,7 +10,7 @@ -
    +
    diff --git a/src/packages/Setting/AppearanceHandle.js b/src/packages/Setting/AppearanceHandle.js deleted file mode 100644 index 5e8d5e6..0000000 --- a/src/packages/Setting/AppearanceHandle.js +++ /dev/null @@ -1,126 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class AppearanceHandle extends SettingHandle { - constructor(scheme, parent) { - let v; - super(scheme, parent); - this.wplist = this.find("wplist"); - this.wpreview = this.find("wp-preview"); - this.wpsize = this.find("wpsize"); - this.wprepeat = this.find("wprepeat"); - this.themelist = this.find("theme-list"); - this.syswp = undefined; - this.wplist.set("onlistselect", e => { - const data = e.data.item.get("data"); - $(this.wpreview) - .css("background-image", `url(${data.path.asFileHandle().getlink()})` ) - .css("background-size", "cover"); - this.parent.systemsetting.appearance.wp.url = data.path; - return this.parent._gui.wallpaper(); - }); - - this.wplist.set("buttons", [ - { - text: "+", onbtclick: e => { - return this.parent.openDialog("FileDialog", { - title: __("Select image file"), - mimes: ["image/.*"] - }).then(d => { - this.parent.systemsetting.appearance.wps.push(d.file.path); - return this.wplist.set("data", this.getwplist()); - }); - } - } - ]); - - this.wpsize.set("onlistselect", e => { - this.parent.systemsetting.appearance.wp.size = e.data.item.get("data").text; - return this.parent._gui.wallpaper(); - }); - - const sizes = [ - { text: "cover", selected: this.parent.systemsetting.appearance.wp.size === "cover" }, - { text: "auto", selected: this.parent.systemsetting.appearance.wp.size === "auto" }, - { text: "contain", selected: this.parent.systemsetting.appearance.wp.size === "contain" } - ]; - this.wpsize.set("data", sizes); - - const repeats = [ - { text: "repeat", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat" }, - { text: "repeat-x", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat-x" }, - { text: "repeat-y", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat-y" }, - { text: "no-repeat", selected: this.parent.systemsetting.appearance.wp.repeat === "no-repeat" } - ]; - this.wprepeat.set("onlistselect", e => { - this.parent.systemsetting.appearance.wp.repeat = e.data.item.get("data").text; - return this.parent._gui.wallpaper(); - }); - this.wprepeat.set("data", repeats); - const currtheme = this.parent.systemsetting.appearance.theme; - for (v of Array.from(this.parent.systemsetting.appearance.themes)) { v.selected = v.name === currtheme; } - this.themelist.set("data" , this.parent.systemsetting.appearance.themes); - this.themelist.set("onlistselect", e => { - let data; - if (e && e.data) { data = e.data.item.get("data"); } - if (!data) { return; } - if (data.name === this.parent.systemsetting.appearance.theme) { return; } - this.parent.systemsetting.appearance.theme = data.name; - return this.parent._gui.loadTheme(data.name, true); - }); - if (!this.syswp) { - const path = "os://resources/themes/system/wp"; - path.asFileHandle().read() - .then(d => { - if (d.error) { return this.parent.error(__("Cannot read wallpaper list from {0}", path)); } - for (v of Array.from(d.result)) { - v.text = v.filename; - v.iconclass = "fa fa-file-image-o"; - } - this.syswp = d.result; - return this.wplist.set("data", this.getwplist()); - }).catch(e => this.parent.error(__("Unable to read: {0}", path), e)); - } else { - - this.wplist.set("data", this.getwplist()); - } - } - - getwplist() { - let v; - let list = []; - for (v of Array.from(this.parent.systemsetting.appearance.wps)) { - const file = v.asFileHandle(); - list.push({ - text: file.basename, - path: file.path, - selected: file.path === this.parent.systemsetting.appearance.wp.url, - iconclass: "fa fa-file-image-o" - }); - } - list = list.concat(this.syswp); - for (v of Array.from(list)) { v.selected = v.path === this.parent.systemsetting.appearance.wp.url; } - return list; - } -} \ No newline at end of file diff --git a/src/packages/Setting/AppearanceHandle.ts b/src/packages/Setting/AppearanceHandle.ts new file mode 100644 index 0000000..9c2fcda --- /dev/null +++ b/src/packages/Setting/AppearanceHandle.ts @@ -0,0 +1,206 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 { + const App = OS.application.Setting; + + /** + * + * + * @class AppearanceHandle + * @extends {App.SettingHandle} + */ + class AppearanceHandle extends App.SettingHandle { + private wplist: GUI.tag.ListViewTag; + private wpreview: HTMLDivElement; + private wprepeat: GUI.tag.ListViewTag; + private themelist: GUI.tag.ListViewTag; + private wpsize: GUI.tag.ListViewTag; + private syswp: string; + + /** + *Creates an instance of AppearanceHandle. + * @param {HTMLElement} scheme + * @param {OS.application.Setting} parent + * @memberof AppearanceHandle + */ + constructor(scheme: HTMLElement, parent: OS.application.Setting) { + let v: GenericObject; + super(scheme, parent); + this.wplist = this.find("wplist") as GUI.tag.ListViewTag; + this.wpreview = this.find("wp-preview") as HTMLDivElement; + this.wpsize = this.find("wpsize") as GUI.tag.ListViewTag; + this.wprepeat = this.find("wprepeat") as GUI.tag.ListViewTag; + this.themelist = this.find("theme-list") as GUI.tag.ListViewTag; + this.syswp = undefined; + this.wplist.onlistselect = (e) => { + const data = e.data.item.data; + $(this.wpreview) + .css( + "background-image", + `url(${data.path.asFileHandle().getlink()})` + ) + .css("background-size", "cover"); + OS.setting.appearance.wp.url = data.path; + GUI.wallpaper(); + }; + + this.wplist.buttons = [ + { + text: "+", + onbtclick: (e) => { + return this.parent + .openDialog("FileDialog", { + title: __("Select image file"), + mimes: ["image/.*"], + }) + .then((d) => { + OS.setting.appearance.wps.push(d.file.path); + this.wplist.data = this.getwplist(); + }); + }, + }, + ]; + + this.wpsize.onlistselect = (e) => { + setting.appearance.wp.size = e.data.item.data.text; + return GUI.wallpaper(); + }; + + const sizes = [ + { + text: "cover", + selected: setting.appearance.wp.size === "cover", + }, + { + text: "auto", + selected: setting.appearance.wp.size === "auto", + }, + { + text: "contain", + selected: setting.appearance.wp.size === "contain", + }, + ]; + this.wpsize.data = sizes; + + const repeats = [ + { + text: "repeat", + selected: setting.appearance.wp.repeat === "repeat", + }, + { + text: "repeat-x", + selected: setting.appearance.wp.repeat === "repeat-x", + }, + { + text: "repeat-y", + selected: setting.appearance.wp.repeat === "repeat-y", + }, + { + text: "no-repeat", + selected: setting.appearance.wp.repeat === "no-repeat", + }, + ]; + this.wprepeat.onlistselect = (e) => { + setting.appearance.wp.repeat = e.data.item.data.text; + GUI.wallpaper(); + }; + this.wprepeat.data = repeats; + const currtheme = setting.appearance.theme; + for (v of setting.appearance.themes) { + v.selected = v.name === currtheme; + } + this.themelist.data = setting.appearance.themes; + this.themelist.onlistselect = (e) => { + let data; + if (e && e.data) { + data = e.data.item.data; + } + if (!data) { + return; + } + if (data.name === setting.appearance.theme) { + return; + } + setting.appearance.theme = data.name; + GUI.loadTheme(data.name, true); + }; + if (!this.syswp) { + const path = "os://resources/themes/system/wp"; + path.asFileHandle() + .read() + .then((d) => { + if (d.error) { + return this.parent.error( + __( + "Cannot read wallpaper list from {0}", + path + ) + ); + } + for (v of Array.from(d.result)) { + v.text = v.filename; + v.iconclass = "fa fa-file-image-o"; + } + this.syswp = d.result; + return (this.wplist.data = this.getwplist()); + }) + .catch((e) => + this.parent.error( + __("Unable to read: {0}", path), + e + ) + ); + } else { + this.wplist.data = this.getwplist(); + } + } + + /** + * + * + * @private + * @returns {GenericObject[]} + * @memberof AppearanceHandle + */ + private getwplist(): GenericObject[] { + let v; + let list = []; + for (v of setting.appearance.wps) { + const file = v.asFileHandle(); + list.push({ + text: file.basename, + path: file.path, + selected: file.path === setting.appearance.wp.url, + iconclass: "fa fa-file-image-o", + }); + } + list = list.concat(this.syswp); + for (v of list) { + v.selected = v.path === setting.appearance.wp.url; + } + return list; + } + } + App.AppearanceHandle = AppearanceHandle; +} diff --git a/src/packages/Setting/LocaleHandle.js b/src/packages/Setting/LocaleHandle.js deleted file mode 100644 index 903a579..0000000 --- a/src/packages/Setting/LocaleHandle.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class LocaleHandle extends SettingHandle { - constructor(scheme, parent) { - super(scheme, parent); - this.lglist = this.find("lglist"); - this.localelist = undefined; - this.lglist.set("onlistselect", e => { - return this.parent._api.setLocale(e.data.item.get("data").text); - }); - if (!this.localelist) { - const path = "os://resources/languages"; - path.asFileHandle().read() - .then(d => { - if (d.derror) { return this.parent.error(__("Cannot fetch system locales: {0}", d.error)); } - for (let v of Array.from(d.result)) { - v.text = v.filename.replace(/\.json$/g, ""); - v.selected = v.text === this.parent.systemsetting.system.locale; - } - this.localelist = d.result; - return this.lglist.set("data", this.localelist); - }).catch(e => this.parent.error(__("Unable to read: {0}", path), e)); - } else { - this.lglist.set("data", this.localelist); - } - } -} diff --git a/src/packages/Setting/LocaleHandle.ts b/src/packages/Setting/LocaleHandle.ts new file mode 100644 index 0000000..f970a17 --- /dev/null +++ b/src/packages/Setting/LocaleHandle.ts @@ -0,0 +1,77 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 { + const App = OS.application.Setting; + + /** + * + * + * @class LocaleHandle + * @extends {App.SettingHandle} + */ + class LocaleHandle extends App.SettingHandle { + private lglist: GUI.tag.ListViewTag; + private localelist: GenericObject[]; + + /** + *Creates an instance of LocaleHandle. + * @param {HTMLElement} scheme + * @param {OS.application.Setting} parent + * @memberof LocaleHandle + */ + constructor(scheme: HTMLElement, parent: OS.application.Setting) { + super(scheme, parent); + this.lglist = this.find("lglist") as GUI.tag.ListViewTag; + this.localelist = undefined; + this.lglist.onlistselect = (e) => { + return API.setLocale(e.data.item.data.text); + }; + if (!this.localelist) { + const path = "os://resources/languages"; + path.asFileHandle() + .read() + .then((d) => { + if (d.derror) { + return this.parent.error( + __("Cannot fetch system locales: {0}", d.error) + ); + } + for (let v of d.result) { + v.text = v.filename.replace(/\.json$/g, ""); + v.selected = v.text === setting.system.locale; + } + this.localelist = d.result; + return (this.lglist.data = this.localelist); + }) + .catch((e) => + this.parent.error(__("Unable to read: {0}", path), e) + ); + } else { + this.lglist.data = this.localelist; + } + } + } + App.LocaleHandle = LocaleHandle; +} diff --git a/src/packages/Setting/StartupHandle.js b/src/packages/Setting/StartupHandle.js deleted file mode 100644 index 19929af..0000000 --- a/src/packages/Setting/StartupHandle.js +++ /dev/null @@ -1,110 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS205: Consider reworking code to avoid use of IIFEs - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class StartupHandle extends SettingHandle { - constructor(scheme, parent) { - super(scheme, parent); - this.srvlist = this.find("srvlist"); - this.applist = this.find("applist"); - this.srvlist.set("buttons", [ - { - text: "+", onbtclick: e => { - let services = []; - for (var k in this.parent.systemsetting.system.packages) { - const v = this.parent.systemsetting.system.packages[k]; - if (v.services) { - const srvs = (Array.from(v.services).map((x) => ({ text: `${k}/${x}`, iconclass: "fa fa-tasks" }))); - services = services.concat(srvs); - } - } - return this.parent.openDialog("SelectionDialog", { - title: "__(Add service)", - data: services - }).then(d => { - this.parent.systemsetting.system.startup.services.push(d.text); - return this.refresh(); - }); - } - }, - { - text: "-", onbtclick: e => { - const item = this.srvlist.get("selectedItem"); - if (!item) { return; } - const selidx = $(item).index(); - this.parent.systemsetting.system.startup.services.splice(selidx, 1); - return this.refresh(); - } - } - ]); - - this.applist.set("buttons", [ - { - text: "+", onbtclick: e => { - const apps = ((() => { - const result = []; - for (let k in this.parent.systemsetting.system.packages) { - const v = this.parent.systemsetting.system.packages[k]; - result.push({ text: k, iconclass: v.iconclass }); - } - return result; - })()); - return this.parent.openDialog("SelectionDialog", { - title: "__(Add application)", - data: apps - }).then(d => { - this.parent.systemsetting.system.startup.apps.push(d.text); - return this.refresh(); - }); - } - }, - { - text: "-", onbtclick: e => { - const item = this.applist.get("selectedItem"); - if (!item) { return; } - const selidx = $(item).index(); - this.parent.systemsetting.system.startup.apps.splice(selidx, 1); - return this.refresh(); - } - } - ]); - this.refresh(); - } - - refresh() { - let v; - this.srvlist.set("data", ((() => { - const result = []; - for (v of Array.from(this.parent.systemsetting.system.startup.services)) { result.push({ text:v }); - } - return result; - })())); - return this.applist.set("data", ((() => { - const result1 = []; - for (v of Array.from(this.parent.systemsetting.system.startup.apps)) { result1.push({ text:v }); - } - return result1; - })())); - } -} diff --git a/src/packages/Setting/StartupHandle.ts b/src/packages/Setting/StartupHandle.ts new file mode 100644 index 0000000..0aa1914 --- /dev/null +++ b/src/packages/Setting/StartupHandle.ts @@ -0,0 +1,155 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 { + const App = OS.application.Setting; + + /** + * + * + * @class StartupHandle + * @extends {App.SettingHandle} + */ + class StartupHandle extends App.SettingHandle { + private srvlist: GUI.tag.ListViewTag; + private applist: GUI.tag.ListViewTag; + + /** + *Creates an instance of StartupHandle. + * @param {HTMLElement} scheme + * @param {OS.application.Setting} parent + * @memberof StartupHandle + */ + constructor(scheme: HTMLElement, parent: OS.application.Setting) { + super(scheme, parent); + this.srvlist = this.find("srvlist") as GUI.tag.ListViewTag; + this.applist = this.find("applist") as GUI.tag.ListViewTag; + this.srvlist.buttons = [ + { + text: "+", + onbtclick: () => { + let services = []; + for (var k in setting.system.packages) { + const v = setting.system.packages[k]; + if (v.services) { + const srvs = v.services.map((x) => ({ + text: `${k}/${x}`, + iconclass: "fa fa-tasks", + })); + services = services.concat(srvs); + } + } + this.parent + .openDialog("SelectionDialog", { + title: "__(Add service)", + data: services, + }) + .then((d) => { + setting.system.startup.services.push(d.text); + return this.refresh(); + }); + }, + }, + { + text: "-", + onbtclick: () => { + const item = this.srvlist.selectedItem; + if (!item) { + return; + } + const selidx = $(item).index(); + setting.system.startup.services.splice(selidx, 1); + return this.refresh(); + }, + }, + ]; + + this.applist.buttons = [ + { + text: "+", + onbtclick: () => { + const apps = (() => { + const result = []; + for (let k in setting.system.packages) { + const v = setting.system.packages[k]; + result.push({ + text: k, + iconclass: v.iconclass, + }); + } + return result; + })(); + this.parent + .openDialog("SelectionDialog", { + title: "__(Add application)", + data: apps, + }) + .then((d) => { + setting.system.startup.apps.push(d.text); + return this.refresh(); + }); + }, + }, + { + text: "-", + onbtclick: () => { + const item = this.applist.selectedItem; + if (!item) { + return; + } + const selidx = $(item).index(); + setting.system.startup.apps.splice(selidx, 1); + return this.refresh(); + }, + }, + ]; + this.refresh(); + } + + /** + * + * + * @private + * @memberof StartupHandle + */ + private refresh(): void { + let v; + this.srvlist.data = (() => { + const result = []; + for (v of setting.system.startup.services) { + result.push({ text: v }); + } + return result; + })(); + this.applist.data = (() => { + const result1 = []; + for (v of Array.from(setting.system.startup.apps)) { + result1.push({ text: v }); + } + return result1; + })(); + } + } + App.StartupHandle = StartupHandle; +} diff --git a/src/packages/Setting/VFSHandle.js b/src/packages/Setting/VFSHandle.js deleted file mode 100644 index 9da5a39..0000000 --- a/src/packages/Setting/VFSHandle.js +++ /dev/null @@ -1,173 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class VFSSettingDialog extends this.OS.GUI.BasicDialog { - constructor() { - super("VFSSettingDialog", VFSSettingDialog.scheme); - } - - main() { - super.main(); - $(this.find("txtPath")).click(e => { - return this.openDialog("FileDialog", { - title: "__(Select a directory)", - mimes: ["dir"], - hidden: true - }) - .then(d => { - return (this.find("txtPath")).value = d.file.path; - }); - }); - - this.find("btnOk").set("onbtclick", e => { - const data = { - path: (this.find("txtPath")).value, - name: (this.find("txtName")).value - }; - if (!data.name || (data.name === "")) { return this.error(__("Please enter mount point name")); } - if (!data.path || (data.path === "")) { return this.error(__("Please select a directory")); } - if (this.handle) { this.handle(data); } - return this.quit(); - }); - - (this.find("btnCancel")).set("onbtclick", e => { - return this.quit(); - }); - - if (!this.data) { return; } - if (this.data.text) { (this.find("txtName")).value = this.data.text; } - if (this.data.path) { return (this.find("txtPath")).value = this.data.path; } - } -} - -VFSSettingDialog.scheme = `\ - - - -
    - -
    - - -
    - - -
    - -
    - - - - -
    - - -\ -`; - -class VFSHandle extends SettingHandle { - constructor(scheme, parent) { - super(scheme, parent); - this.mplist = this.find("mplist"); - this.dpath = this.find("dpath"); - this.ppath = this.find("ppath"); - this.mplist.set("buttons", [ - { - text: "+", - onbtclick: e => { - return this.parent.openDialog(new VFSSettingDialog(), { - title: "__(Add mount point)" - }) - .then(d => { - this.parent.systemsetting.VFS.mountpoints.push({ - text: d.name, path: d.path, iconclass: "fa fa-folder", type: "fs" - }); - return this.refresh(); - }); - } - }, - { - text: "-", - onbtclick: e => { - const item = this.mplist.get("selectedItem"); - if (!item) { return; } - const selidx = $(item).index(); - return this.parent.openDialog("YesNoDialog", { - title: "__(Remove)", - text: __("Remove: {0}?", item.get("data").text) - }).then(d => { - if (!d) { return; } - this.parent.systemsetting.VFS.mountpoints.splice(selidx, 1); - return this.refresh(); - }); - } - }, - { - text: "", - iconclass: "fa fa-pencil", - onbtclick: e => { - const sel = this.mplist.get("selectedItem"); - if (!sel) { return; } - return this.parent.openDialog(new VFSSettingDialog(), { - title: "__(Edit mount point)", - text: sel.get("data").text, - path: sel.get("data").path - }).then(d => { - sel.get("data").text = d.name; - sel.get("data").path = d.path; - return this.refresh(); - }); - } - } - ]); - (this.find("btndpath")).set('onbtclick', e => { - return this.parent.openDialog("FileDialog", { - title: "__(Select a directory)", - mimes: ["dir"], - hidden: true - }).then(d => { - this.parent.systemsetting.desktop.path = d.file.path; - this.parent._gui.refreshDesktop(); - return this.refresh(); - }); - }); - - (this.find("btnppath")).set('onbtclick', e => { - return this.parent.openDialog("FileDialog", { - title: "__(Select a directory)", - mimes: ["dir"], - hidden: true - }).then(d => { - this.parent.systemsetting.system.pkgpaths.user = d.file.path; - return this.refresh(); - }); - }); - this.refresh(); - } - - refresh() { - this.mplist.set("data", this.parent.systemsetting.VFS.mountpoints); - this.dpath.set("text", this.parent.systemsetting.desktop.path); - return this.ppath.set("text", this.parent.systemsetting.system.pkgpaths.user); - } -} \ No newline at end of file diff --git a/src/packages/Setting/VFSHandle.ts b/src/packages/Setting/VFSHandle.ts new file mode 100644 index 0000000..4b01084 --- /dev/null +++ b/src/packages/Setting/VFSHandle.ts @@ -0,0 +1,246 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 { + const App = OS.application.Setting; + + /** + * + * + * @class VFSSettingDialog + * @extends {GUI.BasicDialog} + */ + class VFSSettingDialog extends GUI.BasicDialog { + /** + *Creates an instance of VFSSettingDialog. + * @memberof VFSSettingDialog + */ + constructor() { + super("VFSSettingDialog", VFSSettingDialog.scheme); + } + + /** + * + * + * @returns + * @memberof VFSSettingDialog + */ + main() { + super.main(); + $(this.find("txtPath")).click((e) => { + return this.openDialog("FileDialog", { + title: "__(Select a directory)", + mimes: ["dir"], + hidden: true, + }).then((d) => { + return ((this.find("txtPath") as HTMLInputElement).value = + d.file.path); + }); + }); + + (this.find("btnOk") as GUI.tag.ButtonTag).onbtclick = (e) => { + const data = { + path: (this.find("txtPath") as HTMLInputElement).value, + name: (this.find("txtName") as HTMLInputElement).value, + }; + if (!data.name || data.name === "") { + return this.error(__("Please enter mount point name")); + } + if (!data.path || data.path === "") { + return this.error(__("Please select a directory")); + } + if (this.handle) { + this.handle(data); + } + return this.quit(); + }; + + (this.find("btnCancel") as GUI.tag.ButtonTag).onbtclick = (e) => { + return this.quit(); + }; + + if (!this.data) { + return; + } + if (this.data.text) { + (this.find( + "txtName" + ) as HTMLInputElement).value = this.data.text; + } + if (this.data.path) { + return ((this.find( + "txtPath" + ) as HTMLInputElement).value = this.data.path); + } + } + } + + VFSSettingDialog.scheme = `\ + + + +
    + +
    + + +
    + + +
    + +
    + + + + +
    + + +\ +`; + + /** + * + * + * @class VFSHandle + * @extends {App.SettingHandle} + */ + class VFSHandle extends App.SettingHandle { + private mplist: GUI.tag.ListViewTag; + private dpath: GUI.tag.LabelTag; + private ppath: GUI.tag.LabelTag; + + /** + *Creates an instance of VFSHandle. + * @param {HTMLElement} scheme + * @param {OS.application.Setting} parent + * @memberof VFSHandle + */ + constructor(scheme: HTMLElement, parent: OS.application.Setting) { + super(scheme, parent); + this.mplist = this.find("mplist") as GUI.tag.ListViewTag; + this.dpath = this.find("dpath") as GUI.tag.LabelTag; + this.ppath = this.find("ppath") as GUI.tag.LabelTag; + this.mplist.buttons = [ + { + text: "+", + onbtclick: async () => { + const d = await this.parent.openDialog( + new VFSSettingDialog(), + { + title: "__(Add mount point)", + } + ); + setting.VFS.mountpoints.push({ + text: d.name, + path: d.path, + iconclass: "fa fa-folder", + type: "fs", + }); + return this.refresh(); + }, + }, + { + text: "-", + onbtclick: async () => { + const item = this.mplist.selectedItem; + if (!item) { + return; + } + const selidx = $(item).index(); + const d = await this.parent.openDialog("YesNoDialog", { + title: "__(Remove)", + text: __("Remove: {0}?", item.data.text), + }); + if (!d) { + return; + } + setting.VFS.mountpoints.splice(selidx, 1); + return this.refresh(); + }, + }, + { + text: "", + iconclass: "fa fa-pencil", + onbtclick: async () => { + const sel = this.mplist.selectedItem; + if (!sel) { + return; + } + const d = await this.parent.openDialog( + new VFSSettingDialog(), + { + title: "__(Edit mount point)", + text: sel.data.text, + path: sel.data.path, + } + ); + sel.data.text = d.name; + sel.data.path = d.path; + return this.refresh(); + }, + }, + ]; + (this.find( + "btndpath" + ) as GUI.tag.ButtonTag).onbtclick = async () => { + const d = await this.parent.openDialog("FileDialog", { + title: "__(Select a directory)", + mimes: ["dir"], + hidden: true, + }); + setting.desktop.path = d.file.path; + GUI.refreshDesktop(); + return this.refresh(); + }; + + (this.find( + "btnppath" + ) as GUI.tag.ButtonTag).onbtclick = async () => { + const d = await this.parent.openDialog("FileDialog", { + title: "__(Select a directory)", + mimes: ["dir"], + hidden: true, + }); + setting.system.pkgpaths.user = d.file.path; + return this.refresh(); + }; + this.refresh(); + } + + /** + * + * + * @private + * @memberof VFSHandle + */ + private refresh(): void { + this.mplist.data = setting.VFS.mountpoints; + this.dpath.text = setting.desktop.path; + this.ppath.text = setting.system.pkgpaths.user; + } + } + + App.VFSHandle = VFSHandle; +} diff --git a/src/packages/Setting/main.js b/src/packages/Setting/main.js deleted file mode 100644 index 991a5ae..0000000 --- a/src/packages/Setting/main.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS208: Avoid top-level this - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -// 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/. - -class SettingHandle { - constructor(scheme, parent) { - this.scheme = scheme; - this.parent = parent; - } - - find(id) { if (this.scheme) { return ($(`[data-id='${id}']`, this.scheme))[0]; } } - - render() {} -} - -class Setting extends this.OS.GUI.BaseApplication { - constructor(args) { - super("Setting", args); - } - - main() { - this.container = this.find("container"); - - new AppearanceHandle(this.find("appearance"), this); - new VFSHandle(this.find("vfs"), this); - new LocaleHandle(this.find("locale"), this); - new StartupHandle(this.find("startup"), this); - - return (this.find("btnsave")).set("onbtclick", e => { - return this._api.setting() - .then(d => { - if (d.error) { return this.error(__("Cannot save system setting: {0}", d.error)); } - return this.notify(__("System setting saved")); - }).catch(e => { - return this.error(__("Cannot save system setting: {0}", e.toString()), e); - }); - }); - } -} -Setting.singleton = true; -this.OS.register("Setting", Setting); \ No newline at end of file diff --git a/src/packages/Setting/main.ts b/src/packages/Setting/main.ts new file mode 100644 index 0000000..159e0e6 --- /dev/null +++ b/src/packages/Setting/main.ts @@ -0,0 +1,136 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS208: Avoid top-level this + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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 application { + + /** + * + * + * @class SettingHandle + */ + class SettingHandle { + protected scheme: HTMLElement; + protected parent: Setting; + + /** + *Creates an instance of SettingHandle. + * @param {HTMLElement} scheme + * @param {Setting} parent + * @memberof SettingHandle + */ + constructor(scheme: HTMLElement, parent: Setting) { + this.scheme = scheme; + this.parent = parent; + } + + /** + * + * + * @protected + * @param {string} id + * @returns + * @memberof SettingHandle + */ + protected find(id: string) { + if (this.scheme) { + return $(`[data-id='${id}']`, this.scheme)[0]; + } + } + + /** + * + * + * @protected + * @memberof SettingHandle + */ + protected render() : void {}; + } + + /** + * + * + * @export + * @class Setting + * @extends {BaseApplication} + */ + export class Setting extends BaseApplication { + //private containter: GUI.tag.TabContainerTag; + static AppearanceHandle: typeof SettingHandle; + static VFSHandle: typeof SettingHandle; + static LocaleHandle: typeof SettingHandle; + static StartupHandle: typeof SettingHandle; + static SettingHandle: typeof SettingHandle; + + /** + *Creates an instance of Setting. + * @param {AppArgumentsType[]} args + * @memberof Setting + */ + constructor(args: AppArgumentsType[]) { + super("Setting", args); + } + + /** + * + * + * @memberof Setting + */ + main(): void{ + //this.containter = this.find("container") as GUI.tag.TabContainerTag; + + new Setting.AppearanceHandle(this.find("appearance"), this); + new Setting.VFSHandle(this.find("vfs"), this); + new Setting.LocaleHandle(this.find("locale"), this); + new Setting.StartupHandle(this.find("startup"), this); + + (this.find("btnsave") as GUI.tag.ButtonTag ).onbtclick = (e) => { + this._api + .setting() + .then((d) => { + if (d.error) { + return this.error( + __( + "Cannot save system setting: {0}", + d.error + ) + ); + } + return this.notify(__("System setting saved")); + }) + .catch((e) => { + return this.error( + __( + "Cannot save system setting: {0}", + e.toString() + ), + e + ); + }); + }; + } + } + Setting.singleton = true; + Setting.SettingHandle = SettingHandle; + } +} diff --git a/src/packages/Syslog/Calendar.ts b/src/packages/Syslog/Calendar.ts index 1e5dd1c..c6165f7 100644 --- a/src/packages/Syslog/Calendar.ts +++ b/src/packages/Syslog/Calendar.ts @@ -40,7 +40,7 @@ namespace OS { }); } - awake(e: GUI.TagEventType): void { + awake(e: GUI.TagEventType): void { this.openDialog("CalendarDialog").then((d) => console.log(d)); } // do nothing diff --git a/src/packages/Syslog/PushNotification.ts b/src/packages/Syslog/PushNotification.ts index 8fa1407..ff79eda 100644 --- a/src/packages/Syslog/PushNotification.ts +++ b/src/packages/Syslog/PushNotification.ts @@ -226,7 +226,7 @@ namespace OS { * @param {GUI.TagEventType} evt * @memberof PushNotification */ - awake(evt: GUI.TagEventType): void { + awake(evt: GUI.TagEventType): void { if (this.view) { $(this.nzone).hide(); } else {