mirror of
https://github.com/lxsang/antos-frontend.git
synced 2025-02-20 17:22:46 +01:00
add more type, all defaults apps are now in typescript
This commit is contained in:
parent
6e95994892
commit
fb462fe31b
2
Makefile
2
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)/
|
||||
|
@ -35,7 +35,7 @@ namespace OS {
|
||||
*/
|
||||
export abstract class BaseApplication extends BaseModel {
|
||||
setting: GenericObject<any>;
|
||||
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<any>} promise
|
||||
* @returns {Promise<any>}
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
load(promise: Promise<any>): Promise<any> {
|
||||
protected load(promise: Promise<any>): Promise<any> {
|
||||
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;
|
||||
|
@ -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<GUI.tag.ListItemEventData>) => {
|
||||
const data = listview.selectedItem;
|
||||
if (!data) {
|
||||
return this.notify(__("Please select an item"));
|
||||
|
@ -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<any>} cmd
|
||||
* @returns {Promise<any>}
|
||||
* @memberof BaseModel
|
||||
*/
|
||||
call(cmd: GenericObject<any>): Promise<any> {
|
||||
protected call(cmd: GenericObject<any>): Promise<any> {
|
||||
return this._api.apigateway(cmd, false);
|
||||
}
|
||||
|
||||
// get a stream
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @returns {Promise<WebSocket>}
|
||||
* @memberof BaseModel
|
||||
*/
|
||||
stream(): Promise<WebSocket> {
|
||||
protected stream(): Promise<WebSocket> {
|
||||
return this._api.apigateway(null, true) as Promise<WebSocket>;
|
||||
}
|
||||
|
||||
@ -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<any>} [data]
|
||||
* @returns {Promise<any>}
|
||||
* @memberof BaseModel
|
||||
@ -346,24 +378,30 @@ namespace OS {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @param {GenericObject<any>} data
|
||||
* @returns {Promise<any>}
|
||||
* @memberof BaseModel
|
||||
*/
|
||||
ask(data: GenericObject<any>): Promise<any> {
|
||||
protected ask(data: GenericObject<any>): Promise<any> {
|
||||
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];
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace OS {
|
||||
domel: HTMLElement;
|
||||
private timer: number;
|
||||
holder: HTMLElement;
|
||||
onmenuselect: (d: OS.GUI.TagEventType) => void;
|
||||
onmenuselect: (d: OS.GUI.TagEventType<GUI.tag.MenuEventData>) => 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<GUI.tag.MenuEventData>): 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;
|
||||
|
@ -992,14 +992,14 @@ namespace OS {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @export
|
||||
* @param {*} f
|
||||
* @returns {Promise<RequestResult>}
|
||||
*/
|
||||
export function setting(f: any): Promise<RequestResult> {
|
||||
export function setting(): Promise<RequestResult> {
|
||||
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 = {};
|
||||
|
@ -83,7 +83,7 @@ namespace OS {
|
||||
}
|
||||
$(parent as GenericObject<any>).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<tag.ListItemEventData>) {
|
||||
($("#sysdock")[0] as tag.AppDockTag).selectedApp = null;
|
||||
};
|
||||
|
||||
desktop.onlistdbclick = function (d: TagEventType) {
|
||||
desktop.onlistdbclick = function (d: TagEventType<tag.ListItemEventData>) {
|
||||
($("#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<tag.MenuEventData>) {
|
||||
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, []);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -158,7 +158,7 @@ namespace OS {
|
||||
|
||||
export function setting(): Promise<RequestResult> {
|
||||
const p = `${API.REST}/system/settings`;
|
||||
return API.post(p, setting);
|
||||
return API.post(p, OS.setting);
|
||||
}
|
||||
|
||||
export function dbquery(
|
||||
|
@ -28,7 +28,7 @@ namespace OS {
|
||||
*/
|
||||
export class AppDockTag extends AFXTag {
|
||||
|
||||
private _onappselect: TagEventCallback;
|
||||
private _onappselect: TagEventCallback<any>;
|
||||
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]();
|
||||
}
|
||||
|
@ -8,11 +8,12 @@ namespace OS {
|
||||
export namespace tag {
|
||||
export class ButtonTag extends AFXTag {
|
||||
private _selected: boolean;
|
||||
private _onbtclick: TagEventCallback;
|
||||
private _onbtclick: TagEventCallback<JQuery.MouseEventBase>;
|
||||
data: GenericObject<any>;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
set onbtclick(v: TagEventCallback)
|
||||
set onbtclick(v: TagEventCallback<JQuery.MouseEventBase>)
|
||||
{
|
||||
this._onbtclick = v;
|
||||
}
|
||||
@ -61,7 +62,7 @@ namespace OS {
|
||||
|
||||
protected mount() {
|
||||
$(this.refs.button).click((e) => {
|
||||
const evt: TagEventType = {
|
||||
const evt: TagEventType<JQuery.MouseEventBase> = {
|
||||
id: this.aid,
|
||||
data: e,
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ namespace OS {
|
||||
private _month: number;
|
||||
private _year: number;
|
||||
private _selectedDate: Date;
|
||||
private _ondateselect: TagEventCallback;
|
||||
private _ondateselect: TagEventCallback<Date>;
|
||||
|
||||
/**
|
||||
*Creates an instance of CalendarTag.
|
||||
@ -71,7 +71,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof CalendarTag
|
||||
*/
|
||||
set ondateselect(v: TagEventCallback) {
|
||||
set ondateselect(v: TagEventCallback<Date>) {
|
||||
this._ondateselect = v;
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ namespace OS {
|
||||
* @returns {void}
|
||||
* @memberof CalendarTag
|
||||
*/
|
||||
private dateselect(e: TagEventType): void {
|
||||
private dateselect(e: TagEventType<TagEventDataType<tag.GridCellPrototype>>): void {
|
||||
if (!e.data.item) {
|
||||
return;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace OS {
|
||||
*/
|
||||
export class ColorPickerTag extends AFXTag {
|
||||
private _selectedColor: ColorType;
|
||||
private _oncolorselect: TagEventCallback;
|
||||
private _oncolorselect: TagEventCallback<ColorType>;
|
||||
|
||||
/**
|
||||
*Creates an instance of ColorPickerTag.
|
||||
@ -73,7 +73,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ColorPickerTag
|
||||
*/
|
||||
set oncolorselect(v: TagEventCallback) {
|
||||
set oncolorselect(v: TagEventCallback<ColorType>) {
|
||||
this._oncolorselect = v;
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@ namespace OS {
|
||||
* @extends {AFXTag}
|
||||
*/
|
||||
export class FileViewTag extends AFXTag {
|
||||
private _onfileselect: TagEventCallback;
|
||||
private _onfileopen: TagEventCallback;
|
||||
private _onfileselect: TagEventCallback<API.FileInfoType>;
|
||||
private _onfileopen: TagEventCallback<API.FileInfoType>;
|
||||
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<API.FileInfoType>) {
|
||||
this._onfileselect = e;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof FileViewTag
|
||||
*/
|
||||
set onfileopen(e: TagEventCallback) {
|
||||
set onfileopen(e: TagEventCallback<API.FileInfoType>) {
|
||||
this._onfileopen = e;
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof FileViewTag
|
||||
*/
|
||||
set ondragndrop(v: TagEventCallback) {
|
||||
set ondragndrop(v: TagEventCallback<DnDEventDataType<TreeViewTag| ListViewItemTag>>) {
|
||||
(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();
|
||||
}
|
||||
|
@ -27,20 +27,20 @@ namespace OS {
|
||||
protected calibrate(): void {}
|
||||
protected reload(d?: any): void {}
|
||||
}
|
||||
|
||||
export type CellEventData = TagEventDataType<GridCellPrototype>;
|
||||
export abstract class GridCellPrototype extends AFXTag {
|
||||
private _oncellselect: TagEventCallback;
|
||||
private _oncelldbclick: TagEventCallback;
|
||||
private _oncellselect: TagEventCallback<CellEventData>;
|
||||
private _oncelldbclick: TagEventCallback<CellEventData>;
|
||||
private _data: GenericObject<any>;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
set oncellselect(v: TagEventCallback) {
|
||||
set oncellselect(v: TagEventCallback<CellEventData>) {
|
||||
this._oncellselect = v;
|
||||
}
|
||||
set oncelldbclick(v: TagEventCallback) {
|
||||
set oncelldbclick(v: TagEventCallback<CellEventData>) {
|
||||
this._oncelldbclick = v;
|
||||
}
|
||||
set data(v: GenericObject<any>) {
|
||||
@ -77,7 +77,7 @@ namespace OS {
|
||||
protected mount(): void {
|
||||
$(this).attr("class", "afx-grid-cell");
|
||||
this.oncelldbclick = this.oncellselect = (
|
||||
e: TagEventType
|
||||
e: TagEventType<GridCellPrototype>
|
||||
): 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<GridCellPrototype>, 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<CellEventData>;
|
||||
private _onrowselect: TagEventCallback<CellEventData>;
|
||||
private _oncelldbclick: TagEventCallback<CellEventData>;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
@ -143,17 +143,17 @@ namespace OS {
|
||||
this._selectedRow = undefined;
|
||||
this._rows = [];
|
||||
this._oncellselect = this._onrowselect = this._oncelldbclick = (
|
||||
e: TagEventType
|
||||
e: TagEventType<CellEventData>
|
||||
): void => {};
|
||||
}
|
||||
protected reload(d?: any): void {}
|
||||
set oncellselect(v: TagEventCallback) {
|
||||
set oncellselect(v: TagEventCallback<CellEventData>) {
|
||||
this._oncellselect = v;
|
||||
}
|
||||
set onrowselect(v: TagEventCallback) {
|
||||
set onrowselect(v: TagEventCallback<CellEventData>) {
|
||||
this._onrowselect = v;
|
||||
}
|
||||
set oncelldbclick(v: TagEventCallback) {
|
||||
set oncelldbclick(v: TagEventCallback<CellEventData>) {
|
||||
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<CellEventData>, 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<CellEventData>): 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(
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace OS {
|
||||
export namespace GUI {
|
||||
export namespace tag {
|
||||
export type ListItemEventData = TagEventDataType<ListViewItemTag>
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -18,11 +19,11 @@ namespace OS {
|
||||
*/
|
||||
export abstract class ListViewItemTag extends AFXTag {
|
||||
private _data: GenericObject<any>;
|
||||
private _onselect: TagEventCallback;
|
||||
private _onctxmenu: TagEventCallback;
|
||||
private _onclick: TagEventCallback;
|
||||
private _ondbclick: TagEventCallback;
|
||||
private _onclose: TagEventCallback;
|
||||
private _onselect: TagEventCallback<ListItemEventData>;
|
||||
private _onctxmenu: TagEventCallback<ListItemEventData>;
|
||||
private _onclick: TagEventCallback<ListItemEventData>;
|
||||
private _ondbclick: TagEventCallback<ListItemEventData>;
|
||||
private _onclose: TagEventCallback<ListItemEventData>;
|
||||
|
||||
/**
|
||||
*Creates an instance of ListViewItemTag.
|
||||
@ -56,7 +57,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewItemTag
|
||||
*/
|
||||
set onitemselect(v: TagEventCallback) {
|
||||
set onitemselect(v: TagEventCallback<ListViewItemTag>) {
|
||||
this._onselect = v;
|
||||
}
|
||||
|
||||
@ -83,7 +84,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewItemTag
|
||||
*/
|
||||
set onctxmenu(v: TagEventCallback) {
|
||||
set onctxmenu(v: TagEventCallback<ListViewItemTag>) {
|
||||
this._onctxmenu = v;
|
||||
}
|
||||
|
||||
@ -92,7 +93,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewItemTag
|
||||
*/
|
||||
set onitemclick(v: TagEventCallback) {
|
||||
set onitemclick(v: TagEventCallback<ListViewItemTag>) {
|
||||
this._onclick = v;
|
||||
}
|
||||
|
||||
@ -101,7 +102,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewItemTag
|
||||
*/
|
||||
set onitemdbclick(v: TagEventCallback) {
|
||||
set onitemdbclick(v: TagEventCallback<ListViewItemTag>) {
|
||||
this._ondbclick = v;
|
||||
}
|
||||
|
||||
@ -110,7 +111,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewItemTag
|
||||
*/
|
||||
set onitemclose(v: TagEventCallback) {
|
||||
set onitemclose(v: TagEventCallback<ListViewItemTag>) {
|
||||
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<ListItemEventData>;
|
||||
private _onlistdbclick: TagEventCallback<ListItemEventData>;
|
||||
private _ondragndrop: TagEventCallback<DnDEventDataType<ListViewItemTag>>;
|
||||
private _onitemclose: (e: TagEventType<ListItemEventData>) => 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<ListItemEventData>
|
||||
) => {};
|
||||
this._onitemclose = (e: TagEventType) => {
|
||||
this._onitemclose = (e: TagEventType<ListItemEventData>) => {
|
||||
return true;
|
||||
};
|
||||
this._onmousedown = this._onmouseup = this._onmousemove = (
|
||||
@ -384,7 +385,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewTag
|
||||
*/
|
||||
set ondragndrop(v: TagEventCallback) {
|
||||
set ondragndrop(v: TagEventCallback<DnDEventDataType<ListViewItemTag>>) {
|
||||
this._ondragndrop = v;
|
||||
}
|
||||
|
||||
@ -393,7 +394,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewTag
|
||||
*/
|
||||
set onlistselect(v: TagEventCallback) {
|
||||
set onlistselect(v: TagEventCallback<ListItemEventData>) {
|
||||
this._onlistselect = v;
|
||||
}
|
||||
|
||||
@ -402,7 +403,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewTag
|
||||
*/
|
||||
set onlistdbclick(v: TagEventCallback) {
|
||||
set onlistdbclick(v: TagEventCallback<ListItemEventData>) {
|
||||
this._onlistdbclick = v;
|
||||
}
|
||||
|
||||
@ -411,7 +412,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof ListViewTag
|
||||
*/
|
||||
set onitemclose(v: (e: TagEventType) => boolean) {
|
||||
set onitemclose(v: (e: TagEventType<ListItemEventData>) => boolean) {
|
||||
this._onitemclose = v;
|
||||
}
|
||||
|
||||
@ -500,6 +501,7 @@ namespace OS {
|
||||
for (let item of v) {
|
||||
$(this.refs.btlist).show();
|
||||
const bt = $("<afx-button>").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<ListViewItemTag>, 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<ListViewItemTag>) {
|
||||
const evt: TagEventType<ListItemEventData> = { 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<ListViewItemTag>) {
|
||||
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<ListViewItemTag>): void {
|
||||
if (!e.data) {
|
||||
return;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace OS {
|
||||
export namespace GUI {
|
||||
export namespace tag {
|
||||
export type MenuEventData = TagEventDataType<MenuEntryTag>;
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -18,8 +19,8 @@ namespace OS {
|
||||
*/
|
||||
export abstract class MenuEntryTag extends AFXTag {
|
||||
private _data: GenericObject<any>;
|
||||
private _onmenuselect: TagEventCallback;
|
||||
private _onchildselect: TagEventCallback;
|
||||
private _onmenuselect: TagEventCallback<MenuEventData>;
|
||||
private _onchildselect: TagEventCallback<MenuEventData>;
|
||||
parent: MenuEntryTag;
|
||||
root: MenuTag;
|
||||
|
||||
@ -30,7 +31,7 @@ namespace OS {
|
||||
constructor() {
|
||||
super();
|
||||
this._onmenuselect = this._onchildselect = (
|
||||
e: TagEventType
|
||||
e: TagEventType<MenuEventData>
|
||||
): void => {};
|
||||
}
|
||||
|
||||
@ -48,7 +49,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof MenuEntryTag
|
||||
*/
|
||||
set onmenuselect(v: TagEventCallback) {
|
||||
set onmenuselect(v: TagEventCallback<MenuEventData>) {
|
||||
this._onmenuselect = v;
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof MenuEntryTag
|
||||
*/
|
||||
set onchildselect(v: TagEventCallback) {
|
||||
set onchildselect(v: TagEventCallback<MenuEventData>) {
|
||||
this._onchildselect = v;
|
||||
}
|
||||
|
||||
@ -67,7 +68,7 @@ namespace OS {
|
||||
* @type {TagEventCallback}
|
||||
* @memberof MenuEntryTag
|
||||
*/
|
||||
get onchildselect(): TagEventCallback {
|
||||
get onchildselect(): TagEventCallback<MenuEventData> {
|
||||
return this._onchildselect;
|
||||
}
|
||||
/**
|
||||
@ -462,7 +463,7 @@ namespace OS {
|
||||
parent: MenuEntryTag;
|
||||
root: MenuTag;
|
||||
pid: number;
|
||||
private _onmenuselect: TagEventCallback;
|
||||
private _onmenuselect: TagEventCallback<MenuEventData>;
|
||||
private _items: GenericObject<any>[];
|
||||
|
||||
/**
|
||||
@ -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<MenuEventData>): void => {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -554,7 +555,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof MenuTag
|
||||
*/
|
||||
set onmenuselect(v: TagEventCallback) {
|
||||
set onmenuselect(v: TagEventCallback<MenuEventData>) {
|
||||
this._onmenuselect = v;
|
||||
}
|
||||
|
||||
@ -584,7 +585,7 @@ namespace OS {
|
||||
* @type {TagEventCallback}
|
||||
* @memberof MenuTag
|
||||
*/
|
||||
get onmenuitemselect(): TagEventCallback {
|
||||
get onmenuitemselect(): TagEventCallback<MenuEventData> {
|
||||
return this.handleselect;
|
||||
}
|
||||
|
||||
@ -595,7 +596,7 @@ namespace OS {
|
||||
* @param {TagEventType} e
|
||||
* @memberof MenuTag
|
||||
*/
|
||||
private handleselect(e: TagEventType): void {
|
||||
private handleselect(e: TagEventType<MenuEventData>): void {
|
||||
if (this.context) {
|
||||
$(this).hide();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace OS {
|
||||
* @extends {AFXTag}
|
||||
*/
|
||||
export class NSpinnerTag extends AFXTag {
|
||||
private _onchange: TagEventCallback;
|
||||
private _onchange: TagEventCallback<number>;
|
||||
private _value: number;
|
||||
step: number;
|
||||
|
||||
@ -50,7 +50,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof NSpinnerTag
|
||||
*/
|
||||
set onvaluechange(f: TagEventCallback) {
|
||||
set onvaluechange(f: TagEventCallback<number>) {
|
||||
this._onchange = f;
|
||||
}
|
||||
|
||||
|
@ -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<number>;
|
||||
private _onchanging: TagEventCallback<number>;
|
||||
|
||||
/**
|
||||
*Creates an instance of SliderTag.
|
||||
@ -53,7 +53,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof SliderTag
|
||||
*/
|
||||
set onvaluechange(f: TagEventCallback) {
|
||||
set onvaluechange(f: TagEventCallback<number>) {
|
||||
this._onchange = f;
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof SliderTag
|
||||
*/
|
||||
set onvaluechanging(f: TagEventCallback) {
|
||||
set onvaluechanging(f: TagEventCallback<number>) {
|
||||
this._onchanging = f;
|
||||
}
|
||||
|
||||
|
@ -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<boolean>;
|
||||
private _onchanging: TagEventCallback<boolean>;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@ -34,7 +34,7 @@ namespace OS {
|
||||
return this.hasattr("enable");
|
||||
}
|
||||
|
||||
set onswchange(v: TagEventCallback) {
|
||||
set onswchange(v: TagEventCallback<boolean>) {
|
||||
this._onchange = v;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace OS {
|
||||
export namespace GUI {
|
||||
export namespace tag {
|
||||
|
||||
type TabEventData = TagEventDataType<ListViewItemTag>;
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -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<TabEventData>) => boolean;
|
||||
private _ontabselect: TagEventCallback<TabEventData>;
|
||||
|
||||
/**
|
||||
*Creates an instance of TabBarTag.
|
||||
@ -146,7 +146,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof TabBarTag
|
||||
*/
|
||||
set ontabclose(v: (e: TagEventType) => boolean) {
|
||||
set ontabclose(v: (e: TagEventType<TabEventData>) => boolean) {
|
||||
this._ontabclose = v;
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof TabBarTag
|
||||
*/
|
||||
set ontabselect(v: TagEventCallback) {
|
||||
set ontabselect(v: TagEventCallback<TabEventData>) {
|
||||
this._ontabselect = v;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace OS {
|
||||
*/
|
||||
export class TabContainerTag extends AFXTag {
|
||||
private _selectedTab: TabContainerTabType;
|
||||
private _ontabselect: TagEventCallback;
|
||||
private _ontabselect: TagEventCallback<TabContainerTabType>;
|
||||
|
||||
/**
|
||||
*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<TabContainerTabType>) {
|
||||
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<any>;
|
||||
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<any>;
|
||||
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();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace OS {
|
||||
selected?: boolean;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export type TreeItemEventData = TagEventDataType<TreeViewItemPrototype>;
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -31,7 +31,7 @@ namespace OS {
|
||||
export abstract class TreeViewItemPrototype extends AFXTag {
|
||||
private _data: TreeViewDataType;
|
||||
private _indent: number;
|
||||
private _evt: TagEventType;
|
||||
private _evt: TagEventType<TreeItemEventData>;
|
||||
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<TreeItemEventData>;
|
||||
private _ontreedbclick: TagEventCallback<TreeItemEventData>;
|
||||
private _ondragndrop: TagEventCallback<DnDEventDataType<TreeViewTag>>;
|
||||
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<TreeItemEventData>) {
|
||||
this._ontreeselect = v;
|
||||
}
|
||||
|
||||
@ -513,7 +513,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof TreeViewTag
|
||||
*/
|
||||
set ontreedbclick(v: TagEventCallback) {
|
||||
set ontreedbclick(v: TagEventCallback<TreeItemEventData>) {
|
||||
this._ontreedbclick = v;
|
||||
}
|
||||
|
||||
@ -605,7 +605,7 @@ namespace OS {
|
||||
* @returns {void}
|
||||
* @memberof TreeViewTag
|
||||
*/
|
||||
itemclick(e: TagEventType): void {
|
||||
itemclick(e: TagEventType<TreeItemEventData>): void {
|
||||
if (!e || !e.data) {
|
||||
return;
|
||||
}
|
||||
@ -656,7 +656,7 @@ namespace OS {
|
||||
*
|
||||
* @memberof TreeViewTag
|
||||
*/
|
||||
set ondragndrop(v: TagEventCallback) {
|
||||
set ondragndrop(v: TagEventCallback<DnDEventDataType<TreeViewTag>>) {
|
||||
this._ondragndrop = v;
|
||||
}
|
||||
|
||||
|
@ -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<T> {
|
||||
item?: T,
|
||||
[propName:string]: any;
|
||||
}
|
||||
export interface TagEventType<T>{
|
||||
id: number | string;
|
||||
data: any;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export type TagEventCallback = (e: TagEventType) => void;
|
||||
export interface DnDEventDataType<T> {
|
||||
from: T;
|
||||
to: T;
|
||||
}
|
||||
|
||||
export type TagEventCallback<T> = (e: TagEventType<T>) => 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 {
|
||||
|
@ -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;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
@ -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, []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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"))
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -282,11 +282,11 @@ namespace OS {
|
||||
private run(meta: GenericObject<any>): Promise<any> {
|
||||
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<any>;
|
||||
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<GUI.tag.ListItemEventData>) => {
|
||||
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
|
||||
|
@ -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<GUI.tag.MenuEventData>
|
||||
) => {
|
||||
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<GUI.tag.ListItemEventData>,
|
||||
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<GUI.tag.ListItemEventData>,
|
||||
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<GUI.tag.MenuEventData>,
|
||||
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<GUI.tag.MenuEventData>
|
||||
): 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<GUI.tag.MenuEventData>,
|
||||
r: CodePadFileHandle
|
||||
) => {
|
||||
return this.spotlight.run(this);
|
||||
@ -969,7 +982,10 @@ namespace OS {
|
||||
private shortcut: string;
|
||||
nodes: GenericObject<any>[];
|
||||
parent: CMDMenu;
|
||||
private select: (e: GUI.TagEventType, r: CodePad) => void;
|
||||
private select: (
|
||||
e: GUI.TagEventType<GUI.tag.ListItemEventData>,
|
||||
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<GUI.tag.ListItemEventData>,
|
||||
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();
|
||||
|
@ -7,5 +7,5 @@ cssfiles = main.css
|
||||
copyfiles = scheme.html package.json
|
||||
|
||||
|
||||
PKG_NAME=ActivityFile
|
||||
PKG_NAME=Files
|
||||
include ../pkg.mk
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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);
|
699
src/packages/Files/main.ts
Normal file
699
src/packages/Files/main.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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<GUI.tag.MenuEventData>) => {
|
||||
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<GUI.tag.MenuEventData>) =>
|
||||
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<GUI.tag.MenuEventData>) =>
|
||||
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<GUI.tag.MenuEventData>) => {
|
||||
const { type } = e.data.item.data;
|
||||
this.view.view = type;
|
||||
return (this.viewType[type] = true);
|
||||
},
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) => 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<GUI.tag.MenuEventData>): 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
module_files = dialog.js main.js
|
||||
module_files = main.js dialog.js
|
||||
|
||||
libfiles =
|
||||
|
||||
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
108
src/packages/MarketPlace/dialog.ts
Normal file
108
src/packages/MarketPlace/dialog.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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(
|
||||
$("<li>")
|
||||
.append(($("<span class= 'info-header'>")).html(k))
|
||||
.append($("<span>").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);
|
614
src/packages/MarketPlace/main.ts
Normal file
614
src/packages/MarketPlace/main.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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<any>[];
|
||||
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<any>;
|
||||
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<any>): 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<any>): 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(
|
||||
$("<li>")
|
||||
.append(
|
||||
$("<span class= 'info-header'>").html(k)
|
||||
)
|
||||
.append($("<span>").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<GUI.tag.MenuEventData>
|
||||
) => {
|
||||
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<string> {
|
||||
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<string> {
|
||||
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<any>
|
||||
): Promise<string> {
|
||||
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<any> {
|
||||
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<any>{
|
||||
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<any> {
|
||||
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<any>{
|
||||
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;
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width = "3" ></afx-resizer>
|
||||
<afx-vbox data-id = "container">
|
||||
<div data-id = "appname" data-height = "25"></div>
|
||||
<afx-label data-id = "appname" data-height = "25"></afx-label>
|
||||
<afx-hbox data-height = "30">
|
||||
<div style = "text-align:left;">
|
||||
<afx-button data-id = "bt-remove" text = "__(Uninstall)"></afx-button>
|
||||
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
206
src/packages/Setting/AppearanceHandle.ts
Normal file
206
src/packages/Setting/AppearanceHandle.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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<any>;
|
||||
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<any>[]}
|
||||
* @memberof AppearanceHandle
|
||||
*/
|
||||
private getwplist(): GenericObject<any>[] {
|
||||
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;
|
||||
}
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
77
src/packages/Setting/LocaleHandle.ts
Normal file
77
src/packages/Setting/LocaleHandle.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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<any>[];
|
||||
|
||||
/**
|
||||
*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;
|
||||
}
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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;
|
||||
})()));
|
||||
}
|
||||
}
|
155
src/packages/Setting/StartupHandle.ts
Normal file
155
src/packages/Setting/StartupHandle.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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;
|
||||
}
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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 = `\
|
||||
<afx-app-window width='250' height='180' apptitle = "__(Mount Points)">
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<div data-width = "10" />
|
||||
<afx-vbox>
|
||||
<div data-height="10" />
|
||||
<afx-label data-height="30" text = "__(Name)" />
|
||||
<input type = "text" data-id= "txtName" />
|
||||
<div data-height="3" />
|
||||
<afx-label data-height="30" text = "__(Path)" />
|
||||
<input type = "text" data-id= "txtPath" />
|
||||
<div data-height="10" />
|
||||
<afx-hbox data-height="30">
|
||||
<div />
|
||||
<afx-button data-id = "btnOk" text = "__(Ok)" data-width = "40" />
|
||||
<afx-button data-id = "btnCancel" text = "__(Cancel)" data-width = "50" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
<div data-width = "10" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
</afx-app-window>\
|
||||
`;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
246
src/packages/Setting/VFSHandle.ts
Normal file
246
src/packages/Setting/VFSHandle.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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 = `\
|
||||
<afx-app-window width='250' height='180' apptitle = "__(Mount Points)">
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<div data-width = "10" />
|
||||
<afx-vbox>
|
||||
<div data-height="10" />
|
||||
<afx-label data-height="30" text = "__(Name)" />
|
||||
<input type = "text" data-id= "txtName" />
|
||||
<div data-height="3" />
|
||||
<afx-label data-height="30" text = "__(Path)" />
|
||||
<input type = "text" data-id= "txtPath" />
|
||||
<div data-height="10" />
|
||||
<afx-hbox data-height="30">
|
||||
<div />
|
||||
<afx-button data-id = "btnOk" text = "__(Ok)" data-width = "40" />
|
||||
<afx-button data-id = "btnCancel" text = "__(Cancel)" data-width = "50" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
<div data-width = "10" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
</afx-app-window>\
|
||||
`;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @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;
|
||||
}
|
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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);
|
136
src/packages/Setting/main.ts
Normal file
136
src/packages/Setting/main.ts
Normal file
@ -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 <xsang.le AT gmail DOT com>
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ namespace OS {
|
||||
});
|
||||
}
|
||||
|
||||
awake(e: GUI.TagEventType): void {
|
||||
awake(e: GUI.TagEventType<GUI.tag.MenuEventData>): void {
|
||||
this.openDialog("CalendarDialog").then((d) => console.log(d));
|
||||
}
|
||||
// do nothing
|
||||
|
@ -226,7 +226,7 @@ namespace OS {
|
||||
* @param {GUI.TagEventType} evt
|
||||
* @memberof PushNotification
|
||||
*/
|
||||
awake(evt: GUI.TagEventType): void {
|
||||
awake(evt: GUI.TagEventType<GUI.tag.MenuEventData>): void {
|
||||
if (this.view) {
|
||||
$(this.nzone).hide();
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user