add more type, all defaults apps are now in typescript

This commit is contained in:
Xuan Sang LE 2020-06-04 17:49:48 +02:00
parent 6e95994892
commit fb462fe31b
50 changed files with 2612 additions and 1734 deletions

View File

@ -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)/

View File

@ -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;

View File

@ -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"));

View File

@ -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];
}

View File

@ -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;

View File

@ -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 = {};

View File

@ -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, []);
});
})
});
}
});

View File

@ -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(

View File

@ -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]();
}

View File

@ -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,
};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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(

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}
/**
*
*

View File

@ -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, []);
});
}
}

View File

@ -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"))
);
});
});

View File

@ -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

View 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();

View File

@ -7,5 +7,5 @@ cssfiles = main.css
copyfiles = scheme.html package.json
PKG_NAME=ActivityFile
PKG_NAME=Files
include ../pkg.mk

View File

@ -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
View 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);
}
}
}
}
}

View File

@ -1,4 +1,4 @@
module_files = dialog.js main.js
module_files = main.js dialog.js
libfiles =

View File

@ -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);
}
}

View 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;
}

View File

@ -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;

View File

@ -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);

View 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;
}
}

View File

@ -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>

View File

@ -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;
}
}

View 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;
}

View File

@ -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);
}
}
}

View 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;
}

View File

@ -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;
})()));
}
}

View 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;
}

View File

@ -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);
}
}

View 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;
}

View File

@ -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);

View 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;
}
}

View File

@ -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

View File

@ -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 {