mirror of
https://github.com/lxsang/antos-frontend.git
synced 2025-07-26 18:59:45 +02:00
add more type, all defaults apps are now in typescript
This commit is contained in:
@ -373,9 +373,9 @@ namespace OS {
|
||||
v.iconclass = "fa fa-adn";
|
||||
}
|
||||
this.notify(__("Installing..."));
|
||||
this.app.systemsetting.system.packages[meta.name] = v;
|
||||
setting.system.packages[meta.name] = v;
|
||||
this.notify(__("Running {0}...", meta.name));
|
||||
return this.app._gui.forceLaunch(meta.name, []);
|
||||
return GUI.forceLaunch(meta.name, []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ namespace OS {
|
||||
.parent()
|
||||
.mk(path.basename)
|
||||
.then((d: any) => {
|
||||
this.app.trigger("filechange", {
|
||||
this.app.observable.trigger("filechange", {
|
||||
file: path.parent(),
|
||||
type: "dir",
|
||||
});
|
||||
@ -414,7 +414,7 @@ namespace OS {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.app.currdir) {
|
||||
return reject(
|
||||
this.app._api.throwe(__("Current folder is not found"))
|
||||
API.throwe(__("Current folder is not found"))
|
||||
);
|
||||
}
|
||||
`${this.app.currdir.path}/${file}`
|
||||
@ -423,7 +423,7 @@ namespace OS {
|
||||
.then((data) => resolve(data))
|
||||
.catch((e) => {
|
||||
return reject(
|
||||
this.app._api.throwe(__("Unable to read meta-data"))
|
||||
API.throwe(__("Unable to read meta-data"))
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -282,11 +282,11 @@ namespace OS {
|
||||
private run(meta: GenericObject<any>): Promise<any> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const path = `${meta.root}/build/debug/${meta.meta.name}.js`;
|
||||
if (this.app._api.shared[path]) {
|
||||
delete this.app._api.shared[path];
|
||||
if (API.shared[path]) {
|
||||
delete API.shared[path];
|
||||
}
|
||||
try {
|
||||
await this.app._api.requires(path);
|
||||
await API.requires(path);
|
||||
let v: GenericObject<any>;
|
||||
if (this.app.extensions[meta.meta.name]) {
|
||||
this.app.extensions[meta.meta.name].child = [];
|
||||
@ -306,9 +306,9 @@ namespace OS {
|
||||
this.app.extensions[meta.meta.name]
|
||||
);
|
||||
this.app.extensions[meta.meta.name].onchildselect(
|
||||
(e: GUI.TagEventType) => {
|
||||
(e: GUI.TagEventType<GUI.tag.ListItemEventData>) => {
|
||||
return this.app.loadAndRunExtensionAction(
|
||||
e.data.item.data
|
||||
e.data.item.data as any
|
||||
);
|
||||
}
|
||||
);
|
||||
@ -334,7 +334,7 @@ namespace OS {
|
||||
return new Promise((resolve, reject) => {
|
||||
const idx = files.indexOf("extension.json");
|
||||
if (idx < 0) {
|
||||
reject(this.app._api.throwe(__("No meta-data found")));
|
||||
reject(API.throwe(__("No meta-data found")));
|
||||
}
|
||||
const metafile = files.splice(idx, 1)[0];
|
||||
// read the meta file
|
||||
|
@ -178,7 +178,9 @@ namespace OS {
|
||||
if (e.data.type === "dir") {
|
||||
return;
|
||||
}
|
||||
return this.openFile(e.data.path.asFileHandle());
|
||||
return this.openFile(
|
||||
e.data.path.asFileHandle() as CodePadFileHandle
|
||||
);
|
||||
};
|
||||
|
||||
this.fileview.onfileselect = (e) => {
|
||||
@ -188,7 +190,9 @@ namespace OS {
|
||||
if (e.data.type === "dir") {
|
||||
return;
|
||||
}
|
||||
const i = this.findTabByFile(e.data.path.asFileHandle());
|
||||
const i = this.findTabByFile(
|
||||
e.data.path.asFileHandle() as CodePadFileHandle
|
||||
);
|
||||
if (i !== -1) {
|
||||
return (this.tabbar.selected = i);
|
||||
}
|
||||
@ -202,7 +206,9 @@ namespace OS {
|
||||
m.items = [
|
||||
{
|
||||
text: __("Command palete"),
|
||||
onmenuselect: (e: GUI.TagEventType) => {
|
||||
onmenuselect: (
|
||||
e: GUI.TagEventType<GUI.tag.MenuEventData>
|
||||
) => {
|
||||
return this.spotlight.run(this);
|
||||
},
|
||||
},
|
||||
@ -237,17 +243,19 @@ namespace OS {
|
||||
.then(function (d: any) {
|
||||
const p1 = des;
|
||||
const p2 = src.parent().path;
|
||||
if(p1.length < p2.length)
|
||||
{
|
||||
if (p1.length < p2.length) {
|
||||
e.data.to.update(p1);
|
||||
e.data.from.parent.update(p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
e.data.from.parent.update(p2);
|
||||
(e.data
|
||||
.from as GUI.tag.TreeViewTag).parent.update(
|
||||
p2
|
||||
);
|
||||
} else {
|
||||
(e.data
|
||||
.from as GUI.tag.TreeViewTag).parent.update(
|
||||
p2
|
||||
);
|
||||
e.data.to.update(p1);
|
||||
}
|
||||
|
||||
})
|
||||
.catch((e: Error) =>
|
||||
this.error(__("Unable to move file/folder"), e)
|
||||
@ -268,7 +276,6 @@ namespace OS {
|
||||
return this.openFile(this.currfile);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -443,7 +450,6 @@ namespace OS {
|
||||
this.langstat.text = this.currfile.langmode.caption;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -500,7 +506,7 @@ namespace OS {
|
||||
cmdtheme.addAction({ text: v.caption, theme: v.theme });
|
||||
}
|
||||
cmdtheme.onchildselect(function (
|
||||
d: GUI.TagEventType,
|
||||
d: GUI.TagEventType<GUI.tag.ListItemEventData>,
|
||||
r: CodePad
|
||||
) {
|
||||
const data = d.data.item.data;
|
||||
@ -513,7 +519,7 @@ namespace OS {
|
||||
cmdmode.addAction({ text: v.caption, mode: v.mode });
|
||||
}
|
||||
cmdmode.onchildselect(function (
|
||||
d: GUI.TagEventType,
|
||||
d: GUI.TagEventType<GUI.tag.ListItemEventData>,
|
||||
r: CodePad
|
||||
) {
|
||||
const data = d.data.item.data;
|
||||
@ -529,7 +535,6 @@ namespace OS {
|
||||
this.addAction(CMDMenu.fromMenu(this.fileMenu()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -558,9 +563,13 @@ namespace OS {
|
||||
this.extensions[ext.name]
|
||||
);
|
||||
this.extensions[ext.name].onchildselect(
|
||||
(e: GUI.TagEventType) => {
|
||||
(
|
||||
e: GUI.TagEventType<
|
||||
GUI.tag.ListItemEventData
|
||||
>
|
||||
) => {
|
||||
return this.loadAndRunExtensionAction(
|
||||
e.data.item.data
|
||||
e.data.item.data as any
|
||||
);
|
||||
}
|
||||
);
|
||||
@ -601,7 +610,6 @@ namespace OS {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -660,7 +668,10 @@ namespace OS {
|
||||
shortcut: "A-W",
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType, r: CodePad) => {
|
||||
onchildselect: (
|
||||
e: GUI.TagEventType<GUI.tag.MenuEventData>,
|
||||
r: CodePad
|
||||
) => {
|
||||
return this.menuAction(e.data.item.data.dataid, r);
|
||||
},
|
||||
};
|
||||
@ -674,7 +685,9 @@ namespace OS {
|
||||
* @returns {void}
|
||||
* @memberof CodePad
|
||||
*/
|
||||
private ctxFileMenuHandle(e: GUI.TagEventType): void {
|
||||
private ctxFileMenuHandle(
|
||||
e: GUI.TagEventType<GUI.tag.MenuEventData>
|
||||
): void {
|
||||
const el = e.data.item as GUI.tag.MenuEntryTag;
|
||||
if (!el) {
|
||||
return;
|
||||
@ -949,7 +962,7 @@ namespace OS {
|
||||
},
|
||||
],
|
||||
onchildselect: (
|
||||
e: GUI.TagEventType,
|
||||
e: GUI.TagEventType<GUI.tag.MenuEventData>,
|
||||
r: CodePadFileHandle
|
||||
) => {
|
||||
return this.spotlight.run(this);
|
||||
@ -969,7 +982,10 @@ namespace OS {
|
||||
private shortcut: string;
|
||||
nodes: GenericObject<any>[];
|
||||
parent: CMDMenu;
|
||||
private select: (e: GUI.TagEventType, r: CodePad) => void;
|
||||
private select: (
|
||||
e: GUI.TagEventType<GUI.tag.ListItemEventData>,
|
||||
r: CodePad
|
||||
) => void;
|
||||
static fromMenu: (mn: GUI.BasicItemType) => CMDMenu;
|
||||
|
||||
/**
|
||||
@ -1017,7 +1033,10 @@ namespace OS {
|
||||
* @memberof CMDMenu
|
||||
*/
|
||||
onchildselect(
|
||||
f: (e: GUI.TagEventType, r: CodePad) => void
|
||||
f: (
|
||||
e: GUI.TagEventType<GUI.tag.ListItemEventData>,
|
||||
r: CodePad
|
||||
) => void
|
||||
): CMDMenu {
|
||||
this.select = f;
|
||||
return this;
|
||||
@ -1093,7 +1112,10 @@ namespace OS {
|
||||
const offset = $(".afx-window-content", win).offset();
|
||||
const pw = win.width / 5;
|
||||
(this.scheme as GUI.tag.WindowTag).width = 3 * pw;
|
||||
$(this.scheme).offset({ top: offset.top - 2, left: offset.left + pw });
|
||||
$(this.scheme).offset({
|
||||
top: offset.top - 2,
|
||||
left: offset.left + pw,
|
||||
});
|
||||
var cb = (e: JQuery.MouseEventBase) => {
|
||||
if ($(e.target).closest(this.scheme).length > 0) {
|
||||
return $(this.find("searchbox")).focus();
|
||||
|
@ -7,5 +7,5 @@ cssfiles = main.css
|
||||
copyfiles = scheme.html package.json
|
||||
|
||||
|
||||
PKG_NAME=ActivityFile
|
||||
PKG_NAME=Files
|
||||
include ../pkg.mk
|
@ -1,424 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class Files extends this.OS.GUI.BaseApplication {
|
||||
constructor(args) {
|
||||
super("Files", args);
|
||||
}
|
||||
|
||||
main() {
|
||||
this.scheme.set("apptitle", "Files manager");
|
||||
this.view = this.find("fileview");
|
||||
this.navinput = this.find("navinput");
|
||||
this.navbar = this.find("nav-bar");
|
||||
if (this.args && (this.args.length > 0)) {
|
||||
this.currdir = this.args[0].path.asFileHandle();
|
||||
} else {
|
||||
this.currdir = "home://".asFileHandle();
|
||||
}
|
||||
this.favo = this.find("favouri");
|
||||
this.clipboard = undefined;
|
||||
this.viewType = this._api.switcher("icon", "list", "tree");
|
||||
this.viewType.list = true;
|
||||
|
||||
this.view.contextmenuHandle = (e, m) => {
|
||||
const file = this.view.get("selectedFile");
|
||||
if (!file) { return; }
|
||||
const apps = [];
|
||||
if (file.type === "dir") { file.mime = "dir"; }
|
||||
|
||||
for (let v of Array.from(this._gui.appsByMime(file.mime))) {
|
||||
apps.push({
|
||||
text: v.text,
|
||||
app: v.app,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass
|
||||
});
|
||||
}
|
||||
|
||||
m.set("items", [
|
||||
{
|
||||
text: "__(Open with)",
|
||||
child: apps,
|
||||
onchildselect: e => {
|
||||
if (!e) { return; }
|
||||
const it = e.data.item.get("data");
|
||||
return this._gui.launch(it.app, [file]);
|
||||
}
|
||||
},
|
||||
this.mnFile(),
|
||||
this.mnEdit()
|
||||
]);
|
||||
return m.show(e);
|
||||
};
|
||||
|
||||
this.view.set("onfileopen", e => {
|
||||
if (!e.data) { return; }
|
||||
if (e.data.type === "dir") { return; }
|
||||
return this._gui.openWith(e.data);
|
||||
});
|
||||
|
||||
this.favo.set("onlistselect", e => {
|
||||
return this.view.set("path", e.data.item.get("data").path);
|
||||
});
|
||||
|
||||
($(this.find("btback"))).click(() => {
|
||||
if (this.currdir.isRoot()) { return; }
|
||||
const p = this.currdir.parent();
|
||||
this.favo.set("selected", -1);
|
||||
return this.view.set("path", p.path);
|
||||
});
|
||||
|
||||
($(this.navinput)).keyup(e => {
|
||||
if (e.keyCode === 13) { return this.view.set("path", ($(this.navinput)).val()); }
|
||||
}); //enter
|
||||
|
||||
this.view.set("fetch", path => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dir = path;
|
||||
if (typeof path === "string") { dir = path.asFileHandle(); }
|
||||
return dir.read().then(d => {
|
||||
if (d.error) { return reject(d.error); }
|
||||
if (!dir.isRoot()) {
|
||||
const p = dir.parent();
|
||||
p.filename = "[..]";
|
||||
p.type = "dir";
|
||||
d.result.unshift(p);
|
||||
}
|
||||
this.currdir = dir;
|
||||
($(this.navinput)).val(dir.path);
|
||||
return resolve(d.result);
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
});
|
||||
|
||||
this.vfs_event_flag = true;
|
||||
this.view.set("ondragndrop", e => {
|
||||
if (!e) { return; }
|
||||
const src = e.data.from.get("data");
|
||||
const des = e.data.to.get("data");
|
||||
if (des.type === "file") { return; }
|
||||
const file = src.path.asFileHandle();
|
||||
// disable the vfs event on
|
||||
// we update it manually
|
||||
this.vfs_event_flag = false;
|
||||
return file.move(`${des.path}/${file.basename}`)
|
||||
.then(() => {
|
||||
if (this.view.get("view") === "icon") {
|
||||
this.view.set("path", this.view.get("path"));
|
||||
} else {
|
||||
this.view.update(file.parent().path);
|
||||
this.view.update(des.path);
|
||||
}
|
||||
//reenable the vfs event
|
||||
return this.vfs_event_flag = true;
|
||||
}).catch(e => {
|
||||
// reenable the vfs event
|
||||
this.vfs_event_flag = true;
|
||||
return this.error(__("Unable to move: {0} -> {1}", src.path, des.path), e);
|
||||
});
|
||||
});
|
||||
|
||||
// application setting
|
||||
if (this.setting.sidebar === undefined) { this.setting.sidebar = true; }
|
||||
if (this.setting.nav === undefined) { this.setting.nav = true; }
|
||||
if (this.setting.showhidden === undefined) { this.setting.showhidden = false; }
|
||||
this.applyAllSetting();
|
||||
|
||||
// VFS mount point and event
|
||||
const mntpoints = this.systemsetting.VFS.mountpoints;
|
||||
for (let i = 0; i < mntpoints.length; i++) { const el = mntpoints[i]; el.selected = false; }
|
||||
this.favo.set("data", mntpoints);
|
||||
//@favo.set "selected", -1
|
||||
if (this.setting.view) { this.view.set("view", this.setting.view); }
|
||||
this.subscribe("VFS", d => {
|
||||
if (!this.vfs_event_flag) { return; }
|
||||
if (["read", "publish", "download"].includes(d.data.m)) { return; }
|
||||
if ((d.data.file.hash() === this.currdir.hash()) ||
|
||||
(d.data.file.parent().hash() === this.currdir.hash())) {
|
||||
return this.view.set("path", this.currdir);
|
||||
}
|
||||
});
|
||||
|
||||
// bind keyboard shortcut
|
||||
this.bindKey("CTRL-F", () => this.actionFile(`${this.name}-mkf`));
|
||||
this.bindKey("CTRL-D", () => this.actionFile(`${this.name}-mkdir`));
|
||||
this.bindKey("CTRL-U", () => this.actionFile(`${this.name}-upload`));
|
||||
this.bindKey("CTRL-S", () => this.actionFile(`${this.name}-share`));
|
||||
this.bindKey("CTRL-I", () => this.actionFile(`${this.name}-info`));
|
||||
|
||||
this.bindKey("CTRL-R", () => this.actionEdit(`${this.name}-mv`));
|
||||
this.bindKey("CTRL-M", () => this.actionEdit(`${this.name}-rm`));
|
||||
this.bindKey("CTRL-X", () => this.actionEdit(`${this.name}-cut`));
|
||||
this.bindKey("CTRL-C", () => this.actionEdit(`${this.name}-copy`));
|
||||
this.bindKey("CTRL-P", () => this.actionEdit(`${this.name}-paste`));
|
||||
|
||||
(this.find("btgrid")).set("onbtclick", e => {
|
||||
this.view.set('view', "icon");
|
||||
return this.viewType.icon = true;
|
||||
});
|
||||
|
||||
(this.find("btlist")).set("onbtclick", e => {
|
||||
this.view.set('view', "list");
|
||||
return this.viewType.list = true;
|
||||
});
|
||||
return this.view.set("path", this.currdir);
|
||||
}
|
||||
|
||||
applySetting(k) {
|
||||
// view setting
|
||||
switch (k) {
|
||||
case "showhidden": return this.view.set("showhidden", this.setting.showhidden);
|
||||
case "nav": return this.toggleNav(this.setting.nav);
|
||||
case "sidebar": return this.toggleSidebar(this.setting.sidebar);
|
||||
}
|
||||
}
|
||||
|
||||
mnFile() {
|
||||
//console.log file
|
||||
const arr = {
|
||||
text: "__(File)",
|
||||
child: [
|
||||
{ text: "__(New file)", dataid: `${this.name}-mkf`, shortcut: 'C-F' },
|
||||
{ text: "__(New folder)", dataid: `${this.name}-mkdir`, shortcut: 'C-D' },
|
||||
{ text: "__(Upload)", dataid: `${this.name}-upload`, shortcut: 'C-U' },
|
||||
{ text: "__(Download)", dataid: `${this.name}-download` },
|
||||
{ text: "__(Share file)", dataid: `${this.name}-share`, shortcut: 'C-S' },
|
||||
{ text: "__(Properties)", dataid: `${this.name}-info`, shortcut: 'C-I' }
|
||||
], onchildselect: e => this.actionFile(e.data.item.get("data").dataid)
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
mnEdit() {
|
||||
return {
|
||||
text: "__(Edit)",
|
||||
child: [
|
||||
{ text: "__(Rename)", dataid: `${this.name}-mv`, shortcut: 'C-R' },
|
||||
{ text: "__(Delete)", dataid: `${this.name}-rm`, shortcut: 'C-M' },
|
||||
{ text: "__(Cut)", dataid: `${this.name}-cut`, shortcut: 'C-X' },
|
||||
{ text: "__(Copy)", dataid: `${this.name}-copy`, shortcut: 'C-C' },
|
||||
{ text: "__(Paste)", dataid: `${this.name}-paste`, shortcut: 'C-P' }
|
||||
], onchildselect: e => this.actionEdit(e.data.item.get("data").dataid)
|
||||
};
|
||||
}
|
||||
menu() {
|
||||
|
||||
const menu = [
|
||||
this.mnFile(),
|
||||
this.mnEdit(),
|
||||
{
|
||||
text: "__(View)",
|
||||
child: [
|
||||
{ text: "__(Refresh)", dataid: `${this.name}-refresh` },
|
||||
{ text: "__(Sidebar)", switch: true, checked: this.setting.sidebar, dataid: `${this.name}-side` },
|
||||
{ text: "__(Navigation bar)", switch: true, checked: this.setting.nav, dataid: `${this.name}-nav` },
|
||||
{ text: "__(Hidden files)", switch: true, checked: this.setting.showhidden, dataid: `${this.name}-hidden` },
|
||||
{ text: "__(Type)", child: [
|
||||
{ text: "__(Icon view)", radio: true, checked: this.viewType.icon, dataid: `${this.name}-icon`, type: 'icon' },
|
||||
{ text: "__(List view)", radio:true, checked: this.viewType.list, dataid: `${this.name}-list`, type: 'list' },
|
||||
{ text: "__(Tree view)", radio:true, checked: this.viewType.tree, dataid: `${this.name}-tree`, type: 'tree' }
|
||||
], onchildselect: e => {
|
||||
const {
|
||||
type
|
||||
} = e.data.item.get("data");
|
||||
this.view.set('view', type);
|
||||
return this.viewType[type] = true;
|
||||
}
|
||||
},
|
||||
], onchildselect: e => this.actionView(e)
|
||||
},
|
||||
];
|
||||
return menu;
|
||||
}
|
||||
|
||||
toggleSidebar(b) {
|
||||
if (b) { ($(this.favo)).show(); } else { ($(this.favo)).hide(); }
|
||||
return this.trigger("resize");
|
||||
}
|
||||
|
||||
toggleNav(b) {
|
||||
if (b) { ($(this.navbar)).show(); } else { ($(this.navbar)).hide(); }
|
||||
return this.trigger("resize");
|
||||
}
|
||||
|
||||
actionView(e) {
|
||||
const data = e.data.item.get("data");
|
||||
switch (data.dataid) {
|
||||
case `${this.name}-hidden`:
|
||||
//@.view.set "showhidden", e.item.data.checked
|
||||
return this.registry("showhidden", data.checked);
|
||||
//@.setting.showhidden = e.item.data.checked
|
||||
case `${this.name}-refresh`:
|
||||
return this.chdir(null);
|
||||
case `${this.name}-side`:
|
||||
return this.registry("sidebar", data.checked);
|
||||
//@setting.sidebar = e.item.data.checked
|
||||
//@toggleSidebar e.item.data.checked
|
||||
case `${this.name}-nav`:
|
||||
return this.registry("nav", data.checked);
|
||||
}
|
||||
}
|
||||
//@setting.nav = e.item.data.checked
|
||||
//@toggleNav e.item.data.checked
|
||||
|
||||
actionEdit(e) {
|
||||
const file = this.view.get("selectedFile");
|
||||
switch (e) {
|
||||
case `${this.name}-mv`:
|
||||
if (!file) { return; }
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: "__(Rename)",
|
||||
label: "__(File name)",
|
||||
value: file.filename
|
||||
})
|
||||
.then(d => {
|
||||
if (d === file.filename) { return; }
|
||||
return file.path.asFileHandle().move(`${this.currdir.path}/${d}`)
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to rename: {0}", file.path), e);
|
||||
});
|
||||
});
|
||||
|
||||
case `${this.name}-rm`:
|
||||
if (!file) { return; }
|
||||
return this.openDialog("YesNoDialog", {
|
||||
title: "__(Delete)",
|
||||
iconclass: "fa fa-question-circle",
|
||||
text: __("Do you really want to delete: {0}?", file.filename)
|
||||
})
|
||||
.then(d => {
|
||||
if (!d) { return; }
|
||||
return file.path.asFileHandle().remove()
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to delete: {0}", file.path), e);
|
||||
});
|
||||
});
|
||||
|
||||
case `${this.name}-cut`:
|
||||
if (!file) { return; }
|
||||
this.clipboard = {
|
||||
cut: true,
|
||||
file: file.path.asFileHandle()
|
||||
};
|
||||
return this.notify(__("File {0} cut", file.filename));
|
||||
|
||||
case `${this.name}-copy`:
|
||||
if (!file && (file.type !== "dir")) { return; }
|
||||
this.clipboard = {
|
||||
cut: false,
|
||||
file: file.path.asFileHandle()
|
||||
};
|
||||
return this.notify(__("File {0} copied", file.filename));
|
||||
|
||||
case `${this.name}-paste`:
|
||||
if (!this.clipboard) { return; }
|
||||
if (this.clipboard.cut) {
|
||||
return this.clipboard.file.move(`${this.currdir.path}/${this.clipboard.file.basename}`)
|
||||
.then(r => {
|
||||
return this.clipboard = undefined;
|
||||
}).catch(e => {
|
||||
return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e);
|
||||
});
|
||||
} else {
|
||||
return this.clipboard.file.read("binary")
|
||||
.then(d => {
|
||||
const blob = new Blob([d], { type: this.clipboard.file.info.mime });
|
||||
const fp = `${this.currdir.path}/${this.clipboard.file.basename}`.asFileHandle();
|
||||
fp.cache = blob;
|
||||
return fp.write(this.clipboard.file.info.mime)
|
||||
.then(r => {
|
||||
return this.clipboard = undefined;
|
||||
}).catch(e => {
|
||||
return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e);
|
||||
});
|
||||
}).catch(e => {
|
||||
return this.error(__("Fail to read: {0}", this.clipboard.file.path), e);
|
||||
});
|
||||
}
|
||||
default:
|
||||
return this._api.handle.setting();
|
||||
}
|
||||
}
|
||||
|
||||
actionFile(e) {
|
||||
const file = this.view.get("selectedFile");
|
||||
switch (e) {
|
||||
case `${this.name}-mkdir`:
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: "__(New folder)",
|
||||
label: "__(Folder name)"
|
||||
})
|
||||
.then(d => {
|
||||
return this.currdir.mk(d)
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to create: {0}", d), e);
|
||||
});
|
||||
});
|
||||
|
||||
case `${this.name}-mkf`:
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: "__(New file)",
|
||||
label: "__(File name)"
|
||||
})
|
||||
.then(d => {
|
||||
const fp = `${this.currdir.path}/${d}`.asFileHandle();
|
||||
return fp.write("text/plain")
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to create: {0}", fp.path));
|
||||
});
|
||||
});
|
||||
|
||||
case `${this.name}-info`:
|
||||
if (!file) { return; }
|
||||
return this.openDialog("InfoDialog", file);
|
||||
|
||||
case `${this.name}-upload`:
|
||||
return this.currdir.upload()
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to upload: {0}", e.toString()), e);
|
||||
});
|
||||
|
||||
case `${this.name}-share`:
|
||||
if (!file || (file.type !== "file")) { return; }
|
||||
return file.path.asFileHandle().publish()
|
||||
.then(r => {
|
||||
return this.notify(__("Shared url: {0}", r.result));
|
||||
}).catch(e => {
|
||||
return this.error(__("Fail to publish: {0}", file.path), e);
|
||||
});
|
||||
|
||||
case `${this.name}-download`:
|
||||
if (file.type !== "file") { return; }
|
||||
return file.path.asFileHandle().download()
|
||||
.catch(e => {
|
||||
return this.error(__("Fail to download: {0}", file.path), e);
|
||||
});
|
||||
default:
|
||||
return console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.OS.register("Files", Files);
|
699
src/packages/Files/main.ts
Normal file
699
src/packages/Files/main.ts
Normal file
@ -0,0 +1,699 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
export namespace application {
|
||||
|
||||
interface FilesClipboardType {
|
||||
cut: boolean;
|
||||
file: API.VFS.BaseFileHandle;
|
||||
}
|
||||
interface FilesViewType {
|
||||
icon: boolean;
|
||||
list: boolean;
|
||||
tree: boolean;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @export
|
||||
* @class Files
|
||||
* @extends {BaseApplication}
|
||||
*/
|
||||
export class Files extends BaseApplication {
|
||||
private view: GUI.tag.FileViewTag;
|
||||
private navinput: HTMLInputElement;
|
||||
private navbar: GUI.tag.HBoxTag;
|
||||
private currdir: API.VFS.BaseFileHandle;
|
||||
private favo: GUI.tag.ListViewTag;
|
||||
private clipboard: FilesClipboardType;
|
||||
private viewType: FilesViewType;
|
||||
private vfs_event_flag: boolean;
|
||||
constructor(args: AppArgumentsType[]) {
|
||||
super("Files", args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns
|
||||
* @memberof Files
|
||||
*/
|
||||
main(): void {
|
||||
this.view = this.find("fileview") as GUI.tag.FileViewTag;
|
||||
this.navinput = this.find("navinput") as HTMLInputElement;
|
||||
this.navbar = this.find("nav-bar") as GUI.tag.HBoxTag;
|
||||
if (this.args && this.args.length > 0) {
|
||||
this.currdir = this.args[0].path.asFileHandle();
|
||||
} else {
|
||||
this.currdir = "home://".asFileHandle();
|
||||
}
|
||||
this.favo = this.find("favouri") as GUI.tag.ListViewTag;
|
||||
this.clipboard = undefined;
|
||||
this.viewType = this._api.switcher("icon", "list", "tree");
|
||||
this.viewType.list = true;
|
||||
|
||||
this.view.contextmenuHandle = (e, m) => {
|
||||
const file = this.view.selectedFile;
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
const apps = [];
|
||||
if (file.type === "dir") {
|
||||
file.mime = "dir";
|
||||
}
|
||||
|
||||
for (let v of this._gui.appsByMime(file.mime)) {
|
||||
apps.push({
|
||||
text: v.text,
|
||||
app: v.app,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass,
|
||||
});
|
||||
}
|
||||
|
||||
m.items = [
|
||||
{
|
||||
text: "__(Open with)",
|
||||
nodes: apps,
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) => {
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
const it = e.data.item.data;
|
||||
return this._gui.launch(it.app, [file]);
|
||||
},
|
||||
},
|
||||
this.mnFile(),
|
||||
this.mnEdit(),
|
||||
];
|
||||
m.show(e);
|
||||
};
|
||||
|
||||
this.view.onfileopen = (e) => {
|
||||
if (!e.data) {
|
||||
return;
|
||||
}
|
||||
if (e.data.type === "dir") {
|
||||
return;
|
||||
}
|
||||
return this._gui.openWith(e.data);
|
||||
};
|
||||
|
||||
this.favo.onlistselect = (e) => {
|
||||
return this.view.path = e.data.item.data.path;
|
||||
};
|
||||
|
||||
(this.find("btback") as GUI.tag.ButtonTag).onbtclick = () => {
|
||||
if (this.currdir.isRoot()) {
|
||||
return;
|
||||
}
|
||||
const p = this.currdir.parent();
|
||||
this.favo.selected = -1;
|
||||
return this.view.path = p.path;
|
||||
};
|
||||
|
||||
$(this.navinput).keyup((e) => {
|
||||
if (e.keyCode === 13) {
|
||||
return this.view.path = $(this.navinput).val() as string;
|
||||
}
|
||||
}); //enter
|
||||
|
||||
this.view.fetch = (path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dir = path.asFileHandle();
|
||||
dir
|
||||
.read()
|
||||
.then((d) => {
|
||||
if (d.error) {
|
||||
return reject(d.error);
|
||||
}
|
||||
if (!dir.isRoot()) {
|
||||
const p = dir.parent();
|
||||
p.filename = "[..]";
|
||||
p.type = "dir";
|
||||
d.result.unshift(p);
|
||||
}
|
||||
this.currdir = dir;
|
||||
$(this.navinput).val(dir.path);
|
||||
return resolve(d.result);
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
});
|
||||
};
|
||||
|
||||
this.vfs_event_flag = true;
|
||||
this.view.ondragndrop = (e) => {
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
const src = e.data.from.data;
|
||||
const des = e.data.to.data;
|
||||
if (des.type === "file") {
|
||||
return;
|
||||
}
|
||||
const file = src.path.asFileHandle();
|
||||
// disable the vfs event on
|
||||
// we update it manually
|
||||
this.vfs_event_flag = false;
|
||||
return file
|
||||
.move(`${des.path}/${file.basename}`)
|
||||
.then(() => {
|
||||
if (this.view.view === "icon") {
|
||||
this.view.path = this.view.path;
|
||||
} else {
|
||||
this.view.update(file.parent().path);
|
||||
this.view.update(des.path);
|
||||
}
|
||||
//reenable the vfs event
|
||||
return (this.vfs_event_flag = true);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// reenable the vfs event
|
||||
this.vfs_event_flag = true;
|
||||
return this.error(
|
||||
__(
|
||||
"Unable to move: {0} -> {1}",
|
||||
src.path,
|
||||
des.path
|
||||
),
|
||||
e
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// application setting
|
||||
if (this.setting.sidebar === undefined) {
|
||||
this.setting.sidebar = true;
|
||||
}
|
||||
if (this.setting.nav === undefined) {
|
||||
this.setting.nav = true;
|
||||
}
|
||||
if (this.setting.showhidden === undefined) {
|
||||
this.setting.showhidden = false;
|
||||
}
|
||||
this.applyAllSetting();
|
||||
|
||||
// VFS mount point and event
|
||||
const mntpoints = [];
|
||||
for(let v of this.systemsetting.VFS.mountpoints)
|
||||
{
|
||||
mntpoints.push({
|
||||
text: v.text,
|
||||
path: v.path,
|
||||
selected: false
|
||||
});
|
||||
}
|
||||
this.favo.data = mntpoints;
|
||||
//@favo.set "selected", -1
|
||||
if (this.setting.view) {
|
||||
this.view.view = this.setting.view;
|
||||
}
|
||||
this.subscribe("VFS", (d) => {
|
||||
if (!this.vfs_event_flag) {
|
||||
return;
|
||||
}
|
||||
if (["read", "publish", "download"].includes(d.data.m)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
d.data.file.hash() === this.currdir.hash() ||
|
||||
d.data.file.parent().hash() === this.currdir.hash()
|
||||
) {
|
||||
return this.view.path = this.currdir.path;
|
||||
}
|
||||
});
|
||||
|
||||
// bind keyboard shortcut
|
||||
this.bindKey("CTRL-F", () =>
|
||||
this.actionFile(`${this.name}-mkf`)
|
||||
);
|
||||
this.bindKey("CTRL-D", () =>
|
||||
this.actionFile(`${this.name}-mkdir`)
|
||||
);
|
||||
this.bindKey("CTRL-U", () =>
|
||||
this.actionFile(`${this.name}-upload`)
|
||||
);
|
||||
this.bindKey("CTRL-S", () =>
|
||||
this.actionFile(`${this.name}-share`)
|
||||
);
|
||||
this.bindKey("CTRL-I", () =>
|
||||
this.actionFile(`${this.name}-info`)
|
||||
);
|
||||
|
||||
this.bindKey("CTRL-R", () =>
|
||||
this.actionEdit(`${this.name}-mv`)
|
||||
);
|
||||
this.bindKey("CTRL-M", () =>
|
||||
this.actionEdit(`${this.name}-rm`)
|
||||
);
|
||||
this.bindKey("CTRL-X", () =>
|
||||
this.actionEdit(`${this.name}-cut`)
|
||||
);
|
||||
this.bindKey("CTRL-C", () =>
|
||||
this.actionEdit(`${this.name}-copy`)
|
||||
);
|
||||
this.bindKey("CTRL-P", () =>
|
||||
this.actionEdit(`${this.name}-paste`)
|
||||
);
|
||||
|
||||
(this.find("btgrid") as GUI.tag.ButtonTag).onbtclick = (e) => {
|
||||
this.view.view = "icon";
|
||||
this.viewType.icon = true;
|
||||
};
|
||||
|
||||
(this.find("btlist") as GUI.tag.ButtonTag).onbtclick = (e) => {
|
||||
this.view.view = "list";
|
||||
this.viewType.list = true;
|
||||
};
|
||||
this.view.path = this.currdir.path;
|
||||
}
|
||||
|
||||
protected applySetting(k: string): void{
|
||||
// view setting
|
||||
switch (k) {
|
||||
case "showhidden":
|
||||
return this.view.showhidden = this.setting.showhidden;
|
||||
case "nav":
|
||||
return this.toggleNav(this.setting.nav);
|
||||
case "sidebar":
|
||||
return this.toggleSidebar(this.setting.sidebar);
|
||||
}
|
||||
}
|
||||
|
||||
private mnFile(): GUI.BasicItemType{
|
||||
//console.log file
|
||||
const arr: GUI.BasicItemType = {
|
||||
text: "__(File)",
|
||||
nodes: [
|
||||
{
|
||||
text: "__(New file)",
|
||||
dataid: `${this.name}-mkf`,
|
||||
shortcut: "C-F",
|
||||
},
|
||||
{
|
||||
text: "__(New folder)",
|
||||
dataid: `${this.name}-mkdir`,
|
||||
shortcut: "C-D",
|
||||
},
|
||||
{
|
||||
text: "__(Upload)",
|
||||
dataid: `${this.name}-upload`,
|
||||
shortcut: "C-U",
|
||||
},
|
||||
{
|
||||
text: "__(Download)",
|
||||
dataid: `${this.name}-download`,
|
||||
},
|
||||
{
|
||||
text: "__(Share file)",
|
||||
dataid: `${this.name}-share`,
|
||||
shortcut: "C-S",
|
||||
},
|
||||
{
|
||||
text: "__(Properties)",
|
||||
dataid: `${this.name}-info`,
|
||||
shortcut: "C-I",
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) =>
|
||||
this.actionFile(e.data.item.data.dataid),
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
private mnEdit(): GUI.BasicItemType{
|
||||
return {
|
||||
text: "__(Edit)",
|
||||
nodes: [
|
||||
{
|
||||
text: "__(Rename)",
|
||||
dataid: `${this.name}-mv`,
|
||||
shortcut: "C-R",
|
||||
},
|
||||
{
|
||||
text: "__(Delete)",
|
||||
dataid: `${this.name}-rm`,
|
||||
shortcut: "C-M",
|
||||
},
|
||||
{
|
||||
text: "__(Cut)",
|
||||
dataid: `${this.name}-cut`,
|
||||
shortcut: "C-X",
|
||||
},
|
||||
{
|
||||
text: "__(Copy)",
|
||||
dataid: `${this.name}-copy`,
|
||||
shortcut: "C-C",
|
||||
},
|
||||
{
|
||||
text: "__(Paste)",
|
||||
dataid: `${this.name}-paste`,
|
||||
shortcut: "C-P",
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) =>
|
||||
this.actionEdit(e.data.item.data.dataid),
|
||||
};
|
||||
}
|
||||
protected menu(): GUI.BasicItemType[]{
|
||||
const menu = [
|
||||
this.mnFile(),
|
||||
this.mnEdit(),
|
||||
{
|
||||
text: "__(View)",
|
||||
nodes: [
|
||||
{
|
||||
text: "__(Refresh)",
|
||||
dataid: `${this.name}-refresh`,
|
||||
},
|
||||
{
|
||||
text: "__(Sidebar)",
|
||||
switch: true,
|
||||
checked: this.setting.sidebar,
|
||||
dataid: `${this.name}-side`,
|
||||
},
|
||||
{
|
||||
text: "__(Navigation bar)",
|
||||
switch: true,
|
||||
checked: this.setting.nav,
|
||||
dataid: `${this.name}-nav`,
|
||||
},
|
||||
{
|
||||
text: "__(Hidden files)",
|
||||
switch: true,
|
||||
checked: this.setting.showhidden,
|
||||
dataid: `${this.name}-hidden`,
|
||||
},
|
||||
{
|
||||
text: "__(Type)",
|
||||
nodes: [
|
||||
{
|
||||
text: "__(Icon view)",
|
||||
radio: true,
|
||||
checked: this.viewType.icon,
|
||||
dataid: `${this.name}-icon`,
|
||||
type: "icon",
|
||||
},
|
||||
{
|
||||
text: "__(List view)",
|
||||
radio: true,
|
||||
checked: this.viewType.list,
|
||||
dataid: `${this.name}-list`,
|
||||
type: "list",
|
||||
},
|
||||
{
|
||||
text: "__(Tree view)",
|
||||
radio: true,
|
||||
checked: this.viewType.tree,
|
||||
dataid: `${this.name}-tree`,
|
||||
type: "tree",
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) => {
|
||||
const { type } = e.data.item.data;
|
||||
this.view.view = type;
|
||||
return (this.viewType[type] = true);
|
||||
},
|
||||
},
|
||||
],
|
||||
onchildselect: (e: GUI.TagEventType<GUI.tag.MenuEventData>) => this.actionView(e),
|
||||
},
|
||||
];
|
||||
return menu;
|
||||
}
|
||||
|
||||
private toggleSidebar(b: boolean): void {
|
||||
if (b) {
|
||||
$(this.favo).show();
|
||||
} else {
|
||||
$(this.favo).hide();
|
||||
}
|
||||
return this.trigger("resize");
|
||||
}
|
||||
|
||||
private toggleNav(b: boolean): void {
|
||||
if (b) {
|
||||
$(this.navbar).show();
|
||||
} else {
|
||||
$(this.navbar).hide();
|
||||
}
|
||||
return this.trigger("resize");
|
||||
}
|
||||
|
||||
private actionView(e: GUI.TagEventType<GUI.tag.MenuEventData>): void{
|
||||
const data = e.data.item.data;
|
||||
switch (data.dataid) {
|
||||
case `${this.name}-hidden`:
|
||||
//@.view.set "showhidden", e.item.data.checked
|
||||
return this.registry("showhidden", data.checked);
|
||||
//@.setting.showhidden = e.item.data.checked
|
||||
case `${this.name}-refresh`:
|
||||
this.view.path = this.currdir.path;
|
||||
return;
|
||||
case `${this.name}-side`:
|
||||
return this.registry("sidebar", data.checked);
|
||||
//@setting.sidebar = e.item.data.checked
|
||||
//@toggleSidebar e.item.data.checked
|
||||
case `${this.name}-nav`:
|
||||
return this.registry("nav", data.checked);
|
||||
}
|
||||
}
|
||||
//@setting.nav = e.item.data.checked
|
||||
//@toggleNav e.item.data.checked
|
||||
|
||||
private actionEdit(e: string): void{
|
||||
const file = this.view.selectedFile;
|
||||
switch (e) {
|
||||
case `${this.name}-mv`:
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
this.openDialog("PromptDialog", {
|
||||
title: "__(Rename)",
|
||||
label: "__(File name)",
|
||||
value: file.filename,
|
||||
}).then(async (d) => {
|
||||
if (d === file.filename) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
return file.path
|
||||
.asFileHandle()
|
||||
.move(`${this.currdir.path}/${d}`);
|
||||
}
|
||||
catch (e) {
|
||||
return this.error(__("Fail to rename: {0}", file.path), e);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case `${this.name}-rm`:
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
this.openDialog("YesNoDialog", {
|
||||
title: "__(Delete)",
|
||||
iconclass: "fa fa-question-circle",
|
||||
text: __(
|
||||
"Do you really want to delete: {0}?",
|
||||
file.filename
|
||||
),
|
||||
}).then(async (d) => {
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
return file.path
|
||||
.asFileHandle()
|
||||
.remove();
|
||||
}
|
||||
catch (e) {
|
||||
return this.error(__("Fail to delete: {0}", file.path), e);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case `${this.name}-cut`:
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
this.clipboard = {
|
||||
cut: true,
|
||||
file: file.path.asFileHandle(),
|
||||
};
|
||||
return this.notify(__("File {0} cut", file.filename));
|
||||
|
||||
case `${this.name}-copy`:
|
||||
if (!file && file.type !== "dir") {
|
||||
return;
|
||||
}
|
||||
this.clipboard = {
|
||||
cut: false,
|
||||
file: file.path.asFileHandle(),
|
||||
};
|
||||
return this.notify(
|
||||
__("File {0} copied", file.filename)
|
||||
);
|
||||
|
||||
case `${this.name}-paste`:
|
||||
if (!this.clipboard) {
|
||||
return;
|
||||
}
|
||||
if (this.clipboard.cut) {
|
||||
this.clipboard.file
|
||||
.move(
|
||||
`${this.currdir.path}/${this.clipboard.file.basename}`
|
||||
)
|
||||
.then((r) => {
|
||||
return (this.clipboard = undefined);
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__(
|
||||
"Fail to paste: {0}",
|
||||
this.clipboard.file.path
|
||||
),
|
||||
e
|
||||
);
|
||||
});
|
||||
} else {
|
||||
this.clipboard.file
|
||||
.read("binary")
|
||||
.then(async (d) => {
|
||||
const blob = new Blob([d], {
|
||||
type: this.clipboard.file.info.mime,
|
||||
});
|
||||
const fp = `${this.currdir.path}/${this.clipboard.file.basename}`.asFileHandle();
|
||||
fp.cache = blob;
|
||||
try {
|
||||
const r = await fp.write(this.clipboard.file.info.mime);
|
||||
return (this.clipboard = undefined);
|
||||
}
|
||||
catch (e) {
|
||||
return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__(
|
||||
"Fail to read: {0}",
|
||||
this.clipboard.file.path
|
||||
),
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this._api.handle.setting();
|
||||
}
|
||||
}
|
||||
|
||||
private actionFile(e: string): void{
|
||||
const file = this.view.selectedFile;
|
||||
switch (e) {
|
||||
case `${this.name}-mkdir`:
|
||||
this.openDialog("PromptDialog", {
|
||||
title: "__(New folder)",
|
||||
label: "__(Folder name)",
|
||||
}).then(async (d) => {
|
||||
try {
|
||||
return this.currdir.mk(d);
|
||||
}
|
||||
catch (e) {
|
||||
return this.error(__("Fail to create: {0}", d), e);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case `${this.name}-mkf`:
|
||||
this.openDialog("PromptDialog", {
|
||||
title: "__(New file)",
|
||||
label: "__(File name)",
|
||||
}).then(async (d) => {
|
||||
const fp = `${this.currdir.path}/${d}`.asFileHandle();
|
||||
try {
|
||||
return fp.write("text/plain");
|
||||
}
|
||||
catch (e) {
|
||||
return this.error(__("Fail to create: {0}", fp.path));
|
||||
}
|
||||
});
|
||||
break;
|
||||
case `${this.name}-info`:
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
this.openDialog("InfoDialog", file);
|
||||
break;
|
||||
|
||||
case `${this.name}-upload`:
|
||||
this.currdir.upload().catch((e) => {
|
||||
return this.error(
|
||||
__("Fail to upload: {0}", e.toString()),
|
||||
e
|
||||
);
|
||||
});
|
||||
break;
|
||||
|
||||
case `${this.name}-share`:
|
||||
if (!file || file.type !== "file") {
|
||||
return;
|
||||
}
|
||||
file.path
|
||||
.asFileHandle()
|
||||
.publish()
|
||||
.then((r) => {
|
||||
return this.notify(
|
||||
__("Shared url: {0}", r.result)
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__("Fail to publish: {0}", file.path),
|
||||
e
|
||||
);
|
||||
});
|
||||
break;
|
||||
case `${this.name}-download`:
|
||||
if (file.type !== "file") {
|
||||
return;
|
||||
}
|
||||
file.path
|
||||
.asFileHandle()
|
||||
.download()
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__("Fail to download: {0}", file.path),
|
||||
e
|
||||
);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
module_files = dialog.js main.js
|
||||
module_files = main.js dialog.js
|
||||
|
||||
libfiles =
|
||||
|
||||
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class RepositoryDialog extends this.OS.GUI.subwindows.SelectionDialog {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
main() {
|
||||
super.main();
|
||||
this.list = this.find("list");
|
||||
$((this.find("btnOk"))).hide();
|
||||
return this.list.set("buttons", [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: () => {
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: __("Add repository"),
|
||||
label: __("Format : [name] url")
|
||||
}).then(e => {
|
||||
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
|
||||
if (!m || (m.length !== 3)) {
|
||||
return this.error(__("Wrong format: it should be [name] url"));
|
||||
}
|
||||
const repo = {
|
||||
url: m[2],
|
||||
text: m[1]
|
||||
};
|
||||
this.systemsetting.system.repositories.push(repo);
|
||||
return this.list.push(repo);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: () => {
|
||||
const el = this.list.get("selectedItem");
|
||||
if (!el) { return; }
|
||||
const selidx = $(el).index();
|
||||
if (!(selidx >= 0)) { return; }
|
||||
this.systemsetting.system.repositories.splice(selidx, selidx);
|
||||
return this.list.remove(el);
|
||||
}
|
||||
},
|
||||
{
|
||||
iconclass: "fa fa-pencil",
|
||||
onbtclick: () => this.editRepo()
|
||||
}
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
editRepo() {
|
||||
const el = this.list.get("selectedItem");
|
||||
if (!el) { return; }
|
||||
const selidx = $(el).index();
|
||||
if (!(selidx >= 0)) { return; }
|
||||
const data = el.get("data");
|
||||
const sel = this.systemsetting.system.repositories[selidx];
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: __("Edit repository"),
|
||||
label: __("Format : [name] url"),
|
||||
value: `[${data.text}] ${data.url}`
|
||||
}).then(e => {
|
||||
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
|
||||
if (!m || (m.length !== 3)) {
|
||||
return this.error(__("Wrong format: it should be [name] url"));
|
||||
}
|
||||
data.text = m[1];
|
||||
data.url = m[2];
|
||||
this.list.update();
|
||||
return this.list.unselect();
|
||||
});
|
||||
}
|
||||
|
||||
onexit(e) {
|
||||
this.parent.refreshRepoList();
|
||||
return super.onexit(e);
|
||||
}
|
||||
}
|
108
src/packages/MarketPlace/dialog.ts
Normal file
108
src/packages/MarketPlace/dialog.ts
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
const App = OS.application.MarketPlace;
|
||||
export type MarketPlaceRepoDialog = typeof RepositoryDialog;
|
||||
class RepositoryDialog extends OS.GUI.dialogs.SelectionDialog {
|
||||
private list: GUI.tag.ListViewTag;
|
||||
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
main() {
|
||||
super.main();
|
||||
this.list = this.find("list") as GUI.tag.ListViewTag;
|
||||
$((this.find("btnOk"))).hide();
|
||||
return this.list.buttons = [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: () => {
|
||||
return this.openDialog("PromptDialog", {
|
||||
title: __("Add repository"),
|
||||
label: __("Format : [name] url")
|
||||
}).then(e => {
|
||||
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
|
||||
if (!m || (m.length !== 3)) {
|
||||
return this.error(__("Wrong format: it should be [name] url"));
|
||||
}
|
||||
const repo = {
|
||||
url: m[2],
|
||||
text: m[1]
|
||||
};
|
||||
this.systemsetting.system.repositories.push(repo);
|
||||
return this.list.push(repo);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: () => {
|
||||
const el = this.list.selectedItem;
|
||||
if (!el) { return; }
|
||||
const selidx = $(el).index();
|
||||
if (!(selidx >= 0)) { return; }
|
||||
this.systemsetting.system.repositories.splice(selidx, selidx);
|
||||
return this.list.delete(el);
|
||||
}
|
||||
},
|
||||
{
|
||||
iconclass: "fa fa-pencil",
|
||||
onbtclick: () => this.editRepo()
|
||||
}
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
private editRepo(): void{
|
||||
const el = this.list.selectedItem;
|
||||
if (!el) { return; }
|
||||
const selidx = $(el).index();
|
||||
if (!(selidx >= 0)) { return; }
|
||||
const data = el.data;
|
||||
const sel = this.systemsetting.system.repositories[selidx];
|
||||
this.openDialog("PromptDialog", {
|
||||
title: __("Edit repository"),
|
||||
label: __("Format : [name] url"),
|
||||
value: `[${data.text}] ${data.url}`
|
||||
}).then(e => {
|
||||
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
|
||||
if (!m || (m.length !== 3)) {
|
||||
return this.error(__("Wrong format: it should be [name] url"));
|
||||
}
|
||||
data.text = m[1];
|
||||
data.url = m[2];
|
||||
this.list.update(undefined);
|
||||
return this.list.unselect();
|
||||
});
|
||||
}
|
||||
|
||||
protected onexit(e: BaseEvent): void{
|
||||
(this.parent as OS.application.MarketPlace).refreshRepoList();
|
||||
return super.onexit(e);
|
||||
}
|
||||
}
|
||||
|
||||
App.RepoDialog = RepositoryDialog;
|
||||
}
|
@ -9,7 +9,7 @@ afx-app-window[data-id="marketplace-win"] afx-vbox[data-id='container'] {
|
||||
afx-app-window[data-id="marketplace-win"] afx-vbox[data-id='container'] afx-hbox {
|
||||
padding-left: 10px;
|
||||
}
|
||||
afx-app-window[data-id="marketplace-win"] div[data-id='appname'] {
|
||||
afx-app-window[data-id="marketplace-win"] afx-label[data-id='appname'] i.label-text{
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
|
@ -1,433 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class MarketPlace extends this.OS.GUI.BaseApplication {
|
||||
constructor(args) {
|
||||
super("MarketPlace", args);
|
||||
}
|
||||
|
||||
main() {
|
||||
this.installdir = this.systemsetting.system.pkgpaths.user;
|
||||
// test repository
|
||||
this.apps_meta = [];
|
||||
this.repo = this.find("repo");
|
||||
this.repo.set("onlistselect", e => {
|
||||
const data = e.data.item.get("data");
|
||||
if (!data) { return; }
|
||||
return this.fetchApps(data);
|
||||
});
|
||||
|
||||
this.refreshRepoList();
|
||||
|
||||
this.applist = this.find("applist");
|
||||
this.applist.set("onlistselect", e => {
|
||||
const data = e.data.item.get("data");
|
||||
return this.appDetail(data);
|
||||
});
|
||||
|
||||
this.container = this.find("container");
|
||||
this.appname = this.find("appname");
|
||||
this.appdesc = this.find("app-desc");
|
||||
this.appdetail = this.find("app-detail");
|
||||
this.btinstall = this.find("bt-install");
|
||||
this.btremove = this.find("bt-remove");
|
||||
this.btexec = this.find("bt-exec");
|
||||
this.searchbox = this.find("searchbox");
|
||||
($(this.container)).css("visibility", "hidden");
|
||||
this.btexec.set("onbtclick", e => {
|
||||
const el = this.applist.get("selectedItem");
|
||||
if (!el) { return; }
|
||||
const app = el.get("data");
|
||||
if (app.pkgname) { return this._gui.launch(app.pkgname); }
|
||||
});
|
||||
|
||||
this.btinstall.set("onbtclick", e => {
|
||||
if (this.btinstall.get("dirty")) {
|
||||
return this.updatePackage()
|
||||
.then(() => this.notify(__("Package updated")))
|
||||
.catch(e => this.error(e.toString(), e));
|
||||
}
|
||||
return this.remoteInstall()
|
||||
.then(n => this.notify(__("Package installed: {0}", n)))
|
||||
.catch(e => this.error(e.toString(), e));
|
||||
});
|
||||
|
||||
this.btremove.set("onbtclick", e => {
|
||||
return this.uninstall()
|
||||
.then(() => this.notify(__("Packaged uninstalled")))
|
||||
.catch(e => this.error(e.toString(), e));
|
||||
});
|
||||
|
||||
this.bindKey("CTRL-R", () => {
|
||||
return this.menuOptionsHandle("repos");
|
||||
});
|
||||
|
||||
return $(this.searchbox).keyup(e => this.search(e));
|
||||
}
|
||||
|
||||
refreshRepoList() {
|
||||
const list = (Array.from(this.systemsetting.system.repositories));
|
||||
list.unshift({
|
||||
text: "Installed"
|
||||
});
|
||||
return this.repo.set("data", list);
|
||||
}
|
||||
|
||||
search(e) {
|
||||
let v;
|
||||
switch (e.which) {
|
||||
case 37:
|
||||
return e.preventDefault();
|
||||
case 38:
|
||||
this.applist.selectPrev();
|
||||
return e.preventDefault();
|
||||
case 39:
|
||||
return e.preventDefault();
|
||||
case 40:
|
||||
this.applist.selectNext();
|
||||
return e.preventDefault();
|
||||
case 13:
|
||||
return e.preventDefault();
|
||||
default:
|
||||
var text = this.searchbox.value;
|
||||
if (text.length === 2) { this.applist.set("data", ((() => {
|
||||
const result1 = [];
|
||||
for (v of Array.from(this.apps_meta)) { result1.push(v);
|
||||
}
|
||||
return result1;
|
||||
})())); }
|
||||
if (text.length < 3) { return; }
|
||||
var result = [];
|
||||
var term = new RegExp(text, 'i');
|
||||
for (v of Array.from(this.apps_meta)) { if (v.text.match(term)) { result.push(v); } }
|
||||
return this.applist.set("data", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fetchApps(data) {
|
||||
let v;
|
||||
if (!data.url) {
|
||||
const pkgcache = this.systemsetting.system.packages;
|
||||
const list = [];
|
||||
for (let k in pkgcache) {
|
||||
v = pkgcache[k];
|
||||
list.push({
|
||||
pkgname: v.pkgname ? v.pkgname : v.app,
|
||||
name: v.name,
|
||||
text: v.name,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass,
|
||||
category: v.category,
|
||||
author: v.info.author,
|
||||
version: v.version,
|
||||
description: `${v.path}/REAME.md`
|
||||
});
|
||||
}
|
||||
this.apps_meta = list;
|
||||
this.applist.set("data", list);
|
||||
return;
|
||||
}
|
||||
|
||||
return this._api.get((data.url + "?_=" + (new Date().getTime())) , "json")
|
||||
.then(d => {
|
||||
for (v of Array.from(d)) {
|
||||
v.text = v.name;
|
||||
v.iconclass = "fa fa-adn";
|
||||
}
|
||||
this.apps_meta = d;
|
||||
return this.applist.set("data", d);
|
||||
}).catch(e => {
|
||||
return this.error(__("Fail to fetch packages list from: {0}", data.url), e);
|
||||
});
|
||||
}
|
||||
|
||||
appDetail(d) {
|
||||
($(this.container)).css("visibility", "visible");
|
||||
( $(this.appname) ).html(d.name);
|
||||
(this.find("vstat")).set("text", "");
|
||||
if (d.description) {
|
||||
d.description.asFileHandle().read().then(text => {
|
||||
const converter = new showdown.Converter();
|
||||
return ($(this.appdesc)).html(converter.makeHtml(text));
|
||||
}).catch(e => {
|
||||
this.notify(__("Unable to read package description"));
|
||||
return ($(this.appdesc)).empty();
|
||||
});
|
||||
} else {
|
||||
($(this.appdesc)).empty();
|
||||
}
|
||||
const pkgcache = this.systemsetting.system.packages;
|
||||
this.btinstall.set("text", "__(Install)");
|
||||
this.btinstall.set("dirty", false);
|
||||
if (pkgcache[d.pkgname]) {
|
||||
let vs = pkgcache[d.pkgname].version;
|
||||
let ovs = d.version;
|
||||
($(this.btinstall)).hide();
|
||||
if (vs && ovs) {
|
||||
vs = vs.__v();
|
||||
ovs = ovs.__v();
|
||||
if (ovs.nt(vs)) {
|
||||
this.btinstall.set("dirty", true);
|
||||
this.btinstall.set("text", "__(Update)");
|
||||
($(this.btinstall)).show();
|
||||
(this.find("vstat")).set("text",
|
||||
__("Your application version is older ({0} < {1})", vs, ovs));
|
||||
}
|
||||
}
|
||||
($(this.btremove)).show();
|
||||
($(this.btexec)).show();
|
||||
} else {
|
||||
($(this.btinstall)).show();
|
||||
($(this.btremove)).hide();
|
||||
($(this.btexec)).hide();
|
||||
}
|
||||
|
||||
($(this.appdetail)).empty();
|
||||
return (() => {
|
||||
const result = [];
|
||||
for (let k in d) {
|
||||
const v = d[k];
|
||||
if ((k !== "name") && (k !== "description") && (k !== "domel")) {
|
||||
result.push(($(this.appdetail)).append(
|
||||
$("<li>")
|
||||
.append(($("<span class= 'info-header'>")).html(k))
|
||||
.append($("<span>").html(v))
|
||||
));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
}
|
||||
|
||||
menu() {
|
||||
return [
|
||||
{
|
||||
text: "__(Options)", child: [
|
||||
{ text: "__(Repositories)", shortcut: "C-R", id: "repos" },
|
||||
{ text: "__(Install from zip)", shortcut: "C-I", id: "install" }
|
||||
] , onchildselect: e => {
|
||||
return this.menuOptionsHandle(e.data.item.get("data").id);
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
menuOptionsHandle(id) {
|
||||
switch (id) {
|
||||
case "repos":
|
||||
return this.openDialog(new RepositoryDialog(), {
|
||||
title: __("Repositories"),
|
||||
data: this.systemsetting.system.repositories
|
||||
});
|
||||
case "install":
|
||||
return this.localInstall().then(n => {
|
||||
return this.notify(__("Package installed: {0}", n));
|
||||
}).catch(e => this.error(__("Unable to install package"), e));
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
remoteInstall() {
|
||||
const el = this.applist.get("selectedItem");
|
||||
if (!el) { return; }
|
||||
const app = el.get("data");
|
||||
if (!app) { return; }
|
||||
// get blob file
|
||||
return new Promise((resolve, reject) => {
|
||||
return this._api.blob(app.download + "?_=" + (new Date().getTime()))
|
||||
.then(data => {
|
||||
return this.install(data, app)
|
||||
.then(n => resolve(n))
|
||||
.catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
localInstall() {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.openDialog("FileDialog", {
|
||||
title: "__(Select package archive)",
|
||||
mimes: [".*/zip"]
|
||||
}).then(d => {
|
||||
return d.file.path.asFileHandle().read("binary").then(data => {
|
||||
return this.install(data)
|
||||
.then(n => {
|
||||
this.repo.unselect();
|
||||
this.repo.set("selected", 0);
|
||||
const apps = (Array.from(this.applist.get("data")).map((v) => v.pkgname));
|
||||
const idx = apps.indexOf(n);
|
||||
if (idx >= 0) {
|
||||
this.applist.set("selected", idx);
|
||||
}
|
||||
return resolve(n);
|
||||
}).catch(e => reject(__e(e)))
|
||||
.catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
install(data, meta) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return JSZip.loadAsync(data).then(zip => {
|
||||
return zip.file("package.json").async("string").then(d => {
|
||||
let name;
|
||||
const v = JSON.parse(d);
|
||||
const pth = `${this.installdir}/${v.app}`;
|
||||
const dir = [pth];
|
||||
const files = [];
|
||||
for (name in zip.files) {
|
||||
const file = zip.files[name];
|
||||
if (file.dir) {
|
||||
dir.push(pth + "/" + name);
|
||||
} else {
|
||||
files.push(name);
|
||||
}
|
||||
}
|
||||
// create all directory
|
||||
return this.mkdirs(dir).then(() => {
|
||||
return this.installFile(v.app, zip, files).then(() => {
|
||||
const app_meta = {
|
||||
pkgname: v.app,
|
||||
name: v.name,
|
||||
text: v.name,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass,
|
||||
category: v.category,
|
||||
author: v.info.author,
|
||||
version: v.version,
|
||||
description: meta ? meta.description : undefined,
|
||||
download: meta ? meta.download : undefined
|
||||
};
|
||||
v.text = v.name;
|
||||
v.filename = v.app;
|
||||
v.type = "app";
|
||||
v.mime = "antos/app";
|
||||
if (!v.iconclass && !v.icon) { v.iconclass = "fa fa-adn"; }
|
||||
v.path = pth;
|
||||
this.systemsetting.system.packages[v.app] = v;
|
||||
this.appDetail(app_meta);
|
||||
return resolve(v.name);
|
||||
}).catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
}).catch(err => reject(__e(err)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const el = this.applist.get("selectedItem");
|
||||
if (!el) { return; }
|
||||
const sel = el.get("data");
|
||||
if (!sel) { return; }
|
||||
const name = sel.pkgname;
|
||||
const app = this.systemsetting.system.packages[sel.pkgname];
|
||||
if (!app) { return; }
|
||||
return this.openDialog("YesNoDialog", {
|
||||
title: __("Uninstall") ,
|
||||
text: __("Uninstall: {0}?", app.name)
|
||||
}).then(d => {
|
||||
if (!d) { return; }
|
||||
return app.path.asFileHandle().remove().then(r => {
|
||||
if (r.error) {
|
||||
return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error)));
|
||||
}
|
||||
this.notify(__("Package uninstalled"));
|
||||
// stop all the services if any
|
||||
if (app.services) {
|
||||
for (let srv of Array.from(app.services)) {
|
||||
this._gui.unloadApp(srv);
|
||||
}
|
||||
}
|
||||
|
||||
delete this.systemsetting.system.packages[name];
|
||||
this._gui.unloadApp(name);
|
||||
if (sel.download) {
|
||||
this.appDetail(sel);
|
||||
} else {
|
||||
this.applist.remove(el);
|
||||
($(this.container)).css("visibility", "hidden");
|
||||
}
|
||||
return resolve();
|
||||
}).catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
updatePackage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.uninstall().then(() => {
|
||||
return this.remoteInstall()
|
||||
.then(() => resolve())
|
||||
.catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
mkdirs(list) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (list.length === 0) { return resolve(); }
|
||||
const dir = (list.splice(0, 1))[0].asFileHandle();
|
||||
const path = dir.parent();
|
||||
const dname = dir.basename;
|
||||
return path.asFileHandle().mk(dname)
|
||||
.then(r => {
|
||||
if (r.error) { return reject(this._api.throwe(__("Cannot create {0}", `${path}/${dir}`))); }
|
||||
return this.mkdirs(list)
|
||||
.then(() => resolve())
|
||||
.catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
installFile(n, zip, files) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (files.length === 0) { return resolve(); }
|
||||
const file = (files.splice(0, 1))[0];
|
||||
const path = `${this.installdir}/${n}/${file}`;
|
||||
return zip.file(file).async("uint8array").then(d => {
|
||||
const fp = path.asFileHandle();
|
||||
fp.cache = new Blob([d], { type: "octet/stream" });
|
||||
return fp.write("text/plain")
|
||||
.then(r => {
|
||||
if (r.error) { return reject(this._api.throwe(__("Cannot install {0}", path))); }
|
||||
return this.installFile(n, zip, files)
|
||||
.then(() => resolve())
|
||||
.catch(e => reject( __e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
}).catch(e => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MarketPlace.dependencies = [
|
||||
"os://scripts/jszip.min.js",
|
||||
"os://scripts/showdown.min.js"
|
||||
];
|
||||
MarketPlace.singleton = true;
|
||||
this.OS.register("MarketPlace", MarketPlace);
|
614
src/packages/MarketPlace/main.ts
Normal file
614
src/packages/MarketPlace/main.ts
Normal file
@ -0,0 +1,614 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
export namespace application {
|
||||
declare var showdown: any;
|
||||
declare var JSZip: any;
|
||||
export class MarketPlace extends BaseApplication {
|
||||
private installdir: string;
|
||||
private apps_meta: GenericObject<any>[];
|
||||
private repo: GUI.tag.ListViewTag;
|
||||
private applist: GUI.tag.ListViewTag;
|
||||
private container: GUI.tag.VBoxTag;
|
||||
private appname: GUI.tag.LabelTag;
|
||||
private appdetail: HTMLUListElement;
|
||||
private appdesc: HTMLParagraphElement;
|
||||
private btinstall: GUI.tag.ButtonTag;
|
||||
private btremove: GUI.tag.ButtonTag;
|
||||
private btexec: GUI.tag.ButtonTag;
|
||||
private searchbox: HTMLInputElement;
|
||||
static RepoDialog: MarketPlaceRepoDialog;
|
||||
constructor(args: AppArgumentsType[]) {
|
||||
super("MarketPlace", args);
|
||||
}
|
||||
|
||||
main(): void {
|
||||
this.installdir = this.systemsetting.system.pkgpaths.user;
|
||||
// test repository
|
||||
this.apps_meta = [];
|
||||
this.repo = this.find("repo") as GUI.tag.ListViewTag;
|
||||
this.repo.onlistselect = (e) => {
|
||||
const data = e.data.item.data;
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
return this.fetchApps(data);
|
||||
};
|
||||
|
||||
this.refreshRepoList();
|
||||
|
||||
this.applist = this.find("applist") as GUI.tag.ListViewTag;
|
||||
this.applist.onlistselect = (e) => {
|
||||
const data = e.data.item.data;
|
||||
return this.appDetail(data);
|
||||
};
|
||||
|
||||
this.container = this.find("container") as GUI.tag.VBoxTag;
|
||||
this.appname = this.find("appname") as GUI.tag.LabelTag;
|
||||
this.appdesc = this.find("app-desc") as HTMLParagraphElement;
|
||||
this.appdetail = this.find("app-detail") as HTMLUListElement;
|
||||
this.btinstall = this.find("bt-install") as GUI.tag.ButtonTag;
|
||||
this.btremove = this.find("bt-remove") as GUI.tag.ButtonTag;
|
||||
this.btexec = this.find("bt-exec") as GUI.tag.ButtonTag;
|
||||
this.searchbox = this.find("searchbox") as HTMLInputElement;
|
||||
$(this.container).css("visibility", "hidden");
|
||||
this.btexec.onbtclick = (e) => {
|
||||
const el = this.applist.selectedItem;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
const app = el.data;
|
||||
if (app.pkgname) {
|
||||
return this._gui.launch(app.pkgname, []);
|
||||
}
|
||||
};
|
||||
|
||||
this.btinstall.onbtclick = async () => {
|
||||
if (this.btinstall.data.dirty) {
|
||||
try {
|
||||
await this.updatePackage();
|
||||
return this.notify(__("Package updated"));
|
||||
} catch (e) {
|
||||
return this.error(e.toString(), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const n = await this.remoteInstall();
|
||||
return this.notify(__("Package installed: {0}", n));
|
||||
} catch (e_1) {
|
||||
return this.error(e_1.toString(), e_1);
|
||||
}
|
||||
};
|
||||
|
||||
this.btremove.onbtclick = async () => {
|
||||
try {
|
||||
await this.uninstall();
|
||||
return this.notify(__("Packaged uninstalled"));
|
||||
} catch (e) {
|
||||
return this.error(e.toString(), e);
|
||||
}
|
||||
};
|
||||
|
||||
this.bindKey("CTRL-R", () => {
|
||||
return this.menuOptionsHandle("repos");
|
||||
});
|
||||
|
||||
$(this.searchbox).keyup((e) => this.search(e));
|
||||
}
|
||||
|
||||
refreshRepoList(): void {
|
||||
const list = Array.from(this.systemsetting.system.repositories);
|
||||
list.unshift({
|
||||
text: "Installed",
|
||||
url: undefined,
|
||||
});
|
||||
this.repo.data = list;
|
||||
}
|
||||
|
||||
private search(e: JQuery.KeyboardEventBase) {
|
||||
let v: GenericObject<any>;
|
||||
switch (e.which) {
|
||||
case 37:
|
||||
return e.preventDefault();
|
||||
case 38:
|
||||
this.applist.selectPrev();
|
||||
return e.preventDefault();
|
||||
case 39:
|
||||
return e.preventDefault();
|
||||
case 40:
|
||||
this.applist.selectNext();
|
||||
return e.preventDefault();
|
||||
case 13:
|
||||
return e.preventDefault();
|
||||
default:
|
||||
var text = this.searchbox.value;
|
||||
if (text.length === 2) {
|
||||
this.applist.data = (() => {
|
||||
const result1 = [];
|
||||
for (v of this.apps_meta) {
|
||||
result1.push(v);
|
||||
}
|
||||
return result1;
|
||||
})();
|
||||
}
|
||||
if (text.length < 3) {
|
||||
return;
|
||||
}
|
||||
var result = [];
|
||||
var term = new RegExp(text, "i");
|
||||
for (v of this.apps_meta) {
|
||||
if (v.text.match(term)) {
|
||||
result.push(v);
|
||||
}
|
||||
}
|
||||
this.applist.data = result;
|
||||
}
|
||||
}
|
||||
|
||||
private fetchApps(data: GenericObject<any>): void {
|
||||
let v: API.PackageMetaType;
|
||||
if (!data.url) {
|
||||
const pkgcache = this.systemsetting.system.packages;
|
||||
const list = [];
|
||||
for (let k in pkgcache) {
|
||||
v = pkgcache[k];
|
||||
list.push({
|
||||
pkgname: v.pkgname ? v.pkgname : v.app,
|
||||
name: v.name,
|
||||
text: v.name,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass,
|
||||
category: v.category,
|
||||
author: v.info.author,
|
||||
version: v.version,
|
||||
description: `${v.path}/REAME.md`,
|
||||
});
|
||||
}
|
||||
this.apps_meta = list;
|
||||
this.applist.data = list;
|
||||
return;
|
||||
}
|
||||
|
||||
this._api
|
||||
.get(data.url + "?_=" + new Date().getTime(), "json")
|
||||
.then((d) => {
|
||||
for (v of d) {
|
||||
v.text = v.name;
|
||||
v.iconclass = "fa fa-adn";
|
||||
}
|
||||
this.apps_meta = d;
|
||||
return (this.applist.data = d);
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__(
|
||||
"Fail to fetch packages list from: {0}",
|
||||
data.url
|
||||
),
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private appDetail(d: GenericObject<any>): void {
|
||||
$(this.container).css("visibility", "visible");
|
||||
this.appname.text = d.name;
|
||||
const status = this.find("vstat") as GUI.tag.LabelTag;
|
||||
status.text = "";
|
||||
if (d.description) {
|
||||
d.description
|
||||
.asFileHandle()
|
||||
.read()
|
||||
.then((text) => {
|
||||
const converter = new showdown.Converter();
|
||||
return $(this.appdesc).html(
|
||||
converter.makeHtml(text)
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.notify(
|
||||
__("Unable to read package description")
|
||||
);
|
||||
return $(this.appdesc).empty();
|
||||
});
|
||||
} else {
|
||||
$(this.appdesc).empty();
|
||||
}
|
||||
const pkgcache = this.systemsetting.system.packages;
|
||||
this.btinstall.text = "__(Install)";
|
||||
this.btinstall.data = { dirty: false };
|
||||
if (pkgcache[d.pkgname]) {
|
||||
let vs: Version, ovs: Version;
|
||||
if (pkgcache[d.pkgname].version)
|
||||
vs = pkgcache[d.pkgname].version.__v();
|
||||
if (d.version) ovs = d.version.__v();
|
||||
$(this.btinstall).hide();
|
||||
if (vs && ovs) {
|
||||
if (ovs.nt(vs)) {
|
||||
this.btinstall.data = { dirty: true };
|
||||
this.btinstall.text = "__(Update)";
|
||||
$(this.btinstall).show();
|
||||
status.text = __(
|
||||
"Your application version is older ({0} < {1})",
|
||||
vs,
|
||||
ovs
|
||||
);
|
||||
}
|
||||
}
|
||||
$(this.btremove).show();
|
||||
$(this.btexec).show();
|
||||
} else {
|
||||
$(this.btinstall).show();
|
||||
$(this.btremove).hide();
|
||||
$(this.btexec).hide();
|
||||
}
|
||||
|
||||
$(this.appdetail).empty();
|
||||
for (let k in d) {
|
||||
const v = d[k];
|
||||
if (k !== "name" && k !== "description" && k !== "domel") {
|
||||
$(this.appdetail).append(
|
||||
$("<li>")
|
||||
.append(
|
||||
$("<span class= 'info-header'>").html(k)
|
||||
)
|
||||
.append($("<span>").html(v))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected menu(): GUI.BasicItemType[] {
|
||||
return [
|
||||
{
|
||||
text: "__(Options)",
|
||||
nodes: [
|
||||
{
|
||||
text: "__(Repositories)",
|
||||
shortcut: "C-R",
|
||||
id: "repos",
|
||||
},
|
||||
{
|
||||
text: "__(Install from zip)",
|
||||
shortcut: "C-I",
|
||||
id: "install",
|
||||
},
|
||||
],
|
||||
onchildselect: (
|
||||
e: GUI.TagEventType<GUI.tag.MenuEventData>
|
||||
) => {
|
||||
return this.menuOptionsHandle(e.data.item.data.id);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private menuOptionsHandle(id: string): void {
|
||||
switch (id) {
|
||||
case "repos":
|
||||
this.openDialog(new MarketPlace.RepoDialog(), {
|
||||
title: __("Repositories"),
|
||||
data: this.systemsetting.system.repositories,
|
||||
});
|
||||
break;
|
||||
|
||||
case "install":
|
||||
this.localInstall()
|
||||
.then((n) => {
|
||||
return this.notify(
|
||||
__("Package installed: {0}", n)
|
||||
);
|
||||
})
|
||||
.catch((e) =>
|
||||
this.error(__("Unable to install package"), e)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private remoteInstall(): Promise<string> {
|
||||
const el = this.applist.selectedItem;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
const app = el.data;
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
// get blob file
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const data = await this._api.blob(
|
||||
app.download + "?_=" + new Date().getTime()
|
||||
);
|
||||
try {
|
||||
const n = await this.install(data, app);
|
||||
return resolve(n);
|
||||
} catch (e) {
|
||||
return reject(__e(e));
|
||||
}
|
||||
} catch (e_1) {
|
||||
return reject(__e(e_1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private localInstall(): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.openDialog("FileDialog", {
|
||||
title: "__(Select package archive)",
|
||||
mimes: [".*/zip"],
|
||||
}).then((d) => {
|
||||
return d.file.path
|
||||
.asFileHandle()
|
||||
.read("binary")
|
||||
.then((data: Uint8Array) => {
|
||||
return this.install(data)
|
||||
.then((n) => {
|
||||
this.repo.unselect();
|
||||
this.repo.selected = 0;
|
||||
const apps = this.applist.data.map(
|
||||
(v) => v.pkgname
|
||||
);
|
||||
const idx = apps.indexOf(n);
|
||||
if (idx >= 0) {
|
||||
this.applist.selected = idx;
|
||||
}
|
||||
return resolve(n);
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)))
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private install(
|
||||
data: ArrayBuffer,
|
||||
meta?: GenericObject<any>
|
||||
): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return JSZip.loadAsync(data)
|
||||
.then((zip: any) => {
|
||||
return zip
|
||||
.file("package.json")
|
||||
.async("string")
|
||||
.then((d: string) => {
|
||||
let name: string;
|
||||
const v = JSON.parse(d);
|
||||
const pth = `${this.installdir}/${v.app}`;
|
||||
const dir = [pth];
|
||||
const files = [];
|
||||
for (name in zip.files) {
|
||||
const file = zip.files[name];
|
||||
if (file.dir) {
|
||||
dir.push(pth + "/" + name);
|
||||
} else {
|
||||
files.push(name);
|
||||
}
|
||||
}
|
||||
// create all directory
|
||||
return this.mkdirs(dir)
|
||||
.then(() => {
|
||||
return this.installFile(
|
||||
v.app,
|
||||
zip,
|
||||
files
|
||||
)
|
||||
.then(() => {
|
||||
const app_meta = {
|
||||
pkgname: v.app,
|
||||
name: v.name,
|
||||
text: v.name,
|
||||
icon: v.icon,
|
||||
iconclass: v.iconclass,
|
||||
category: v.category,
|
||||
author: v.info.author,
|
||||
version: v.version,
|
||||
description: meta
|
||||
? meta.description
|
||||
: undefined,
|
||||
download: meta
|
||||
? meta.download
|
||||
: undefined,
|
||||
};
|
||||
v.text = v.name;
|
||||
v.filename = v.app;
|
||||
v.type = "app";
|
||||
v.mime = "antos/app";
|
||||
if (
|
||||
!v.iconclass &&
|
||||
!v.icon
|
||||
) {
|
||||
v.iconclass =
|
||||
"fa fa-adn";
|
||||
}
|
||||
v.path = pth;
|
||||
this.systemsetting.system.packages[
|
||||
v.app
|
||||
] = v;
|
||||
this.appDetail(app_meta);
|
||||
return resolve(v.name);
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((err: Error) => reject(__e(err)));
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
private uninstall(): Promise<any> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const el = this.applist.selectedItem;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
const sel = el.data;
|
||||
if (!sel) {
|
||||
return;
|
||||
}
|
||||
const name = sel.pkgname;
|
||||
const app = this.systemsetting.system.packages[sel.pkgname];
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const d = await this.openDialog("YesNoDialog", {
|
||||
title: __("Uninstall"),
|
||||
text: __("Uninstall: {0}?", app.name),
|
||||
});
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const r = await app.path
|
||||
.asFileHandle()
|
||||
.remove();
|
||||
if (r.error) {
|
||||
return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error)));
|
||||
}
|
||||
this.notify(__("Package uninstalled"));
|
||||
// stop all the services if any
|
||||
if (app.services) {
|
||||
for (let srv of Array.from(app.services)) {
|
||||
this._gui.unloadApp(srv);
|
||||
}
|
||||
}
|
||||
delete this.systemsetting.system.packages[name];
|
||||
this._gui.unloadApp(name);
|
||||
if (sel.download) {
|
||||
this.appDetail(sel);
|
||||
}
|
||||
else {
|
||||
this.applist.delete(el);
|
||||
$(this.container).css("visibility", "hidden");
|
||||
}
|
||||
return resolve();
|
||||
}
|
||||
catch (e) {
|
||||
return reject(__e(e));
|
||||
}
|
||||
}
|
||||
catch (e_1) {
|
||||
return reject(__e(e_1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updatePackage(): Promise<any>{
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await this.uninstall();
|
||||
try {
|
||||
await this.remoteInstall();
|
||||
return resolve();
|
||||
}
|
||||
catch (e) {
|
||||
return reject(__e(e));
|
||||
}
|
||||
}
|
||||
catch (e_1) {
|
||||
return reject(__e(e_1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private mkdirs(list: string[]): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (list.length === 0) {
|
||||
return resolve();
|
||||
}
|
||||
const dir = list.splice(0, 1)[0].asFileHandle();
|
||||
const path = dir.parent();
|
||||
const dname = dir.basename;
|
||||
return path
|
||||
.asFileHandle()
|
||||
.mk(dname)
|
||||
.then((r) => {
|
||||
if (r.error) {
|
||||
return reject(
|
||||
this._api.throwe(
|
||||
__(
|
||||
"Cannot create {0}",
|
||||
`${path}/${dir}`
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return this.mkdirs(list)
|
||||
.then(() => resolve())
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
private installFile(n: string, zip: any, files: string[]): Promise<any>{
|
||||
return new Promise((resolve, reject) => {
|
||||
if (files.length === 0) {
|
||||
return resolve();
|
||||
}
|
||||
const file = files.splice(0, 1)[0];
|
||||
const path = `${this.installdir}/${n}/${file}`;
|
||||
return zip
|
||||
.file(file)
|
||||
.async("uint8array")
|
||||
.then((d: Uint8Array) => {
|
||||
const fp = path.asFileHandle();
|
||||
fp.cache = new Blob([d], { type: "octet/stream" });
|
||||
return fp
|
||||
.write("text/plain")
|
||||
.then((r) => {
|
||||
if (r.error) {
|
||||
return reject(
|
||||
this._api.throwe(
|
||||
__("Cannot install {0}", path)
|
||||
)
|
||||
);
|
||||
}
|
||||
return this.installFile(n, zip, files)
|
||||
.then(() => resolve())
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MarketPlace.dependencies = [
|
||||
"os://scripts/jszip.min.js",
|
||||
"os://scripts/showdown.min.js",
|
||||
];
|
||||
MarketPlace.singleton = true;
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width = "3" ></afx-resizer>
|
||||
<afx-vbox data-id = "container">
|
||||
<div data-id = "appname" data-height = "25"></div>
|
||||
<afx-label data-id = "appname" data-height = "25"></afx-label>
|
||||
<afx-hbox data-height = "30">
|
||||
<div style = "text-align:left;">
|
||||
<afx-button data-id = "bt-remove" text = "__(Uninstall)"></afx-button>
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class AppearanceHandle extends SettingHandle {
|
||||
constructor(scheme, parent) {
|
||||
let v;
|
||||
super(scheme, parent);
|
||||
this.wplist = this.find("wplist");
|
||||
this.wpreview = this.find("wp-preview");
|
||||
this.wpsize = this.find("wpsize");
|
||||
this.wprepeat = this.find("wprepeat");
|
||||
this.themelist = this.find("theme-list");
|
||||
this.syswp = undefined;
|
||||
this.wplist.set("onlistselect", e => {
|
||||
const data = e.data.item.get("data");
|
||||
$(this.wpreview)
|
||||
.css("background-image", `url(${data.path.asFileHandle().getlink()})` )
|
||||
.css("background-size", "cover");
|
||||
this.parent.systemsetting.appearance.wp.url = data.path;
|
||||
return this.parent._gui.wallpaper();
|
||||
});
|
||||
|
||||
this.wplist.set("buttons", [
|
||||
{
|
||||
text: "+", onbtclick: e => {
|
||||
return this.parent.openDialog("FileDialog", {
|
||||
title: __("Select image file"),
|
||||
mimes: ["image/.*"]
|
||||
}).then(d => {
|
||||
this.parent.systemsetting.appearance.wps.push(d.file.path);
|
||||
return this.wplist.set("data", this.getwplist());
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
this.wpsize.set("onlistselect", e => {
|
||||
this.parent.systemsetting.appearance.wp.size = e.data.item.get("data").text;
|
||||
return this.parent._gui.wallpaper();
|
||||
});
|
||||
|
||||
const sizes = [
|
||||
{ text: "cover", selected: this.parent.systemsetting.appearance.wp.size === "cover" },
|
||||
{ text: "auto", selected: this.parent.systemsetting.appearance.wp.size === "auto" },
|
||||
{ text: "contain", selected: this.parent.systemsetting.appearance.wp.size === "contain" }
|
||||
];
|
||||
this.wpsize.set("data", sizes);
|
||||
|
||||
const repeats = [
|
||||
{ text: "repeat", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat" },
|
||||
{ text: "repeat-x", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat-x" },
|
||||
{ text: "repeat-y", selected: this.parent.systemsetting.appearance.wp.repeat === "repeat-y" },
|
||||
{ text: "no-repeat", selected: this.parent.systemsetting.appearance.wp.repeat === "no-repeat" }
|
||||
];
|
||||
this.wprepeat.set("onlistselect", e => {
|
||||
this.parent.systemsetting.appearance.wp.repeat = e.data.item.get("data").text;
|
||||
return this.parent._gui.wallpaper();
|
||||
});
|
||||
this.wprepeat.set("data", repeats);
|
||||
const currtheme = this.parent.systemsetting.appearance.theme;
|
||||
for (v of Array.from(this.parent.systemsetting.appearance.themes)) { v.selected = v.name === currtheme; }
|
||||
this.themelist.set("data" , this.parent.systemsetting.appearance.themes);
|
||||
this.themelist.set("onlistselect", e => {
|
||||
let data;
|
||||
if (e && e.data) { data = e.data.item.get("data"); }
|
||||
if (!data) { return; }
|
||||
if (data.name === this.parent.systemsetting.appearance.theme) { return; }
|
||||
this.parent.systemsetting.appearance.theme = data.name;
|
||||
return this.parent._gui.loadTheme(data.name, true);
|
||||
});
|
||||
if (!this.syswp) {
|
||||
const path = "os://resources/themes/system/wp";
|
||||
path.asFileHandle().read()
|
||||
.then(d => {
|
||||
if (d.error) { return this.parent.error(__("Cannot read wallpaper list from {0}", path)); }
|
||||
for (v of Array.from(d.result)) {
|
||||
v.text = v.filename;
|
||||
v.iconclass = "fa fa-file-image-o";
|
||||
}
|
||||
this.syswp = d.result;
|
||||
return this.wplist.set("data", this.getwplist());
|
||||
}).catch(e => this.parent.error(__("Unable to read: {0}", path), e));
|
||||
} else {
|
||||
|
||||
this.wplist.set("data", this.getwplist());
|
||||
}
|
||||
}
|
||||
|
||||
getwplist() {
|
||||
let v;
|
||||
let list = [];
|
||||
for (v of Array.from(this.parent.systemsetting.appearance.wps)) {
|
||||
const file = v.asFileHandle();
|
||||
list.push({
|
||||
text: file.basename,
|
||||
path: file.path,
|
||||
selected: file.path === this.parent.systemsetting.appearance.wp.url,
|
||||
iconclass: "fa fa-file-image-o"
|
||||
});
|
||||
}
|
||||
list = list.concat(this.syswp);
|
||||
for (v of Array.from(list)) { v.selected = v.path === this.parent.systemsetting.appearance.wp.url; }
|
||||
return list;
|
||||
}
|
||||
}
|
206
src/packages/Setting/AppearanceHandle.ts
Normal file
206
src/packages/Setting/AppearanceHandle.ts
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
const App = OS.application.Setting;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class AppearanceHandle
|
||||
* @extends {App.SettingHandle}
|
||||
*/
|
||||
class AppearanceHandle extends App.SettingHandle {
|
||||
private wplist: GUI.tag.ListViewTag;
|
||||
private wpreview: HTMLDivElement;
|
||||
private wprepeat: GUI.tag.ListViewTag;
|
||||
private themelist: GUI.tag.ListViewTag;
|
||||
private wpsize: GUI.tag.ListViewTag;
|
||||
private syswp: string;
|
||||
|
||||
/**
|
||||
*Creates an instance of AppearanceHandle.
|
||||
* @param {HTMLElement} scheme
|
||||
* @param {OS.application.Setting} parent
|
||||
* @memberof AppearanceHandle
|
||||
*/
|
||||
constructor(scheme: HTMLElement, parent: OS.application.Setting) {
|
||||
let v: GenericObject<any>;
|
||||
super(scheme, parent);
|
||||
this.wplist = this.find("wplist") as GUI.tag.ListViewTag;
|
||||
this.wpreview = this.find("wp-preview") as HTMLDivElement;
|
||||
this.wpsize = this.find("wpsize") as GUI.tag.ListViewTag;
|
||||
this.wprepeat = this.find("wprepeat") as GUI.tag.ListViewTag;
|
||||
this.themelist = this.find("theme-list") as GUI.tag.ListViewTag;
|
||||
this.syswp = undefined;
|
||||
this.wplist.onlistselect = (e) => {
|
||||
const data = e.data.item.data;
|
||||
$(this.wpreview)
|
||||
.css(
|
||||
"background-image",
|
||||
`url(${data.path.asFileHandle().getlink()})`
|
||||
)
|
||||
.css("background-size", "cover");
|
||||
OS.setting.appearance.wp.url = data.path;
|
||||
GUI.wallpaper();
|
||||
};
|
||||
|
||||
this.wplist.buttons = [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: (e) => {
|
||||
return this.parent
|
||||
.openDialog("FileDialog", {
|
||||
title: __("Select image file"),
|
||||
mimes: ["image/.*"],
|
||||
})
|
||||
.then((d) => {
|
||||
OS.setting.appearance.wps.push(d.file.path);
|
||||
this.wplist.data = this.getwplist();
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
this.wpsize.onlistselect = (e) => {
|
||||
setting.appearance.wp.size = e.data.item.data.text;
|
||||
return GUI.wallpaper();
|
||||
};
|
||||
|
||||
const sizes = [
|
||||
{
|
||||
text: "cover",
|
||||
selected: setting.appearance.wp.size === "cover",
|
||||
},
|
||||
{
|
||||
text: "auto",
|
||||
selected: setting.appearance.wp.size === "auto",
|
||||
},
|
||||
{
|
||||
text: "contain",
|
||||
selected: setting.appearance.wp.size === "contain",
|
||||
},
|
||||
];
|
||||
this.wpsize.data = sizes;
|
||||
|
||||
const repeats = [
|
||||
{
|
||||
text: "repeat",
|
||||
selected: setting.appearance.wp.repeat === "repeat",
|
||||
},
|
||||
{
|
||||
text: "repeat-x",
|
||||
selected: setting.appearance.wp.repeat === "repeat-x",
|
||||
},
|
||||
{
|
||||
text: "repeat-y",
|
||||
selected: setting.appearance.wp.repeat === "repeat-y",
|
||||
},
|
||||
{
|
||||
text: "no-repeat",
|
||||
selected: setting.appearance.wp.repeat === "no-repeat",
|
||||
},
|
||||
];
|
||||
this.wprepeat.onlistselect = (e) => {
|
||||
setting.appearance.wp.repeat = e.data.item.data.text;
|
||||
GUI.wallpaper();
|
||||
};
|
||||
this.wprepeat.data = repeats;
|
||||
const currtheme = setting.appearance.theme;
|
||||
for (v of setting.appearance.themes) {
|
||||
v.selected = v.name === currtheme;
|
||||
}
|
||||
this.themelist.data = setting.appearance.themes;
|
||||
this.themelist.onlistselect = (e) => {
|
||||
let data;
|
||||
if (e && e.data) {
|
||||
data = e.data.item.data;
|
||||
}
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
if (data.name === setting.appearance.theme) {
|
||||
return;
|
||||
}
|
||||
setting.appearance.theme = data.name;
|
||||
GUI.loadTheme(data.name, true);
|
||||
};
|
||||
if (!this.syswp) {
|
||||
const path = "os://resources/themes/system/wp";
|
||||
path.asFileHandle()
|
||||
.read()
|
||||
.then((d) => {
|
||||
if (d.error) {
|
||||
return this.parent.error(
|
||||
__(
|
||||
"Cannot read wallpaper list from {0}",
|
||||
path
|
||||
)
|
||||
);
|
||||
}
|
||||
for (v of Array.from(d.result)) {
|
||||
v.text = v.filename;
|
||||
v.iconclass = "fa fa-file-image-o";
|
||||
}
|
||||
this.syswp = d.result;
|
||||
return (this.wplist.data = this.getwplist());
|
||||
})
|
||||
.catch((e) =>
|
||||
this.parent.error(
|
||||
__("Unable to read: {0}", path),
|
||||
e
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.wplist.data = this.getwplist();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @returns {GenericObject<any>[]}
|
||||
* @memberof AppearanceHandle
|
||||
*/
|
||||
private getwplist(): GenericObject<any>[] {
|
||||
let v;
|
||||
let list = [];
|
||||
for (v of setting.appearance.wps) {
|
||||
const file = v.asFileHandle();
|
||||
list.push({
|
||||
text: file.basename,
|
||||
path: file.path,
|
||||
selected: file.path === setting.appearance.wp.url,
|
||||
iconclass: "fa fa-file-image-o",
|
||||
});
|
||||
}
|
||||
list = list.concat(this.syswp);
|
||||
for (v of list) {
|
||||
v.selected = v.path === setting.appearance.wp.url;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
App.AppearanceHandle = AppearanceHandle;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class LocaleHandle extends SettingHandle {
|
||||
constructor(scheme, parent) {
|
||||
super(scheme, parent);
|
||||
this.lglist = this.find("lglist");
|
||||
this.localelist = undefined;
|
||||
this.lglist.set("onlistselect", e => {
|
||||
return this.parent._api.setLocale(e.data.item.get("data").text);
|
||||
});
|
||||
if (!this.localelist) {
|
||||
const path = "os://resources/languages";
|
||||
path.asFileHandle().read()
|
||||
.then(d => {
|
||||
if (d.derror) { return this.parent.error(__("Cannot fetch system locales: {0}", d.error)); }
|
||||
for (let v of Array.from(d.result)) {
|
||||
v.text = v.filename.replace(/\.json$/g, "");
|
||||
v.selected = v.text === this.parent.systemsetting.system.locale;
|
||||
}
|
||||
this.localelist = d.result;
|
||||
return this.lglist.set("data", this.localelist);
|
||||
}).catch(e => this.parent.error(__("Unable to read: {0}", path), e));
|
||||
} else {
|
||||
this.lglist.set("data", this.localelist);
|
||||
}
|
||||
}
|
||||
}
|
77
src/packages/Setting/LocaleHandle.ts
Normal file
77
src/packages/Setting/LocaleHandle.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
namespace OS {
|
||||
const App = OS.application.Setting;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class LocaleHandle
|
||||
* @extends {App.SettingHandle}
|
||||
*/
|
||||
class LocaleHandle extends App.SettingHandle {
|
||||
private lglist: GUI.tag.ListViewTag;
|
||||
private localelist: GenericObject<any>[];
|
||||
|
||||
/**
|
||||
*Creates an instance of LocaleHandle.
|
||||
* @param {HTMLElement} scheme
|
||||
* @param {OS.application.Setting} parent
|
||||
* @memberof LocaleHandle
|
||||
*/
|
||||
constructor(scheme: HTMLElement, parent: OS.application.Setting) {
|
||||
super(scheme, parent);
|
||||
this.lglist = this.find("lglist") as GUI.tag.ListViewTag;
|
||||
this.localelist = undefined;
|
||||
this.lglist.onlistselect = (e) => {
|
||||
return API.setLocale(e.data.item.data.text);
|
||||
};
|
||||
if (!this.localelist) {
|
||||
const path = "os://resources/languages";
|
||||
path.asFileHandle()
|
||||
.read()
|
||||
.then((d) => {
|
||||
if (d.derror) {
|
||||
return this.parent.error(
|
||||
__("Cannot fetch system locales: {0}", d.error)
|
||||
);
|
||||
}
|
||||
for (let v of d.result) {
|
||||
v.text = v.filename.replace(/\.json$/g, "");
|
||||
v.selected = v.text === setting.system.locale;
|
||||
}
|
||||
this.localelist = d.result;
|
||||
return (this.lglist.data = this.localelist);
|
||||
})
|
||||
.catch((e) =>
|
||||
this.parent.error(__("Unable to read: {0}", path), e)
|
||||
);
|
||||
} else {
|
||||
this.lglist.data = this.localelist;
|
||||
}
|
||||
}
|
||||
}
|
||||
App.LocaleHandle = LocaleHandle;
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class StartupHandle extends SettingHandle {
|
||||
constructor(scheme, parent) {
|
||||
super(scheme, parent);
|
||||
this.srvlist = this.find("srvlist");
|
||||
this.applist = this.find("applist");
|
||||
this.srvlist.set("buttons", [
|
||||
{
|
||||
text: "+", onbtclick: e => {
|
||||
let services = [];
|
||||
for (var k in this.parent.systemsetting.system.packages) {
|
||||
const v = this.parent.systemsetting.system.packages[k];
|
||||
if (v.services) {
|
||||
const srvs = (Array.from(v.services).map((x) => ({ text: `${k}/${x}`, iconclass: "fa fa-tasks" })));
|
||||
services = services.concat(srvs);
|
||||
}
|
||||
}
|
||||
return this.parent.openDialog("SelectionDialog", {
|
||||
title: "__(Add service)",
|
||||
data: services
|
||||
}).then(d => {
|
||||
this.parent.systemsetting.system.startup.services.push(d.text);
|
||||
return this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "-", onbtclick: e => {
|
||||
const item = this.srvlist.get("selectedItem");
|
||||
if (!item) { return; }
|
||||
const selidx = $(item).index();
|
||||
this.parent.systemsetting.system.startup.services.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
this.applist.set("buttons", [
|
||||
{
|
||||
text: "+", onbtclick: e => {
|
||||
const apps = ((() => {
|
||||
const result = [];
|
||||
for (let k in this.parent.systemsetting.system.packages) {
|
||||
const v = this.parent.systemsetting.system.packages[k];
|
||||
result.push({ text: k, iconclass: v.iconclass });
|
||||
}
|
||||
return result;
|
||||
})());
|
||||
return this.parent.openDialog("SelectionDialog", {
|
||||
title: "__(Add application)",
|
||||
data: apps
|
||||
}).then(d => {
|
||||
this.parent.systemsetting.system.startup.apps.push(d.text);
|
||||
return this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "-", onbtclick: e => {
|
||||
const item = this.applist.get("selectedItem");
|
||||
if (!item) { return; }
|
||||
const selidx = $(item).index();
|
||||
this.parent.systemsetting.system.startup.apps.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
}
|
||||
}
|
||||
]);
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
let v;
|
||||
this.srvlist.set("data", ((() => {
|
||||
const result = [];
|
||||
for (v of Array.from(this.parent.systemsetting.system.startup.services)) { result.push({ text:v });
|
||||
}
|
||||
return result;
|
||||
})()));
|
||||
return this.applist.set("data", ((() => {
|
||||
const result1 = [];
|
||||
for (v of Array.from(this.parent.systemsetting.system.startup.apps)) { result1.push({ text:v });
|
||||
}
|
||||
return result1;
|
||||
})()));
|
||||
}
|
||||
}
|
155
src/packages/Setting/StartupHandle.ts
Normal file
155
src/packages/Setting/StartupHandle.ts
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
const App = OS.application.Setting;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class StartupHandle
|
||||
* @extends {App.SettingHandle}
|
||||
*/
|
||||
class StartupHandle extends App.SettingHandle {
|
||||
private srvlist: GUI.tag.ListViewTag;
|
||||
private applist: GUI.tag.ListViewTag;
|
||||
|
||||
/**
|
||||
*Creates an instance of StartupHandle.
|
||||
* @param {HTMLElement} scheme
|
||||
* @param {OS.application.Setting} parent
|
||||
* @memberof StartupHandle
|
||||
*/
|
||||
constructor(scheme: HTMLElement, parent: OS.application.Setting) {
|
||||
super(scheme, parent);
|
||||
this.srvlist = this.find("srvlist") as GUI.tag.ListViewTag;
|
||||
this.applist = this.find("applist") as GUI.tag.ListViewTag;
|
||||
this.srvlist.buttons = [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: () => {
|
||||
let services = [];
|
||||
for (var k in setting.system.packages) {
|
||||
const v = setting.system.packages[k];
|
||||
if (v.services) {
|
||||
const srvs = v.services.map((x) => ({
|
||||
text: `${k}/${x}`,
|
||||
iconclass: "fa fa-tasks",
|
||||
}));
|
||||
services = services.concat(srvs);
|
||||
}
|
||||
}
|
||||
this.parent
|
||||
.openDialog("SelectionDialog", {
|
||||
title: "__(Add service)",
|
||||
data: services,
|
||||
})
|
||||
.then((d) => {
|
||||
setting.system.startup.services.push(d.text);
|
||||
return this.refresh();
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: () => {
|
||||
const item = this.srvlist.selectedItem;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const selidx = $(item).index();
|
||||
setting.system.startup.services.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
this.applist.buttons = [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: () => {
|
||||
const apps = (() => {
|
||||
const result = [];
|
||||
for (let k in setting.system.packages) {
|
||||
const v = setting.system.packages[k];
|
||||
result.push({
|
||||
text: k,
|
||||
iconclass: v.iconclass,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
this.parent
|
||||
.openDialog("SelectionDialog", {
|
||||
title: "__(Add application)",
|
||||
data: apps,
|
||||
})
|
||||
.then((d) => {
|
||||
setting.system.startup.apps.push(d.text);
|
||||
return this.refresh();
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: () => {
|
||||
const item = this.applist.selectedItem;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const selidx = $(item).index();
|
||||
setting.system.startup.apps.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
},
|
||||
},
|
||||
];
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @memberof StartupHandle
|
||||
*/
|
||||
private refresh(): void {
|
||||
let v;
|
||||
this.srvlist.data = (() => {
|
||||
const result = [];
|
||||
for (v of setting.system.startup.services) {
|
||||
result.push({ text: v });
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
this.applist.data = (() => {
|
||||
const result1 = [];
|
||||
for (v of Array.from(setting.system.startup.apps)) {
|
||||
result1.push({ text: v });
|
||||
}
|
||||
return result1;
|
||||
})();
|
||||
}
|
||||
}
|
||||
App.StartupHandle = StartupHandle;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class VFSSettingDialog extends this.OS.GUI.BasicDialog {
|
||||
constructor() {
|
||||
super("VFSSettingDialog", VFSSettingDialog.scheme);
|
||||
}
|
||||
|
||||
main() {
|
||||
super.main();
|
||||
$(this.find("txtPath")).click(e => {
|
||||
return this.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true
|
||||
})
|
||||
.then(d => {
|
||||
return (this.find("txtPath")).value = d.file.path;
|
||||
});
|
||||
});
|
||||
|
||||
this.find("btnOk").set("onbtclick", e => {
|
||||
const data = {
|
||||
path: (this.find("txtPath")).value,
|
||||
name: (this.find("txtName")).value
|
||||
};
|
||||
if (!data.name || (data.name === "")) { return this.error(__("Please enter mount point name")); }
|
||||
if (!data.path || (data.path === "")) { return this.error(__("Please select a directory")); }
|
||||
if (this.handle) { this.handle(data); }
|
||||
return this.quit();
|
||||
});
|
||||
|
||||
(this.find("btnCancel")).set("onbtclick", e => {
|
||||
return this.quit();
|
||||
});
|
||||
|
||||
if (!this.data) { return; }
|
||||
if (this.data.text) { (this.find("txtName")).value = this.data.text; }
|
||||
if (this.data.path) { return (this.find("txtPath")).value = this.data.path; }
|
||||
}
|
||||
}
|
||||
|
||||
VFSSettingDialog.scheme = `\
|
||||
<afx-app-window width='250' height='180' apptitle = "__(Mount Points)">
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<div data-width = "10" />
|
||||
<afx-vbox>
|
||||
<div data-height="10" />
|
||||
<afx-label data-height="30" text = "__(Name)" />
|
||||
<input type = "text" data-id= "txtName" />
|
||||
<div data-height="3" />
|
||||
<afx-label data-height="30" text = "__(Path)" />
|
||||
<input type = "text" data-id= "txtPath" />
|
||||
<div data-height="10" />
|
||||
<afx-hbox data-height="30">
|
||||
<div />
|
||||
<afx-button data-id = "btnOk" text = "__(Ok)" data-width = "40" />
|
||||
<afx-button data-id = "btnCancel" text = "__(Cancel)" data-width = "50" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
<div data-width = "10" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
</afx-app-window>\
|
||||
`;
|
||||
|
||||
class VFSHandle extends SettingHandle {
|
||||
constructor(scheme, parent) {
|
||||
super(scheme, parent);
|
||||
this.mplist = this.find("mplist");
|
||||
this.dpath = this.find("dpath");
|
||||
this.ppath = this.find("ppath");
|
||||
this.mplist.set("buttons", [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: e => {
|
||||
return this.parent.openDialog(new VFSSettingDialog(), {
|
||||
title: "__(Add mount point)"
|
||||
})
|
||||
.then(d => {
|
||||
this.parent.systemsetting.VFS.mountpoints.push({
|
||||
text: d.name, path: d.path, iconclass: "fa fa-folder", type: "fs"
|
||||
});
|
||||
return this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: e => {
|
||||
const item = this.mplist.get("selectedItem");
|
||||
if (!item) { return; }
|
||||
const selidx = $(item).index();
|
||||
return this.parent.openDialog("YesNoDialog", {
|
||||
title: "__(Remove)",
|
||||
text: __("Remove: {0}?", item.get("data").text)
|
||||
}).then(d => {
|
||||
if (!d) { return; }
|
||||
this.parent.systemsetting.VFS.mountpoints.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "",
|
||||
iconclass: "fa fa-pencil",
|
||||
onbtclick: e => {
|
||||
const sel = this.mplist.get("selectedItem");
|
||||
if (!sel) { return; }
|
||||
return this.parent.openDialog(new VFSSettingDialog(), {
|
||||
title: "__(Edit mount point)",
|
||||
text: sel.get("data").text,
|
||||
path: sel.get("data").path
|
||||
}).then(d => {
|
||||
sel.get("data").text = d.name;
|
||||
sel.get("data").path = d.path;
|
||||
return this.refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
(this.find("btndpath")).set('onbtclick', e => {
|
||||
return this.parent.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true
|
||||
}).then(d => {
|
||||
this.parent.systemsetting.desktop.path = d.file.path;
|
||||
this.parent._gui.refreshDesktop();
|
||||
return this.refresh();
|
||||
});
|
||||
});
|
||||
|
||||
(this.find("btnppath")).set('onbtclick', e => {
|
||||
return this.parent.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true
|
||||
}).then(d => {
|
||||
this.parent.systemsetting.system.pkgpaths.user = d.file.path;
|
||||
return this.refresh();
|
||||
});
|
||||
});
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.mplist.set("data", this.parent.systemsetting.VFS.mountpoints);
|
||||
this.dpath.set("text", this.parent.systemsetting.desktop.path);
|
||||
return this.ppath.set("text", this.parent.systemsetting.system.pkgpaths.user);
|
||||
}
|
||||
}
|
246
src/packages/Setting/VFSHandle.ts
Normal file
246
src/packages/Setting/VFSHandle.ts
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
namespace OS {
|
||||
const App = OS.application.Setting;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class VFSSettingDialog
|
||||
* @extends {GUI.BasicDialog}
|
||||
*/
|
||||
class VFSSettingDialog extends GUI.BasicDialog {
|
||||
/**
|
||||
*Creates an instance of VFSSettingDialog.
|
||||
* @memberof VFSSettingDialog
|
||||
*/
|
||||
constructor() {
|
||||
super("VFSSettingDialog", VFSSettingDialog.scheme);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns
|
||||
* @memberof VFSSettingDialog
|
||||
*/
|
||||
main() {
|
||||
super.main();
|
||||
$(this.find("txtPath")).click((e) => {
|
||||
return this.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true,
|
||||
}).then((d) => {
|
||||
return ((this.find("txtPath") as HTMLInputElement).value =
|
||||
d.file.path);
|
||||
});
|
||||
});
|
||||
|
||||
(this.find("btnOk") as GUI.tag.ButtonTag).onbtclick = (e) => {
|
||||
const data = {
|
||||
path: (this.find("txtPath") as HTMLInputElement).value,
|
||||
name: (this.find("txtName") as HTMLInputElement).value,
|
||||
};
|
||||
if (!data.name || data.name === "") {
|
||||
return this.error(__("Please enter mount point name"));
|
||||
}
|
||||
if (!data.path || data.path === "") {
|
||||
return this.error(__("Please select a directory"));
|
||||
}
|
||||
if (this.handle) {
|
||||
this.handle(data);
|
||||
}
|
||||
return this.quit();
|
||||
};
|
||||
|
||||
(this.find("btnCancel") as GUI.tag.ButtonTag).onbtclick = (e) => {
|
||||
return this.quit();
|
||||
};
|
||||
|
||||
if (!this.data) {
|
||||
return;
|
||||
}
|
||||
if (this.data.text) {
|
||||
(this.find(
|
||||
"txtName"
|
||||
) as HTMLInputElement).value = this.data.text;
|
||||
}
|
||||
if (this.data.path) {
|
||||
return ((this.find(
|
||||
"txtPath"
|
||||
) as HTMLInputElement).value = this.data.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VFSSettingDialog.scheme = `\
|
||||
<afx-app-window width='250' height='180' apptitle = "__(Mount Points)">
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<div data-width = "10" />
|
||||
<afx-vbox>
|
||||
<div data-height="10" />
|
||||
<afx-label data-height="30" text = "__(Name)" />
|
||||
<input type = "text" data-id= "txtName" />
|
||||
<div data-height="3" />
|
||||
<afx-label data-height="30" text = "__(Path)" />
|
||||
<input type = "text" data-id= "txtPath" />
|
||||
<div data-height="10" />
|
||||
<afx-hbox data-height="30">
|
||||
<div />
|
||||
<afx-button data-id = "btnOk" text = "__(Ok)" data-width = "40" />
|
||||
<afx-button data-id = "btnCancel" text = "__(Cancel)" data-width = "50" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
<div data-width = "10" />
|
||||
</afx-hbox>
|
||||
</afx-vbox>
|
||||
</afx-app-window>\
|
||||
`;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class VFSHandle
|
||||
* @extends {App.SettingHandle}
|
||||
*/
|
||||
class VFSHandle extends App.SettingHandle {
|
||||
private mplist: GUI.tag.ListViewTag;
|
||||
private dpath: GUI.tag.LabelTag;
|
||||
private ppath: GUI.tag.LabelTag;
|
||||
|
||||
/**
|
||||
*Creates an instance of VFSHandle.
|
||||
* @param {HTMLElement} scheme
|
||||
* @param {OS.application.Setting} parent
|
||||
* @memberof VFSHandle
|
||||
*/
|
||||
constructor(scheme: HTMLElement, parent: OS.application.Setting) {
|
||||
super(scheme, parent);
|
||||
this.mplist = this.find("mplist") as GUI.tag.ListViewTag;
|
||||
this.dpath = this.find("dpath") as GUI.tag.LabelTag;
|
||||
this.ppath = this.find("ppath") as GUI.tag.LabelTag;
|
||||
this.mplist.buttons = [
|
||||
{
|
||||
text: "+",
|
||||
onbtclick: async () => {
|
||||
const d = await this.parent.openDialog(
|
||||
new VFSSettingDialog(),
|
||||
{
|
||||
title: "__(Add mount point)",
|
||||
}
|
||||
);
|
||||
setting.VFS.mountpoints.push({
|
||||
text: d.name,
|
||||
path: d.path,
|
||||
iconclass: "fa fa-folder",
|
||||
type: "fs",
|
||||
});
|
||||
return this.refresh();
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "-",
|
||||
onbtclick: async () => {
|
||||
const item = this.mplist.selectedItem;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const selidx = $(item).index();
|
||||
const d = await this.parent.openDialog("YesNoDialog", {
|
||||
title: "__(Remove)",
|
||||
text: __("Remove: {0}?", item.data.text),
|
||||
});
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
setting.VFS.mountpoints.splice(selidx, 1);
|
||||
return this.refresh();
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "",
|
||||
iconclass: "fa fa-pencil",
|
||||
onbtclick: async () => {
|
||||
const sel = this.mplist.selectedItem;
|
||||
if (!sel) {
|
||||
return;
|
||||
}
|
||||
const d = await this.parent.openDialog(
|
||||
new VFSSettingDialog(),
|
||||
{
|
||||
title: "__(Edit mount point)",
|
||||
text: sel.data.text,
|
||||
path: sel.data.path,
|
||||
}
|
||||
);
|
||||
sel.data.text = d.name;
|
||||
sel.data.path = d.path;
|
||||
return this.refresh();
|
||||
},
|
||||
},
|
||||
];
|
||||
(this.find(
|
||||
"btndpath"
|
||||
) as GUI.tag.ButtonTag).onbtclick = async () => {
|
||||
const d = await this.parent.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true,
|
||||
});
|
||||
setting.desktop.path = d.file.path;
|
||||
GUI.refreshDesktop();
|
||||
return this.refresh();
|
||||
};
|
||||
|
||||
(this.find(
|
||||
"btnppath"
|
||||
) as GUI.tag.ButtonTag).onbtclick = async () => {
|
||||
const d = await this.parent.openDialog("FileDialog", {
|
||||
title: "__(Select a directory)",
|
||||
mimes: ["dir"],
|
||||
hidden: true,
|
||||
});
|
||||
setting.system.pkgpaths.user = d.file.path;
|
||||
return this.refresh();
|
||||
};
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @memberof VFSHandle
|
||||
*/
|
||||
private refresh(): void {
|
||||
this.mplist.data = setting.VFS.mountpoints;
|
||||
this.dpath.text = setting.desktop.path;
|
||||
this.ppath.text = setting.system.pkgpaths.user;
|
||||
}
|
||||
}
|
||||
|
||||
App.VFSHandle = VFSHandle;
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
class SettingHandle {
|
||||
constructor(scheme, parent) {
|
||||
this.scheme = scheme;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
find(id) { if (this.scheme) { return ($(`[data-id='${id}']`, this.scheme))[0]; } }
|
||||
|
||||
render() {}
|
||||
}
|
||||
|
||||
class Setting extends this.OS.GUI.BaseApplication {
|
||||
constructor(args) {
|
||||
super("Setting", args);
|
||||
}
|
||||
|
||||
main() {
|
||||
this.container = this.find("container");
|
||||
|
||||
new AppearanceHandle(this.find("appearance"), this);
|
||||
new VFSHandle(this.find("vfs"), this);
|
||||
new LocaleHandle(this.find("locale"), this);
|
||||
new StartupHandle(this.find("startup"), this);
|
||||
|
||||
return (this.find("btnsave")).set("onbtclick", e => {
|
||||
return this._api.setting()
|
||||
.then(d => {
|
||||
if (d.error) { return this.error(__("Cannot save system setting: {0}", d.error)); }
|
||||
return this.notify(__("System setting saved"));
|
||||
}).catch(e => {
|
||||
return this.error(__("Cannot save system setting: {0}", e.toString()), e);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Setting.singleton = true;
|
||||
this.OS.register("Setting", Setting);
|
136
src/packages/Setting/main.ts
Normal file
136
src/packages/Setting/main.ts
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS208: Avoid top-level this
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
||||
|
||||
// AnTOS Web desktop is is licensed under the GNU General Public
|
||||
// License v3.0, see the LICENCE file for more information
|
||||
|
||||
// This program is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
namespace OS {
|
||||
export namespace application {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class SettingHandle
|
||||
*/
|
||||
class SettingHandle {
|
||||
protected scheme: HTMLElement;
|
||||
protected parent: Setting;
|
||||
|
||||
/**
|
||||
*Creates an instance of SettingHandle.
|
||||
* @param {HTMLElement} scheme
|
||||
* @param {Setting} parent
|
||||
* @memberof SettingHandle
|
||||
*/
|
||||
constructor(scheme: HTMLElement, parent: Setting) {
|
||||
this.scheme = scheme;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @param {string} id
|
||||
* @returns
|
||||
* @memberof SettingHandle
|
||||
*/
|
||||
protected find(id: string) {
|
||||
if (this.scheme) {
|
||||
return $(`[data-id='${id}']`, this.scheme)[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @memberof SettingHandle
|
||||
*/
|
||||
protected render() : void {};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @export
|
||||
* @class Setting
|
||||
* @extends {BaseApplication}
|
||||
*/
|
||||
export class Setting extends BaseApplication {
|
||||
//private containter: GUI.tag.TabContainerTag;
|
||||
static AppearanceHandle: typeof SettingHandle;
|
||||
static VFSHandle: typeof SettingHandle;
|
||||
static LocaleHandle: typeof SettingHandle;
|
||||
static StartupHandle: typeof SettingHandle;
|
||||
static SettingHandle: typeof SettingHandle;
|
||||
|
||||
/**
|
||||
*Creates an instance of Setting.
|
||||
* @param {AppArgumentsType[]} args
|
||||
* @memberof Setting
|
||||
*/
|
||||
constructor(args: AppArgumentsType[]) {
|
||||
super("Setting", args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @memberof Setting
|
||||
*/
|
||||
main(): void{
|
||||
//this.containter = this.find("container") as GUI.tag.TabContainerTag;
|
||||
|
||||
new Setting.AppearanceHandle(this.find("appearance"), this);
|
||||
new Setting.VFSHandle(this.find("vfs"), this);
|
||||
new Setting.LocaleHandle(this.find("locale"), this);
|
||||
new Setting.StartupHandle(this.find("startup"), this);
|
||||
|
||||
(this.find("btnsave") as GUI.tag.ButtonTag ).onbtclick = (e) => {
|
||||
this._api
|
||||
.setting()
|
||||
.then((d) => {
|
||||
if (d.error) {
|
||||
return this.error(
|
||||
__(
|
||||
"Cannot save system setting: {0}",
|
||||
d.error
|
||||
)
|
||||
);
|
||||
}
|
||||
return this.notify(__("System setting saved"));
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.error(
|
||||
__(
|
||||
"Cannot save system setting: {0}",
|
||||
e.toString()
|
||||
),
|
||||
e
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
Setting.singleton = true;
|
||||
Setting.SettingHandle = SettingHandle;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ namespace OS {
|
||||
});
|
||||
}
|
||||
|
||||
awake(e: GUI.TagEventType): void {
|
||||
awake(e: GUI.TagEventType<GUI.tag.MenuEventData>): void {
|
||||
this.openDialog("CalendarDialog").then((d) => console.log(d));
|
||||
}
|
||||
// do nothing
|
||||
|
@ -226,7 +226,7 @@ namespace OS {
|
||||
* @param {GUI.TagEventType} evt
|
||||
* @memberof PushNotification
|
||||
*/
|
||||
awake(evt: GUI.TagEventType): void {
|
||||
awake(evt: GUI.TagEventType<GUI.tag.MenuEventData>): void {
|
||||
if (this.view) {
|
||||
$(this.nzone).hide();
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user