switch to es6 from coffeescript

This commit is contained in:
Xuan Sang LE
2020-05-24 13:17:59 +02:00
parent f11509120e
commit 759cd1fc6f
122 changed files with 10658 additions and 8702 deletions

View File

@ -1,6 +1,6 @@
coffee_files = dialog.coffee main.coffee
module_files = dialog.js main.js
jsfiles =
libfiles =
cssfiles = main.css

View File

@ -1,84 +0,0 @@
# 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()
@list = @find "list"
$((@find "btnOk")).hide()
@list.set "buttons", [
{
text: "+",
onbtclick: () =>
@openDialog("PromptDialog", {
title: __("Add repository"),
label: __("Format : [name] url")
}).then (e) =>
m = e.match /\[([^\]]*)\]\s*(.+)/
if not m or m.length isnt 3
return @error __("Wrong format: it should be [name] url")
repo = {
url: m[2],
text: m[1]
}
@systemsetting.system.repositories.push repo
@list.push repo
},
{
text: "-",
onbtclick: () =>
el = @list.get "selectedItem"
return unless el
selidx = $(el).index()
return unless selidx >= 0
@systemsetting.system.repositories.splice selidx, selidx
@list.remove el
},
{
iconclass: "fa fa-pencil",
onbtclick: () => @editRepo()
}
]
editRepo: () ->
el = @list.get "selectedItem"
return unless el
selidx = $(el).index()
return unless selidx >= 0
data = el.get "data"
sel = @systemsetting.system.repositories[selidx]
@openDialog("PromptDialog", {
title: __("Edit repository"),
label: __("Format : [name] url"),
value: "[#{data.text}] #{data.url}"
}).then (e) =>
m = e.match /\[([^\]]*)\]\s*(.+)/
if not m or m.length isnt 3
return @error __("Wrong format: it should be [name] url")
data.text = m[1]
data.url = m[2]
@list.update()
@list.unselect()
onexit: (e) ->
@parent.refreshRepoList()
super.onexit e

View File

@ -0,0 +1,100 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
//along with this program. If not, see https://www.gnu.org/licenses/.
class RepositoryDialog extends this.OS.GUI.subwindows.SelectionDialog {
constructor() {
super();
}
main() {
super.main();
this.list = this.find("list");
$((this.find("btnOk"))).hide();
return this.list.set("buttons", [
{
text: "+",
onbtclick: () => {
return this.openDialog("PromptDialog", {
title: __("Add repository"),
label: __("Format : [name] url")
}).then(e => {
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
if (!m || (m.length !== 3)) {
return this.error(__("Wrong format: it should be [name] url"));
}
const repo = {
url: m[2],
text: m[1]
};
this.systemsetting.system.repositories.push(repo);
return this.list.push(repo);
});
}
},
{
text: "-",
onbtclick: () => {
const el = this.list.get("selectedItem");
if (!el) { return; }
const selidx = $(el).index();
if (!(selidx >= 0)) { return; }
this.systemsetting.system.repositories.splice(selidx, selidx);
return this.list.remove(el);
}
},
{
iconclass: "fa fa-pencil",
onbtclick: () => this.editRepo()
}
]);
}
editRepo() {
const el = this.list.get("selectedItem");
if (!el) { return; }
const selidx = $(el).index();
if (!(selidx >= 0)) { return; }
const data = el.get("data");
const sel = this.systemsetting.system.repositories[selidx];
return this.openDialog("PromptDialog", {
title: __("Edit repository"),
label: __("Format : [name] url"),
value: `[${data.text}] ${data.url}`
}).then(e => {
const m = e.match(/\[([^\]]*)\]\s*(.+)/);
if (!m || (m.length !== 3)) {
return this.error(__("Wrong format: it should be [name] url"));
}
data.text = m[1];
data.url = m[2];
this.list.update();
return this.list.unselect();
});
}
onexit(e) {
this.parent.refreshRepoList();
return super.onexit(e);
}
}

View File

@ -1,357 +0,0 @@
# 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: () ->
@installdir = @systemsetting.system.pkgpaths.user
# test repository
@apps_meta = []
@repo = @find "repo"
@repo.set "onlistselect", (e) =>
data = e.data.item.get("data")
return unless data
@fetchApps data
@refreshRepoList()
@applist = @find "applist"
@applist.set "onlistselect", (e) =>
data = e.data.item.get("data")
@appDetail data
@container = @find "container"
@appname = @find "appname"
@appdesc = @find "app-desc"
@appdetail = @find "app-detail"
@btinstall = @find "bt-install"
@btremove = @find "bt-remove"
@btexec = @find "bt-exec"
@searchbox = @find "searchbox"
($ @container).css "visibility", "hidden"
@btexec.set "onbtclick", (e) =>
el = @applist.get "selectedItem"
return unless el
app = el.get("data")
@_gui.launch app.pkgname if app.pkgname
@btinstall.set "onbtclick", (e) =>
if @btinstall.get "dirty"
return @updatePackage()
.then () => @notify __("Package updated")
.catch (e) => @error e.toString(), e
@remoteInstall()
.then (n) => @notify __("Package installed: {0}", n)
.catch (e) => @error e.toString(), e
@btremove.set "onbtclick", (e) =>
@uninstall()
.then () => @notify __("Packaged uninstalled")
.catch (e) => @error e.toString(), e
@bindKey "CTRL-R", () =>
@menuOptionsHandle "repos"
$(@searchbox).keyup (e) => @search e
refreshRepoList: () ->
list = (v for v in @systemsetting.system.repositories)
list.unshift {
text: "Installed"
}
@repo.set "data", list
search: (e) ->
switch e.which
when 37
e.preventDefault()
when 38
@applist.selectPrev()
e.preventDefault()
when 39
e.preventDefault()
when 40
@applist.selectNext()
e.preventDefault()
when 13
e.preventDefault()
else
text = @searchbox.value
@applist.set "data", (v for v in @apps_meta) if text.length is 2
return if text.length < 3
result = []
term = new RegExp text, 'i'
result.push v for v in @apps_meta when v.text.match term
@applist.set "data", result
fetchApps: (data) ->
if not data.url
pkgcache = @systemsetting.system.packages
list = []
for k, v of pkgcache
list.push {
pkgname: if v.pkgname then v.pkgname else 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"
}
@apps_meta = list
@applist.set "data", list
return
@_api.get (data.url + "?_=" + (new Date().getTime())) , "json"
.then ( d ) =>
for v in d
v.text = v.name
v.iconclass = "fa fa-adn"
@apps_meta = d
@applist.set "data", d
.catch (e) =>
@error __("Fail to fetch packages list from: {0}", data.url), e
appDetail: (d) ->
($ @container).css "visibility", "visible"
( $ @appname ).html d.name
(@find "vstat").set "text", ""
if d.description
d.description.asFileHandle().read().then (text) =>
converter = new showdown.Converter()
($ @appdesc).html(converter.makeHtml text)
.catch (e) =>
@notify __("Unable to read package description")
($ @appdesc).empty()
else
($ @appdesc).empty()
pkgcache = @systemsetting.system.packages
@btinstall.set "text", "__(Install)"
@btinstall.set "dirty", false
if pkgcache[d.pkgname]
vs = pkgcache[d.pkgname].version
ovs = d.version
($ @btinstall).hide()
if vs and ovs
vs = vs.__v()
ovs = ovs.__v()
if ovs.nt vs
@btinstall.set "dirty", true
@btinstall.set "text", "__(Update)"
($ @btinstall).show()
(@find "vstat").set "text",
__("Your application version is older ({0} < {1})", vs, ovs)
($ @btremove).show()
($ @btexec).show()
else
($ @btinstall).show()
($ @btremove).hide()
($ @btexec).hide()
($ @appdetail).empty()
for k, v of d when k isnt "name" and k isnt "description" and k isnt "domel"
($ @appdetail).append(
$("<li>")
.append(($ "<span class= 'info-header'>").html k)
.append $("<span>").html v
)
menu: () ->
return [
{
text: "__(Options)", child: [
{ text: "__(Repositories)", shortcut: "C-R", id: "repos" },
{ text: "__(Install from zip)", shortcut: "C-I", id: "install" }
] , onchildselect: (e) =>
@menuOptionsHandle e.data.item.get("data").id
}
]
menuOptionsHandle: (id) ->
switch id
when "repos"
@openDialog new RepositoryDialog(), {
title: __("Repositories"),
data: @systemsetting.system.repositories
}
when "install"
@localInstall().then (n) =>
@notify __("Package installed: {0}", n)
.catch (e) => @error __("Unable to install package"), e
else
remoteInstall: () ->
el = @applist.get "selectedItem"
return unless el
app = el.get "data"
return unless app
# get blob file
new Promise (resolve, reject) =>
@_api.blob app.download + "?_=" + (new Date().getTime())
.then (data) =>
@install data, app
.then (n) -> resolve(n)
.catch (e) -> reject(__e e)
.catch (e) -> reject __e e
localInstall: () ->
new Promise (resolve, reject) =>
@openDialog("FileDialog", {
title: "__(Select package archive)",
mimes: [".*/zip"]
}).then (d) =>
d.file.path.asFileHandle().read("binary").then (data) =>
@install data
.then (n) =>
@repo.unselect()
@repo.set "selected", 0
apps = (v.pkgname for v in @applist.get("data"))
idx = apps.indexOf n
if idx >= 0
@applist.set "selected", idx
resolve(n)
.catch (e) -> reject(__e e)
.catch (e) -> reject __e e
.catch (e) -> reject __e e
install: (data, meta) ->
new Promise (resolve, reject) =>
JSZip.loadAsync(data).then (zip) =>
zip.file("package.json").async("string").then (d) =>
v = JSON.parse d
pth = "#{@installdir}/#{v.app}"
dir = [pth]
files = []
for name, file of zip.files
if file.dir
dir.push(pth + "/" + name)
else
files.push name
# create all directory
@mkdirs(dir).then () =>
@installFile(v.app, zip, files).then () =>
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: if meta then meta.description else undefined,
download: if meta then meta.download else undefined
}
v.text = v.name
v.filename = v.app
v.type = "app"
v.mime = "antos/app"
v.iconclass = "fa fa-adn" unless v.iconclass or v.icon
v.path = pth
@systemsetting.system.packages[v.app] = v
@appDetail app_meta
resolve(v.name)
.catch (e) -> reject __e e
.catch (e) -> reject __e e
.catch (err) -> reject __e err
.catch (e) -> reject __e e
uninstall: () ->
new Promise (resolve, reject) =>
el = @applist.get "selectedItem"
return unless el
sel = el.get "data"
return unless sel
name = sel.pkgname
app = @systemsetting.system.packages[sel.pkgname]
return unless app
@openDialog("YesNoDialog", {
title: __("Uninstall") ,
text: __("Uninstall: {0}?", app.name)
}).then (d) =>
return unless d
app.path.asFileHandle().remove().then (r) =>
if r.error
return reject @_api.throwe __("Cannot uninstall package: {0}", r.error)
@notify __("Package uninstalled")
# stop all the services if any
if app.services
for srv in app.services
@_gui.unloadApp srv
delete @systemsetting.system.packages[name]
@_gui.unloadApp name
if sel.download
@appDetail sel
else
@applist.remove el
($ @container).css "visibility", "hidden"
resolve()
.catch (e) -> reject __e e
.catch (e) -> reject __e e
updatePackage: () ->
new Promise (resolve, reject) =>
@uninstall().then () =>
@remoteInstall()
.then () -> resolve()
.catch (e) -> reject __e e
.catch (e) -> reject __e e
mkdirs: (list) ->
new Promise (resolve, reject) =>
return resolve() if list.length is 0
dir = (list.splice 0, 1)[0].asFileHandle()
path = dir.parent()
dname = dir.basename
path.asFileHandle().mk dname
.then (r) =>
return reject(@_api.throwe __("Cannot create {0}", "#{path}/#{dir}")) if r.error
@mkdirs list
.then () -> resolve()
.catch (e) -> reject __e e
.catch (e) -> reject __e e
installFile: (n, zip, files) ->
new Promise (resolve, reject) =>
return resolve() if files.length is 0
file = (files.splice 0, 1)[0]
path = "#{@installdir}/#{n}/#{file}"
zip.file(file).async("uint8array").then (d) =>
fp = path.asFileHandle()
fp.cache = new Blob [d], { type: "octet/stream" }
fp.write "text/plain"
.then (r) =>
return reject @_api.throwe(__("Cannot install {0}", path)) if r.error
@installFile n, zip, files
.then () -> resolve()
.catch (e) -> reject( __e e)
.catch (e) -> reject __e e
.catch (e) -> reject __e e
MarketPlace.dependencies = [
"os://scripts/jszip.min.js",
"os://scripts/showdown.min.js"
]
MarketPlace.singleton = true
this.OS.register "MarketPlace", MarketPlace

View File

@ -0,0 +1,433 @@
/*
* 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);