mirror of
https://github.com/lxsang/antos-frontend.git
synced 2024-12-26 01:18:21 +01:00
add more test, convert CodePad to type scipt
This commit is contained in:
parent
af496b0aac
commit
6e95994892
2
Makefile
2
Makefile
@ -48,7 +48,7 @@ javascripts= dist/core/core.js \
|
|||||||
dist/core/pm.js \
|
dist/core/pm.js \
|
||||||
dist/bootstrap.js
|
dist/bootstrap.js
|
||||||
|
|
||||||
packages = Syslog #Files Setting CodePad MarketPlace
|
packages = Syslog CodePad#Files Setting MarketPlace
|
||||||
|
|
||||||
main: initd build_javascripts build_themes libs build_packages languages
|
main: initd build_javascripts build_themes libs build_packages languages
|
||||||
- cp src/index.html $(BUILDDIR)/
|
- cp src/index.html $(BUILDDIR)/
|
||||||
|
@ -157,7 +157,7 @@ namespace OS {
|
|||||||
trigger(evtName: string, data: any): void {
|
trigger(evtName: string, data: any): void {
|
||||||
const trig = (name: string, d: any) => {
|
const trig = (name: string, d: any) => {
|
||||||
const names = [name, "*"];
|
const names = [name, "*"];
|
||||||
for (let evt of Array.from(names)) {
|
for (let evt of names) {
|
||||||
if (!this.observable[evt]) {
|
if (!this.observable[evt]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ namespace OS {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i of Array.from(announcer.listeners[app.pid])) {
|
for (let i of announcer.listeners[app.pid]) {
|
||||||
announcer.observable.off(i.e, i.f);
|
announcer.observable.off(i.e, i.f);
|
||||||
}
|
}
|
||||||
delete announcer.listeners[app.pid];
|
delete announcer.listeners[app.pid];
|
||||||
|
@ -211,6 +211,10 @@ namespace OS {
|
|||||||
this.host
|
this.host
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.error(__("Unable to find dialog scheme"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -846,7 +850,7 @@ namespace OS {
|
|||||||
if (!e || !e.data.item) {
|
if (!e || !e.data.item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setroot(e.data.item.get("data").path);
|
setroot(e.data.item.data.path);
|
||||||
};
|
};
|
||||||
location.data = this.systemsetting.VFS.mountpoints.filter(
|
location.data = this.systemsetting.VFS.mountpoints.filter(
|
||||||
(i) => i.type !== "app"
|
(i) => i.type !== "app"
|
||||||
@ -884,7 +888,7 @@ namespace OS {
|
|||||||
//verify the mime
|
//verify the mime
|
||||||
let m = false;
|
let m = false;
|
||||||
if (f.mime) {
|
if (f.mime) {
|
||||||
for (let v of Array.from(this.data.mimes)) {
|
for (let v of this.data.mimes) {
|
||||||
if (
|
if (
|
||||||
f.mime.match(
|
f.mime.match(
|
||||||
new RegExp(v as string, "g")
|
new RegExp(v as string, "g")
|
||||||
|
@ -378,7 +378,8 @@ namespace OS {
|
|||||||
|
|
||||||
Object.defineProperty(Object.prototype, "__", {
|
Object.defineProperty(Object.prototype, "__", {
|
||||||
value() {
|
value() {
|
||||||
return this.toString();
|
if(this)
|
||||||
|
return this.toString();
|
||||||
},
|
},
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: true,
|
writable: true,
|
||||||
|
@ -44,7 +44,7 @@ namespace OS {
|
|||||||
* @interface BasicItemType
|
* @interface BasicItemType
|
||||||
*/
|
*/
|
||||||
export interface BasicItemType {
|
export interface BasicItemType {
|
||||||
text: string;
|
text: string | FormatedString;
|
||||||
children?: BasicItemType[];
|
children?: BasicItemType[];
|
||||||
nodes?: BasicItemType[];
|
nodes?: BasicItemType[];
|
||||||
[propName: string]: any;
|
[propName: string]: any;
|
||||||
@ -190,7 +190,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
let m: API.PackageMetaType;
|
let m: API.PackageMetaType;
|
||||||
const mimes: Array<string[]> = [];
|
const mimes: Array<string[]> = [];
|
||||||
for (m of Array.from(metas)) {
|
for (m of metas) {
|
||||||
if (m) {
|
if (m) {
|
||||||
mimes.push(m.mimes);
|
mimes.push(m.mimes);
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ namespace OS {
|
|||||||
if (apps.length === 1) {
|
if (apps.length === 1) {
|
||||||
return launch(apps[0].app, [it]);
|
return launch(apps[0].app, [it]);
|
||||||
}
|
}
|
||||||
const list = Array.from(apps).map((e) => ({
|
const list = apps.map((e) => ({
|
||||||
text: e.app,
|
text: e.app,
|
||||||
icon: e.icon,
|
icon: e.icon,
|
||||||
iconclass: e.iconclass,
|
iconclass: e.iconclass,
|
||||||
@ -1041,17 +1041,16 @@ namespace OS {
|
|||||||
pushServices(
|
pushServices(
|
||||||
(() => {
|
(() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
for (let v of Array.from(
|
for (let v of
|
||||||
setting.system.startup.services
|
setting.system.startup.services
|
||||||
)) {
|
) {
|
||||||
result.push(v);
|
result.push(v);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
return Array.from(
|
return
|
||||||
setting.system.startup.apps
|
setting.system.startup.apps.map((a) => launch(a, []));
|
||||||
).map((a) => launch(a, []));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ namespace OS {
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
if (metaclass.dependencies) {
|
if (metaclass.dependencies) {
|
||||||
const libs = Array.from(metaclass.dependencies);
|
const libs = metaclass.dependencies;
|
||||||
return API.require(libs)
|
return API.require(libs)
|
||||||
.then(() => resolve(f()))
|
.then(() => resolve(f()))
|
||||||
.catch((e: Error) => reject(__e(e)));
|
.catch((e: Error) => reject(__e(e)));
|
||||||
@ -77,7 +77,7 @@ namespace OS {
|
|||||||
export function appByPid(pid: number): BaseModel {
|
export function appByPid(pid: number): BaseModel {
|
||||||
let app = undefined;
|
let app = undefined;
|
||||||
const find = function (l: Array<any>) {
|
const find = function (l: Array<any>) {
|
||||||
for (let a of Array.from(l)) {
|
for (let a of l) {
|
||||||
if (a.pid === pid) {
|
if (a.pid === pid) {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ namespace OS {
|
|||||||
if (!PM.processes[app]) {
|
if (!PM.processes[app]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Array.from(PM.processes[app]).map((a) => a.quit(force));
|
PM.processes[app].map((a) => a.quit(force));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ namespace OS {
|
|||||||
v1.complex = true;
|
v1.complex = true;
|
||||||
ar.push(v1);
|
ar.push(v1);
|
||||||
} else if (v.mimes) {
|
} else if (v.mimes) {
|
||||||
for (let m of Array.from(v.mimes)) {
|
for (let m of v.mimes) {
|
||||||
if (t.match(new RegExp(m, "g"))) {
|
if (t.match(new RegExp(m, "g"))) {
|
||||||
v1 = {};
|
v1 = {};
|
||||||
for (k1 in v) {
|
for (k1 in v) {
|
||||||
|
@ -356,12 +356,13 @@ namespace OS {
|
|||||||
private refreshTree(): void {
|
private refreshTree(): void {
|
||||||
//@treeview.root.set("selectedItem", null)
|
//@treeview.root.set("selectedItem", null)
|
||||||
const tdata: TreeViewDataType = {
|
const tdata: TreeViewDataType = {
|
||||||
name: this.path,
|
text: this.path,
|
||||||
path: this.path,
|
path: this.path,
|
||||||
open: true,
|
open: true,
|
||||||
nodes: this.getTreeData(this.data),
|
nodes: this.getTreeData(this.data)
|
||||||
};
|
};
|
||||||
(this.refs.treeview as TreeViewTag).data = tdata;
|
(this.refs.treeview as TreeViewTag).data = tdata;
|
||||||
|
// (this.refs.treeview as TreeViewTag).expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -381,7 +382,7 @@ namespace OS {
|
|||||||
if (v.filename[0] === "." && !this.showhidden) {
|
if (v.filename[0] === "." && !this.showhidden) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
v.name = v.filename;
|
v.text = v.filename;
|
||||||
if (v.type === "dir") {
|
if (v.type === "dir") {
|
||||||
v.nodes = [];
|
v.nodes = [];
|
||||||
v.open = false;
|
v.open = false;
|
||||||
@ -500,13 +501,13 @@ namespace OS {
|
|||||||
const tree = this.refs.treeview as TreeViewTag;
|
const tree = this.refs.treeview as TreeViewTag;
|
||||||
tree.fetch = (v) => {
|
tree.fetch = (v) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!this.fetch) {
|
if (!this._fetch) {
|
||||||
return resolve(undefined);
|
return resolve(undefined);
|
||||||
}
|
}
|
||||||
if (!v.data.path) {
|
if (!v.data.path) {
|
||||||
return resolve(undefined);
|
return resolve(undefined);
|
||||||
}
|
}
|
||||||
return this.fetch(v.data.path)
|
return this._fetch(v.data.path)
|
||||||
.then((d: API.FileInfoType[]) =>
|
.then((d: API.FileInfoType[]) =>
|
||||||
resolve(
|
resolve(
|
||||||
this.getTreeData(
|
this.getTreeData(
|
||||||
@ -524,25 +525,25 @@ namespace OS {
|
|||||||
list.dragndrop = true;
|
list.dragndrop = true;
|
||||||
// even handles
|
// even handles
|
||||||
list.onlistselect = (e) => {
|
list.onlistselect = (e) => {
|
||||||
this.fileselect(e.data.item.get("data"));
|
this.fileselect(e.data.item.data);
|
||||||
};
|
};
|
||||||
grid.onrowselect = (e) => {
|
grid.onrowselect = (e) => {
|
||||||
this.fileselect(
|
this.fileselect(
|
||||||
$(e.data.item).children()[0].get("data")
|
$(e.data.item).children()[0].data
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
tree.ontreeselect = (e) => {
|
tree.ontreeselect = (e) => {
|
||||||
this.fileselect(e.data.item.get("data"));
|
this.fileselect(e.data.item.data);
|
||||||
};
|
};
|
||||||
// dblclick
|
// dblclick
|
||||||
list.onlistdbclick = (e) => {
|
list.onlistdbclick = (e) => {
|
||||||
this.filedbclick(e.data.item.get("data"));
|
this.filedbclick(e.data.item.data);
|
||||||
};
|
};
|
||||||
grid.oncelldbclick = (e) => {
|
grid.oncelldbclick = (e) => {
|
||||||
this.filedbclick(e.data.item.get("data"));
|
this.filedbclick(e.data.item.data);
|
||||||
};
|
};
|
||||||
tree.ontreedbclick = (e) => {
|
tree.ontreedbclick = (e) => {
|
||||||
this.filedbclick(e.data.item.get("data"));
|
this.filedbclick(e.data.item.data);
|
||||||
};
|
};
|
||||||
this.switchView();
|
this.switchView();
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ namespace OS {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$(this.refs.header).empty();
|
$(this.refs.header).empty();
|
||||||
for (let item of Array.from(v)) {
|
for (let item of v) {
|
||||||
const el = $(`<${this.headeritem}>`).appendTo(
|
const el = $(`<${this.headeritem}>`).appendTo(
|
||||||
this.refs.header
|
this.refs.header
|
||||||
);
|
);
|
||||||
@ -263,7 +263,7 @@ namespace OS {
|
|||||||
el.data = row;
|
el.data = row;
|
||||||
row.domel = rowel[0];
|
row.domel = rowel[0];
|
||||||
|
|
||||||
for (let cell of Array.from(row)) {
|
for (let cell of row) {
|
||||||
let tag = this.cellitem;
|
let tag = this.cellitem;
|
||||||
if (cell.tag) {
|
if (cell.tag) {
|
||||||
({ tag } = cell);
|
({ tag } = cell);
|
||||||
|
@ -497,7 +497,7 @@ namespace OS {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$(this.refs.btlist).empty();
|
$(this.refs.btlist).empty();
|
||||||
for (let item of Array.from(v)) {
|
for (let item of v) {
|
||||||
$(this.refs.btlist).show();
|
$(this.refs.btlist).show();
|
||||||
const bt = $("<afx-button>").appendTo(this.refs.btlist);
|
const bt = $("<afx-button>").appendTo(this.refs.btlist);
|
||||||
(bt[0] as ButtonTag).set(item);
|
(bt[0] as ButtonTag).set(item);
|
||||||
@ -524,7 +524,7 @@ namespace OS {
|
|||||||
this._selectedItem = undefined;
|
this._selectedItem = undefined;
|
||||||
this._selectedItems = [];
|
this._selectedItems = [];
|
||||||
$(this.refs.mlist).empty();
|
$(this.refs.mlist).empty();
|
||||||
for (let item of Array.from(data)) {
|
for (let item of data) {
|
||||||
this.push(item, false);
|
this.push(item, false);
|
||||||
}
|
}
|
||||||
$(this.refs.container).off("mousedown", this._onmousedown);
|
$(this.refs.container).off("mousedown", this._onmousedown);
|
||||||
@ -791,7 +791,7 @@ namespace OS {
|
|||||||
* @memberof ListViewTag
|
* @memberof ListViewTag
|
||||||
*/
|
*/
|
||||||
private idbclick(e: TagEventType) {
|
private idbclick(e: TagEventType) {
|
||||||
const evt = { id: this.aid, data: e };
|
const evt = { id: this.aid, data: { item: e.data } };
|
||||||
this._onlistdbclick(evt);
|
this._onlistdbclick(evt);
|
||||||
return this.observable.trigger("listdbclick", evt);
|
return this.observable.trigger("listdbclick", evt);
|
||||||
}
|
}
|
||||||
@ -943,7 +943,7 @@ namespace OS {
|
|||||||
if (!e.data) {
|
if (!e.data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const evt = { id: this.aid, data: e };
|
const evt = { id: this.aid, data: {item: e.data} };
|
||||||
const r = this._onitemclose(evt);
|
const r = this._onitemclose(evt);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
return;
|
return;
|
||||||
|
@ -16,7 +16,6 @@ namespace OS {
|
|||||||
* @extends {AFXTag}
|
* @extends {AFXTag}
|
||||||
*/
|
*/
|
||||||
export class TabBarTag extends AFXTag {
|
export class TabBarTag extends AFXTag {
|
||||||
private _items: GenericObject<any>[];
|
|
||||||
private _selected: number;
|
private _selected: number;
|
||||||
private _ontabclose: (e: TagEventType) => boolean;
|
private _ontabclose: (e: TagEventType) => boolean;
|
||||||
private _ontabselect: TagEventCallback;
|
private _ontabselect: TagEventCallback;
|
||||||
@ -29,7 +28,6 @@ namespace OS {
|
|||||||
super();
|
super();
|
||||||
this._ontabclose = (e) => true;
|
this._ontabclose = (e) => true;
|
||||||
this._ontabselect = (e) => {};
|
this._ontabselect = (e) => {};
|
||||||
this._items = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,7 +106,6 @@ namespace OS {
|
|||||||
* @memberof TabBarTag
|
* @memberof TabBarTag
|
||||||
*/
|
*/
|
||||||
set items(v: GenericObject<any>[]) {
|
set items(v: GenericObject<any>[]) {
|
||||||
this._items = v;
|
|
||||||
for (let i of v) {
|
for (let i of v) {
|
||||||
i.closable = this.closable;
|
i.closable = this.closable;
|
||||||
}
|
}
|
||||||
@ -122,7 +119,7 @@ namespace OS {
|
|||||||
* @memberof TabBarTag
|
* @memberof TabBarTag
|
||||||
*/
|
*/
|
||||||
get items(): GenericObject<any>[] {
|
get items(): GenericObject<any>[] {
|
||||||
return this._items;
|
return (this.refs.list as ListViewTag).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,7 +149,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HBoxTag extends TileLayoutTag {
|
export class HBoxTag extends TileLayoutTag {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VBoxTag extends TileLayoutTag {
|
export class VBoxTag extends TileLayoutTag {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ namespace OS {
|
|||||||
this.treepath = v.path;
|
this.treepath = v.path;
|
||||||
}
|
}
|
||||||
this.selected = v.selected;
|
this.selected = v.selected;
|
||||||
|
v.domel = this;
|
||||||
this.ondatachange();
|
this.ondatachange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +172,15 @@ namespace OS {
|
|||||||
$(this.refs.toggle).addClass("afx-tree-view-folder-close");
|
$(this.refs.toggle).addClass("afx-tree-view-folder-close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof TreeViewItemPrototype
|
||||||
|
*/
|
||||||
|
get open(): boolean {
|
||||||
|
return this.hasattr("open");
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@ -264,7 +274,7 @@ namespace OS {
|
|||||||
id: this.aid,
|
id: this.aid,
|
||||||
data: { item: this, dblclick: false },
|
data: { item: this, dblclick: false },
|
||||||
};
|
};
|
||||||
this.indent = 0;
|
this._indent = 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -602,7 +612,7 @@ namespace OS {
|
|||||||
if (e.data.item === this.selectedItem && !e.data.dblclick) {
|
if (e.data.item === this.selectedItem && !e.data.dblclick) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.selectedItem = e.data.item;
|
this._selectedItem = e.data.item;
|
||||||
const evt = { id: this.aid, data: e.data };
|
const evt = { id: this.aid, data: e.data };
|
||||||
if (e.data.dblclick) {
|
if (e.data.dblclick) {
|
||||||
this._ontreedbclick(evt);
|
this._ontreedbclick(evt);
|
||||||
@ -666,7 +676,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
let tag = this.itemtag;
|
let tag = this.itemtag;
|
||||||
if (v.tag) {
|
if (v.tag) {
|
||||||
({ tag } = v);
|
tag = v.tag;
|
||||||
}
|
}
|
||||||
const el = $(`<${tag}>`).appendTo(this);
|
const el = $(`<${tag}>`).appendTo(this);
|
||||||
el[0].uify(this.observable);
|
el[0].uify(this.observable);
|
||||||
|
@ -169,7 +169,7 @@ namespace OS {
|
|||||||
$(dom).attr("tooltip", tag.tooltip.__());
|
$(dom).attr("tooltip", tag.tooltip.__());
|
||||||
}
|
}
|
||||||
if (tag.children) {
|
if (tag.children) {
|
||||||
for (let v of Array.from(tag.children)) {
|
for (let v of tag.children) {
|
||||||
$(this.mkui(v)).appendTo(dom);
|
$(this.mkui(v)).appendTo(dom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,6 @@ namespace OS {
|
|||||||
basename: string;
|
basename: string;
|
||||||
info: FileInfoType;
|
info: FileInfoType;
|
||||||
ext: string;
|
ext: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Creates an instance of BaseFileHandle.
|
*Creates an instance of BaseFileHandle.
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
@ -708,7 +707,7 @@ namespace OS {
|
|||||||
* @class RemoteFileHandle
|
* @class RemoteFileHandle
|
||||||
* @extends {BaseFileHandle}
|
* @extends {BaseFileHandle}
|
||||||
*/
|
*/
|
||||||
class RemoteFileHandle extends BaseFileHandle {
|
export class RemoteFileHandle extends BaseFileHandle {
|
||||||
constructor(path: string) {
|
constructor(path: string) {
|
||||||
super(path);
|
super(path);
|
||||||
}
|
}
|
||||||
@ -1021,7 +1020,7 @@ namespace OS {
|
|||||||
* @class ApplicationHandle
|
* @class ApplicationHandle
|
||||||
* @extends {BaseFileHandle}
|
* @extends {BaseFileHandle}
|
||||||
*/
|
*/
|
||||||
class ApplicationHandle extends BaseFileHandle {
|
export class ApplicationHandle extends BaseFileHandle {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Creates an instance of ApplicationHandle.
|
*Creates an instance of ApplicationHandle.
|
||||||
@ -1099,7 +1098,7 @@ namespace OS {
|
|||||||
* @class BufferFileHandle
|
* @class BufferFileHandle
|
||||||
* @extends {BaseFileHandle}
|
* @extends {BaseFileHandle}
|
||||||
*/
|
*/
|
||||||
class BufferFileHandle extends BaseFileHandle {
|
export class BufferFileHandle extends BaseFileHandle {
|
||||||
constructor(path: string, mime: string, data: any) {
|
constructor(path: string, mime: string, data: any) {
|
||||||
super(path);
|
super(path);
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -1188,7 +1187,7 @@ namespace OS {
|
|||||||
* @class URLFileHandle
|
* @class URLFileHandle
|
||||||
* @extends {BaseFileHandle}
|
* @extends {BaseFileHandle}
|
||||||
*/
|
*/
|
||||||
class URLFileHandle extends BaseFileHandle {
|
export class URLFileHandle extends BaseFileHandle {
|
||||||
constructor(path: string) {
|
constructor(path: string) {
|
||||||
super(path);
|
super(path);
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
@ -1228,7 +1227,7 @@ namespace OS {
|
|||||||
* @class SharedFileHandle
|
* @class SharedFileHandle
|
||||||
* @extends {API.VFS.BaseFileHandle}
|
* @extends {API.VFS.BaseFileHandle}
|
||||||
*/
|
*/
|
||||||
class SharedFileHandle extends API.VFS.BaseFileHandle {
|
export class SharedFileHandle extends API.VFS.BaseFileHandle {
|
||||||
constructor(path: string) {
|
constructor(path: string) {
|
||||||
super(path);
|
super(path);
|
||||||
if (this.isRoot()) {
|
if (this.isRoot()) {
|
||||||
|
383
src/packages/CodePad/AntOSDK.ts
Normal file
383
src/packages/CodePad/AntOSDK.ts
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
namespace OS {
|
||||||
|
// import the CodePad application module
|
||||||
|
const App = OS.application.CodePad;
|
||||||
|
|
||||||
|
declare var CoffeeScript: any;
|
||||||
|
declare var JSZip: any;
|
||||||
|
declare var Terser: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @class AntOSDK
|
||||||
|
* @extends {App.BaseExtension}
|
||||||
|
*/
|
||||||
|
class AntOSDK extends App.BaseExtension {
|
||||||
|
/**
|
||||||
|
*Creates an instance of AntOSDK.
|
||||||
|
* @param {application.CodePad} app
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
constructor(app: application.CodePad) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public functions
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
create(): void {
|
||||||
|
this.app
|
||||||
|
.openDialog("FileDialog", {
|
||||||
|
title: "__(New Project at)",
|
||||||
|
file: { basename: __("ProjectName") },
|
||||||
|
mimes: ["dir"],
|
||||||
|
})
|
||||||
|
.then((d) => {
|
||||||
|
return this.mktpl(d.file.path, d.name, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
init(): void {
|
||||||
|
const dir = this.app.currdir;
|
||||||
|
if (!dir || !dir.basename) {
|
||||||
|
return this.create();
|
||||||
|
}
|
||||||
|
dir.read().then((d) => {
|
||||||
|
if (d.error) {
|
||||||
|
return this.notify(__("Cannot read folder: {0}", dir.path));
|
||||||
|
}
|
||||||
|
if (d.result.length !== 0) {
|
||||||
|
return this.notify(
|
||||||
|
__("The folder is not empty: {0}", dir.path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.mktpl(dir.parent().path, dir.basename);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
buildnrun(): void {
|
||||||
|
this.metadata("project.json")
|
||||||
|
.then(async (meta) => {
|
||||||
|
try {
|
||||||
|
await this.build(meta, true);
|
||||||
|
try {
|
||||||
|
return this.run(meta);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(__("Unable to run project"), e);
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return this.error(__("Unable to build project"), e_1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => this.error(__("Unable to read meta-data"), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
release(): void {
|
||||||
|
this.metadata("project.json")
|
||||||
|
.then(async (meta) => {
|
||||||
|
try {
|
||||||
|
await this.build(meta, false);
|
||||||
|
try {
|
||||||
|
return this.mkar(
|
||||||
|
`${meta.root}/build/debug`,
|
||||||
|
`${meta.root}/build/release/${meta.name}.zip`
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(
|
||||||
|
__("Unable to create package archive"),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return this.error(__("Unable to build project"), e_1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => this.error(__("Unable to read meta-data"), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// private functions
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} path
|
||||||
|
* @param {string} name
|
||||||
|
* @param {boolean} [flag]
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
private mktpl(path: string, name: string, flag?: boolean): void {
|
||||||
|
const rpath = `${path}/${name}`;
|
||||||
|
const dirs = [
|
||||||
|
`${rpath}/javascripts`,
|
||||||
|
`${rpath}/css`,
|
||||||
|
`${rpath}/coffees`,
|
||||||
|
`${rpath}/assets`,
|
||||||
|
];
|
||||||
|
if (flag) {
|
||||||
|
dirs.unshift(rpath);
|
||||||
|
}
|
||||||
|
const files = [
|
||||||
|
["templates/sdk-main.tpl", `${rpath}/coffees/main.coffee`],
|
||||||
|
["templates/sdk-package.tpl", `${rpath}/package.json`],
|
||||||
|
["templates/sdk-project.tpl", `${rpath}/project.json`],
|
||||||
|
["templates/sdk-README.tpl", `${rpath}/README.md`],
|
||||||
|
["templates/sdk-scheme.tpl", `${rpath}/assets/scheme.html`],
|
||||||
|
];
|
||||||
|
this.mkdirAll(dirs)
|
||||||
|
.then(async () => {
|
||||||
|
try {
|
||||||
|
await this.mkfileAll(files, path, name);
|
||||||
|
this.app.currdir = rpath.asFileHandle();
|
||||||
|
this.app.initSideBar();
|
||||||
|
return this.app.openFile(
|
||||||
|
`${rpath}/README.md`.asFileHandle() as application.CodePadFileHandle
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(
|
||||||
|
__("Unable to create template files"),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) =>
|
||||||
|
this.error(__("Unable to create project directory"), e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string[]} list
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
private verify(list: string[]): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const file = list.splice(0, 1)[0].asFileHandle();
|
||||||
|
this.notify(__("Verifying: {0}", file.path));
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then((data) => {
|
||||||
|
try {
|
||||||
|
CoffeeScript.nodes(data);
|
||||||
|
return this.verify(list)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
} catch (ex) {
|
||||||
|
return reject(__e(ex));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
private compile(meta: GenericObject<any>): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
await this.import([
|
||||||
|
`${this.basedir()}/libs/coffeescript.js`,
|
||||||
|
`${this.basedir()}/libs/terser.min.js`,
|
||||||
|
]);
|
||||||
|
const list = meta.coffees.map(
|
||||||
|
(v: string) => `${meta.root}/${v}`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await this.verify(list.map((x: string) =>x));
|
||||||
|
try {
|
||||||
|
const code = await this.cat(list, "");
|
||||||
|
const jsrc = CoffeeScript.compile(code);
|
||||||
|
this.notify(__("Compiled successful"));
|
||||||
|
return resolve(jsrc);
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
} catch (e_2) {
|
||||||
|
return reject(__e(e_2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @param {boolean} debug
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
private build(meta: GenericObject<any>, debug: boolean): Promise<any> {
|
||||||
|
const dirs = [
|
||||||
|
`${meta.root}/build`,
|
||||||
|
`${meta.root}/build/debug`,
|
||||||
|
`${meta.root}/build/release`,
|
||||||
|
];
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
await this.mkdirAll(dirs);
|
||||||
|
try {
|
||||||
|
const src = await this.compile(meta);
|
||||||
|
let v: string;
|
||||||
|
try {
|
||||||
|
let jsrc = await this.cat(
|
||||||
|
(() => {
|
||||||
|
const result = [];
|
||||||
|
for (v of meta.javascripts) {
|
||||||
|
result.push(`${meta.root}/${v}`);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})(),
|
||||||
|
src
|
||||||
|
);
|
||||||
|
await new Promise(async function (r, e) {
|
||||||
|
let code = jsrc;
|
||||||
|
if (!debug) {
|
||||||
|
const options = {
|
||||||
|
toplevel: true,
|
||||||
|
compress: {
|
||||||
|
passes: 3,
|
||||||
|
},
|
||||||
|
mangle: true,
|
||||||
|
output: {
|
||||||
|
//beautify: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result_1 = Terser.minify(
|
||||||
|
jsrc,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
if (result_1.error) {
|
||||||
|
this.notify(
|
||||||
|
__(
|
||||||
|
"Unable to minify code: {0}",
|
||||||
|
result_1.error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
({ code } = result_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const d = await `${meta.root}/build/debug/main.js`
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(code)
|
||||||
|
.write("text/plain");
|
||||||
|
return r();
|
||||||
|
} catch (ex) {
|
||||||
|
return e(__e(ex));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await new Promise(async (r, e) => {
|
||||||
|
const txt = await this.cat(
|
||||||
|
(() => {
|
||||||
|
const result1 = [];
|
||||||
|
for (v of meta.css) {
|
||||||
|
result1.push(`${meta.root}/${v}`);
|
||||||
|
}
|
||||||
|
return result1;
|
||||||
|
})(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
if (txt === "") {
|
||||||
|
return r();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const d_1 = await `${meta.root}/build/debug/main.css`
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(txt)
|
||||||
|
.write("text/plain");
|
||||||
|
return r();
|
||||||
|
} catch (ex_1) {
|
||||||
|
return e(__e(ex_1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await this.copy(
|
||||||
|
(() => {
|
||||||
|
const result1_1 = [];
|
||||||
|
for (v of meta.copies) {
|
||||||
|
result1_1.push(`${meta.root}/${v}`);
|
||||||
|
}
|
||||||
|
return result1_1;
|
||||||
|
})(),
|
||||||
|
`${meta.root}/build/debug`
|
||||||
|
);
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
} catch (e_2) {
|
||||||
|
return reject(__e(e_2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @memberof AntOSDK
|
||||||
|
*/
|
||||||
|
private run(meta: GenericObject<any>): void {
|
||||||
|
`${meta.root}/build/debug/package.json`
|
||||||
|
.asFileHandle()
|
||||||
|
.read("json")
|
||||||
|
.then((v) => {
|
||||||
|
v.text = v.name;
|
||||||
|
v.path = `${meta.root}/build/debug`;
|
||||||
|
v.filename = meta.name;
|
||||||
|
v.type = "app";
|
||||||
|
v.mime = "antos/app";
|
||||||
|
if (v.icon) {
|
||||||
|
v.icon = `${v.path}/${v.icon}`;
|
||||||
|
}
|
||||||
|
if (!v.iconclass && !v.icon) {
|
||||||
|
v.iconclass = "fa fa-adn";
|
||||||
|
}
|
||||||
|
this.notify(__("Installing..."));
|
||||||
|
this.app.systemsetting.system.packages[meta.name] = v;
|
||||||
|
this.notify(__("Running {0}...", meta.name));
|
||||||
|
return this.app._gui.forceLaunch(meta.name, []);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
App.extensions.AntOSDK = AntOSDK;
|
||||||
|
}
|
@ -1,195 +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
|
|
||||||
*/
|
|
||||||
CodePad.BaseExtension = class BaseExtension {
|
|
||||||
|
|
||||||
constructor(app) {
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
return Ant.OS.API.require(this.dependencies());
|
|
||||||
}
|
|
||||||
|
|
||||||
import(libs) {
|
|
||||||
return Ant.OS.API.require(libs);
|
|
||||||
}
|
|
||||||
|
|
||||||
basedir() {
|
|
||||||
return `${this.app.meta().path}/extensions`;
|
|
||||||
}
|
|
||||||
|
|
||||||
notify(m) {
|
|
||||||
return this.app.notify(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
error(m, e) {
|
|
||||||
return this.app.error(m, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
cat(list, data) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(data); }
|
|
||||||
const file = (list.splice(0, 1))[0].asFileHandle();
|
|
||||||
return file
|
|
||||||
.read()
|
|
||||||
.then(text => {
|
|
||||||
data = data + "\n" + text;
|
|
||||||
return this.cat(list, data)
|
|
||||||
.then(d => resolve(d))
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(files, to) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (files.length === 0) { return resolve(); }
|
|
||||||
const file = (files.splice(0, 1))[0].asFileHandle();
|
|
||||||
const tof = `${to}/${file.basename}`.asFileHandle();
|
|
||||||
return file.onready().then(meta => {
|
|
||||||
if (meta.type === "dir") {
|
|
||||||
// copy directory
|
|
||||||
const desdir = to.asFileHandle();
|
|
||||||
return desdir.mk(file.basename).then(() => {
|
|
||||||
// read the dir content
|
|
||||||
return file.read().then(data => {
|
|
||||||
const list = (Array.from(data.result).map((v) => v.path));
|
|
||||||
return this.copy(list, `${desdir.path}/${file.basename}`)
|
|
||||||
.then(() => {
|
|
||||||
return this.copy(files, to)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
} else {
|
|
||||||
// copy file
|
|
||||||
return file.read("binary")
|
|
||||||
.then(data => {
|
|
||||||
return tof.setCache(new Blob([data], { type: file.info.mime }))
|
|
||||||
.write(file.info.mime)
|
|
||||||
.then(d => {
|
|
||||||
return this.copy(files, to)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
aradd(list, zip, base) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(zip); }
|
|
||||||
const path = (list.splice(0, 1))[0];
|
|
||||||
const file = path.asFileHandle();
|
|
||||||
return file.onready().then(meta => {
|
|
||||||
if (meta.type === "dir") {
|
|
||||||
return file.read().then(d => {
|
|
||||||
const l = (Array.from(d.result).map((v) => v.path));
|
|
||||||
return this.aradd(l, zip, `${base}${file.basename}/`)
|
|
||||||
.then(() => {
|
|
||||||
return this.aradd(list, zip, base)
|
|
||||||
.then(() => resolve(zip))
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
} else {
|
|
||||||
return file.read("binary").then(d => {
|
|
||||||
const zpath = `${base}${file.basename}`.replace(/^\/+|\/+$/g, '');
|
|
||||||
zip.file(zpath, d, { binary: true });
|
|
||||||
return this.aradd(list, zip, base)
|
|
||||||
.then(() => resolve(zip))
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mkar(src, dest) {
|
|
||||||
this.notify(__("Preparing for release"));
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return new Promise((r, e) => {
|
|
||||||
return this.import(["os://scripts/jszip.min.js"]).then(() => src.asFileHandle()
|
|
||||||
.read().then(d => r(d.result)).catch(ex => e(__e(ex)))).catch(ex => e(__e(ex)));
|
|
||||||
}).then(files => {
|
|
||||||
return new Promise((r, e) => {
|
|
||||||
const zip = new JSZip();
|
|
||||||
return this.aradd((Array.from(files).map((v) => v.path)), zip, "/")
|
|
||||||
.then(z => r(z))
|
|
||||||
.catch(ex => e(__e(ex)));
|
|
||||||
});
|
|
||||||
}).then(zip => {
|
|
||||||
return zip.generateAsync({ type: "base64" }).then(data => {
|
|
||||||
return dest.asFileHandle()
|
|
||||||
.setCache('data:application/zip;base64,' + data)
|
|
||||||
.write("base64").then(r => {
|
|
||||||
return this.notify(__("Archive is generated at: {0}", dest));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdirAll(list) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(); }
|
|
||||||
const path = (list.splice(0, 1))[0].asFileHandle();
|
|
||||||
return path.parent().mk(path.basename)
|
|
||||||
.then(d => {
|
|
||||||
this.app.trigger("filechange", { file: path.parent(), type: "dir" });
|
|
||||||
return this.mkdirAll(list)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mkfileAll(list, path, name) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(); }
|
|
||||||
const item = (list.splice(0, 1))[0];
|
|
||||||
return `${this.basedir()}/${item[0]}`
|
|
||||||
.asFileHandle()
|
|
||||||
.read()
|
|
||||||
.then(data => {
|
|
||||||
const file = item[1].asFileHandle();
|
|
||||||
return file
|
|
||||||
.setCache(data.format(name, `${path}/${name}`))
|
|
||||||
.write("text/plain")
|
|
||||||
.then(() => {
|
|
||||||
this.app.trigger("filechange", { file, type: "file" });
|
|
||||||
return this.mkfileAll(list, path, name)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!this.app.currdir) {
|
|
||||||
return reject(this.app._api.throwe(__("Current folder is not found")));
|
|
||||||
}
|
|
||||||
return `${this.app.currdir.path}/${file}`
|
|
||||||
.asFileHandle()
|
|
||||||
.read("json")
|
|
||||||
.then(data => resolve(data)).catch(e => {
|
|
||||||
return reject(this.app._api.throwe(__("Unable to read meta-data")));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CodePad.extensions = {};
|
|
435
src/packages/CodePad/BaseExtension.ts
Normal file
435
src/packages/CodePad/BaseExtension.ts
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
namespace OS {
|
||||||
|
const CodePad = OS.application.CodePad;
|
||||||
|
declare var JSZip: any;
|
||||||
|
|
||||||
|
export namespace application {
|
||||||
|
export type CodePadBaseExtension = typeof BaseExtension;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @class BaseExtension
|
||||||
|
*/
|
||||||
|
class BaseExtension {
|
||||||
|
protected app: OS.application.CodePad;
|
||||||
|
constructor(app: OS.application.CodePad) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
preload(): Promise<any> {
|
||||||
|
return API.require(this.dependencies());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {string[]} libs
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
import(libs: string[]): Promise<any> {
|
||||||
|
return API.require(libs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @returns {string}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected basedir(): string {
|
||||||
|
return `${this.app.meta().path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {(string | FormatedString)} m
|
||||||
|
* @returns {void}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected notify(m: string | FormatedString): void {
|
||||||
|
return this.app.notify(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {(string | FormatedString)} m
|
||||||
|
* @param {Error} e
|
||||||
|
* @returns {void}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected error(m: string | FormatedString, e: Error): void {
|
||||||
|
return this.app.error(m, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @returns {string[]}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected dependencies(): string[] {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string[]} list
|
||||||
|
* @param {string} data
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected cat(list: string[], data: string): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve(data);
|
||||||
|
}
|
||||||
|
const file = list.splice(0, 1)[0].asFileHandle();
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then((text: string) => {
|
||||||
|
data = data + "\n" + text;
|
||||||
|
return this.cat(list, data)
|
||||||
|
.then((d) => resolve(d))
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string[]} files
|
||||||
|
* @param {string} to
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected copy(files: string[], to: string): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (files.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const file = files.splice(0, 1)[0].asFileHandle();
|
||||||
|
const tof = `${to}/${file.basename}`.asFileHandle();
|
||||||
|
return file
|
||||||
|
.onready()
|
||||||
|
.then((meta: { type: string }) => {
|
||||||
|
if (meta.type === "dir") {
|
||||||
|
// copy directory
|
||||||
|
const desdir = to.asFileHandle();
|
||||||
|
return desdir
|
||||||
|
.mk(file.basename)
|
||||||
|
.then(() => {
|
||||||
|
// read the dir content
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then((data: API.RequestResult) => {
|
||||||
|
const list = (data.result as API.FileInfoType[]).map(
|
||||||
|
(v) => v.path
|
||||||
|
);
|
||||||
|
return this.copy(
|
||||||
|
list,
|
||||||
|
`${desdir.path}/${file.basename}`
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return this.copy(files, to)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) =>
|
||||||
|
reject(__e(e))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
} else {
|
||||||
|
// copy file
|
||||||
|
return file
|
||||||
|
.read("binary")
|
||||||
|
.then(async (data: BlobPart) => {
|
||||||
|
const d = await tof
|
||||||
|
.setCache(
|
||||||
|
new Blob([data], {
|
||||||
|
type: file.info.mime,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.write(file.info.mime);
|
||||||
|
try {
|
||||||
|
await this.copy(files, to);
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string[]} list
|
||||||
|
* @param {*} zip
|
||||||
|
* @param {string} base
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
private aradd(list: string[], zip: any, base: string): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve(zip);
|
||||||
|
}
|
||||||
|
const path = list.splice(0, 1)[0];
|
||||||
|
const file = path.asFileHandle();
|
||||||
|
return file
|
||||||
|
.onready()
|
||||||
|
.then((meta: { type: string }) => {
|
||||||
|
if (meta.type === "dir") {
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then(
|
||||||
|
(d: {
|
||||||
|
result:
|
||||||
|
| Iterable<unknown>
|
||||||
|
| ArrayLike<unknown>;
|
||||||
|
}) => {
|
||||||
|
const l = (d.result as API.FileInfoType[]).map(
|
||||||
|
(v) => v.path
|
||||||
|
);
|
||||||
|
return this.aradd(
|
||||||
|
l,
|
||||||
|
zip,
|
||||||
|
`${base}${file.basename}/`
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return this.aradd(
|
||||||
|
list,
|
||||||
|
zip,
|
||||||
|
base
|
||||||
|
)
|
||||||
|
.then(() => resolve(zip))
|
||||||
|
.catch((e) =>
|
||||||
|
reject(__e(e))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
} else {
|
||||||
|
return file
|
||||||
|
.read("binary")
|
||||||
|
.then((d: any) => {
|
||||||
|
const zpath = `${base}${file.basename}`.replace(
|
||||||
|
/^\/+|\/+$/g,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
zip.file(zpath, d, { binary: true });
|
||||||
|
return this.aradd(list, zip, base)
|
||||||
|
.then(() => resolve(zip))
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} src
|
||||||
|
* @param {string} dest
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected mkar(src: string, dest: string): Promise<any> {
|
||||||
|
this.notify(__("Preparing for release"));
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return new Promise(async (r, e) => {
|
||||||
|
try {
|
||||||
|
await this.import(["os://scripts/jszip.min.js"]);
|
||||||
|
try {
|
||||||
|
const d = await src.asFileHandle().read();
|
||||||
|
return r(d.result);
|
||||||
|
} catch (ex) {
|
||||||
|
return e(__e(ex));
|
||||||
|
}
|
||||||
|
} catch (ex_1) {
|
||||||
|
return e(__e(ex_1));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((files: API.FileInfoType[]) => {
|
||||||
|
return new Promise(async (r, e) => {
|
||||||
|
const zip = new JSZip();
|
||||||
|
try {
|
||||||
|
const z = await this.aradd(
|
||||||
|
files.map((v: { path: any }) => v.path),
|
||||||
|
zip,
|
||||||
|
"/"
|
||||||
|
);
|
||||||
|
return r(z);
|
||||||
|
} catch (ex) {
|
||||||
|
return e(__e(ex));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then((zip: any) => {
|
||||||
|
return zip
|
||||||
|
.generateAsync({ type: "base64" })
|
||||||
|
.then((data: string) => {
|
||||||
|
return dest
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(
|
||||||
|
"data:application/zip;base64," + data
|
||||||
|
)
|
||||||
|
.write("base64")
|
||||||
|
.then((r: any) => {
|
||||||
|
resolve();
|
||||||
|
return this.notify(
|
||||||
|
__(
|
||||||
|
"Archive is generated at: {0}",
|
||||||
|
dest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string[]} list
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected mkdirAll(list: string[]): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const path = list.splice(0, 1)[0].asFileHandle();
|
||||||
|
return path
|
||||||
|
.parent()
|
||||||
|
.mk(path.basename)
|
||||||
|
.then((d: any) => {
|
||||||
|
this.app.trigger("filechange", {
|
||||||
|
file: path.parent(),
|
||||||
|
type: "dir",
|
||||||
|
});
|
||||||
|
return this.mkdirAll(list)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string[]} list
|
||||||
|
* @param {string} path
|
||||||
|
* @param {string} name
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected mkfileAll(
|
||||||
|
list: Array<string[]>,
|
||||||
|
path: string,
|
||||||
|
name: string
|
||||||
|
): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const item = list.splice(0, 1)[0];
|
||||||
|
return `${this.basedir()}/${item[0]}`
|
||||||
|
.asFileHandle()
|
||||||
|
.read()
|
||||||
|
.then((data) => {
|
||||||
|
const file = item[1].asFileHandle();
|
||||||
|
return file
|
||||||
|
.setCache(data.format(name, `${path}/${name}`))
|
||||||
|
.write("text/plain")
|
||||||
|
.then(() => {
|
||||||
|
this.app.trigger("filechange", {
|
||||||
|
file,
|
||||||
|
type: "file",
|
||||||
|
});
|
||||||
|
return this.mkfileAll(list, path, name)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {string} file
|
||||||
|
* @returns {Promise<GenericObject<any>>}
|
||||||
|
* @memberof BaseExtension
|
||||||
|
*/
|
||||||
|
protected metadata(file: string): Promise<GenericObject<any>> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.app.currdir) {
|
||||||
|
return reject(
|
||||||
|
this.app._api.throwe(__("Current folder is not found"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`${this.app.currdir.path}/${file}`
|
||||||
|
.asFileHandle()
|
||||||
|
.read("json")
|
||||||
|
.then((data) => resolve(data))
|
||||||
|
.catch((e) => {
|
||||||
|
return reject(
|
||||||
|
this.app._api.throwe(__("Unable to read meta-data"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CodePad.extensions = {};
|
||||||
|
CodePad.BaseExtension = BaseExtension;
|
||||||
|
}
|
@ -1,98 +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
|
|
||||||
*/
|
|
||||||
class CommandPalette extends this.OS.GUI.BasicDialog {
|
|
||||||
constructor() {
|
|
||||||
super("CommandPalete", CommandPalette.scheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
super.main();
|
|
||||||
const offset = $(".afx-window-content", this.parent.scheme).offset();
|
|
||||||
const pw = this.parent.scheme.get("width") / 5;
|
|
||||||
this.scheme.set("width", 3 * pw);
|
|
||||||
$(this.scheme).offset({ top: offset.top - 2, left: offset.left + pw });
|
|
||||||
var cb = e => {
|
|
||||||
if (($(e.target)).closest(this.scheme).length > 0) {
|
|
||||||
return $(this.find("searchbox")).focus();
|
|
||||||
} else {
|
|
||||||
$(document).unbind("mousedown", cb);
|
|
||||||
return this.quit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
$(document).on("mousedown", cb);
|
|
||||||
$(this.find("searchbox")).focus();
|
|
||||||
this.cmdlist = this.find("container");
|
|
||||||
if (this.data) { this.cmdlist.set("data", (Array.from(this.data.child))); }
|
|
||||||
$(this.cmdlist).click(e => {
|
|
||||||
return this.selectCommand();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.searchbox = this.find("searchbox");
|
|
||||||
return ($(this.searchbox)).keyup(e => {
|
|
||||||
return this.search(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
search(e) {
|
|
||||||
let v;
|
|
||||||
switch (e.which) {
|
|
||||||
case 27:
|
|
||||||
// escape key
|
|
||||||
this.quit();
|
|
||||||
if (this.data.parent && this.data.parent.run) { return this.data.parent.run(this.parent); }
|
|
||||||
break;
|
|
||||||
case 37:
|
|
||||||
return e.preventDefault();
|
|
||||||
case 38:
|
|
||||||
this.cmdlist.selectPrev();
|
|
||||||
return e.preventDefault();
|
|
||||||
case 39:
|
|
||||||
return e.preventDefault();
|
|
||||||
case 40:
|
|
||||||
this.cmdlist.selectNext();
|
|
||||||
return e.preventDefault();
|
|
||||||
case 13:
|
|
||||||
e.preventDefault();
|
|
||||||
return this.selectCommand();
|
|
||||||
default:
|
|
||||||
var text = this.searchbox.value;
|
|
||||||
if (text.length === 2) { this.cmdlist.set("data", ((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (v of Array.from(this.data.child)) { result1.push(v);
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})())); }
|
|
||||||
if (text.length < 3) { return; }
|
|
||||||
var result = [];
|
|
||||||
var term = new RegExp(text, 'i');
|
|
||||||
for (v of Array.from(this.data.child)) { if (v.text.match(term)) { result.push(v); } }
|
|
||||||
return this.cmdlist.set("data", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
selectCommand() {
|
|
||||||
const el = this.cmdlist.get("selectedItem");
|
|
||||||
if (!el) { return; }
|
|
||||||
el.set("selected", false);
|
|
||||||
let result = false;
|
|
||||||
if (this.handle) { result = this.handle({ data: { item: el } }); }
|
|
||||||
if (!result) { return this.quit(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandPalette.scheme = `\
|
|
||||||
<afx-app-window data-id = "cmd-win"
|
|
||||||
apptitle="" minimizable="false"
|
|
||||||
resizable = "false" width="200" height="200">
|
|
||||||
<afx-vbox>
|
|
||||||
<input data-height="25" type = "text" data-id="searchbox"/>
|
|
||||||
<afx-list-view data-id="container"></afx-list-view>
|
|
||||||
</afx-vbox>
|
|
||||||
</afx-app-window>\
|
|
||||||
`;
|
|
492
src/packages/CodePad/ExtensionMaker.ts
Normal file
492
src/packages/CodePad/ExtensionMaker.ts
Normal file
@ -0,0 +1,492 @@
|
|||||||
|
namespace OS {
|
||||||
|
// import the CodePad application module
|
||||||
|
const App = OS.application.CodePad;
|
||||||
|
|
||||||
|
declare var CoffeeScript: any;
|
||||||
|
declare var JSZip: any;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @class ExtensionMaker
|
||||||
|
* @extends {App.BaseExtension}
|
||||||
|
*/
|
||||||
|
class ExtensionMaker extends App.BaseExtension {
|
||||||
|
constructor(app: application.CodePad) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public functions
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
create(): void {
|
||||||
|
this.app
|
||||||
|
.openDialog("FileDialog", {
|
||||||
|
title: "__(New CodePad extension at)",
|
||||||
|
file: { basename: __("ExtensionName") },
|
||||||
|
mimes: ["dir"],
|
||||||
|
})
|
||||||
|
.then((d) => {
|
||||||
|
return this.mktpl(d.file.path, d.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
buildnrun(): void {
|
||||||
|
this.metadata("extension.json")
|
||||||
|
.then(async (meta) => {
|
||||||
|
try {
|
||||||
|
await this.build(meta);
|
||||||
|
try {
|
||||||
|
return this.run(meta);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(__("Unable to run extension"), e);
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return this.error(__("Unable to build extension"), e_1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => this.error(__("Unable to read meta-data"), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
release(): void {
|
||||||
|
this.metadata("extension.json")
|
||||||
|
.then(async (meta) => {
|
||||||
|
try {
|
||||||
|
await this.build(meta);
|
||||||
|
try {
|
||||||
|
return this.mkar(
|
||||||
|
`${meta.root}/build/debug`,
|
||||||
|
`${meta.root}/build/release/${meta.meta.name}.zip`
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(
|
||||||
|
__("Unable to create archive"),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return this.error(__("Unable to build extension"), e_1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => this.error(__("Unable to read meta-data"), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
install(): void {
|
||||||
|
this.app
|
||||||
|
.openDialog("FileDialog", {
|
||||||
|
title: "__(Select extension archive)",
|
||||||
|
mimes: [".*/zip"],
|
||||||
|
})
|
||||||
|
.then(async (d) => {
|
||||||
|
try {
|
||||||
|
await this.installZip(d.file.path);
|
||||||
|
this.notify(__("Extension installed"));
|
||||||
|
return this.app.loadExtensionMetaData();
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(__("Unable to install extension"), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} path
|
||||||
|
* @param {string} name
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private mktpl(path: string, name: string): void {
|
||||||
|
const rpath = `${path}/${name}`;
|
||||||
|
const dirs = [
|
||||||
|
rpath,
|
||||||
|
`${rpath}/build`,
|
||||||
|
`${rpath}/build/release`,
|
||||||
|
`${rpath}/build/debug`,
|
||||||
|
];
|
||||||
|
const files = [
|
||||||
|
["templates/ext-main.tpl", `${rpath}/${name}.coffee`],
|
||||||
|
["templates/ext-extension.tpl", `${rpath}/extension.json`],
|
||||||
|
];
|
||||||
|
this.mkdirAll(dirs)
|
||||||
|
.then(async () => {
|
||||||
|
try {
|
||||||
|
await this.mkfileAll(files, path, name);
|
||||||
|
this.app.currdir = rpath.asFileHandle();
|
||||||
|
this.app.initSideBar();
|
||||||
|
return this.app.openFile(
|
||||||
|
`${rpath}/${name}.coffee`.asFileHandle() as application.CodePadFileHandle
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return this.error(
|
||||||
|
__("Unable to create extension template"),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) =>
|
||||||
|
this.error(__("Unable to create extension directories"), e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string[]} list
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private verify(list: string[]): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const file = list.splice(0, 1)[0].asFileHandle();
|
||||||
|
this.notify(__("Verifying: {0}", file.path));
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then((data) => {
|
||||||
|
try {
|
||||||
|
CoffeeScript.nodes(data);
|
||||||
|
return this.verify(list)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
} catch (ex) {
|
||||||
|
return reject(__e(ex));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private compile(meta: GenericObject<any>): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
await this.import([`${this.basedir()}/libs/coffeescript.js`]);
|
||||||
|
const list = meta.coffees.map(
|
||||||
|
(v) => `${meta.root}/${v}`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await this.verify(list.map((x: string) =>x));
|
||||||
|
try {
|
||||||
|
const code = await this.cat(list, "");
|
||||||
|
const jsrc = CoffeeScript.compile(code);
|
||||||
|
this.notify(__("Compiled successful"));
|
||||||
|
return resolve(jsrc);
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
} catch (e_2) {
|
||||||
|
return reject(__e(e_2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private build(meta: GenericObject<any>): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const src = await this.compile(meta);
|
||||||
|
let v: string;
|
||||||
|
try {
|
||||||
|
const jsrc = await this.cat(
|
||||||
|
(() => {
|
||||||
|
const result = [];
|
||||||
|
for (v of meta.javascripts) {
|
||||||
|
result.push(`${meta.root}/${v}`);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})(),
|
||||||
|
src
|
||||||
|
);
|
||||||
|
await new Promise((r, e) =>
|
||||||
|
`${meta.root}/build/debug/${meta.meta.name}.js`
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(jsrc)
|
||||||
|
.write("text/plain")
|
||||||
|
.then((d) => r())
|
||||||
|
.catch((ex) => e(__e(ex)))
|
||||||
|
);
|
||||||
|
await new Promise((r, e) =>
|
||||||
|
`${meta.root}/build/debug/extension.json`
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(meta.meta)
|
||||||
|
.write("object")
|
||||||
|
.then((data) => r(data))
|
||||||
|
.catch((ex_1) => e(__e(ex_1)))
|
||||||
|
);
|
||||||
|
await this.copy(
|
||||||
|
(() => {
|
||||||
|
const result1 = [];
|
||||||
|
for (v of meta.copies) {
|
||||||
|
result1.push(`${meta.root}/${v}`);
|
||||||
|
}
|
||||||
|
return result1;
|
||||||
|
})(),
|
||||||
|
`${meta.root}/build/debug`
|
||||||
|
);
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.app._api.requires(path);
|
||||||
|
let v: GenericObject<any>;
|
||||||
|
if (this.app.extensions[meta.meta.name]) {
|
||||||
|
this.app.extensions[meta.meta.name].child = [];
|
||||||
|
for (v of meta.meta.actions) {
|
||||||
|
this.app.extensions[meta.meta.name].addAction(v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.app.extensions[meta.meta.name] = new App.CMDMenu(
|
||||||
|
meta.meta.text
|
||||||
|
);
|
||||||
|
this.app.extensions[meta.meta.name].name =
|
||||||
|
meta.meta.name;
|
||||||
|
for (v of meta.meta.actions) {
|
||||||
|
this.app.extensions[meta.meta.name].addAction(v);
|
||||||
|
}
|
||||||
|
this.app.spotlight.addAction(
|
||||||
|
this.app.extensions[meta.meta.name]
|
||||||
|
);
|
||||||
|
this.app.extensions[meta.meta.name].onchildselect(
|
||||||
|
(e: GUI.TagEventType) => {
|
||||||
|
return this.app.loadAndRunExtensionAction(
|
||||||
|
e.data.item.data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.app.spotlight.run(this.app);
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string[]} files
|
||||||
|
* @param {*} zip
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private installExtension(files: string[], zip: any): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const idx = files.indexOf("extension.json");
|
||||||
|
if (idx < 0) {
|
||||||
|
reject(this.app._api.throwe(__("No meta-data found")));
|
||||||
|
}
|
||||||
|
const metafile = files.splice(idx, 1)[0];
|
||||||
|
// read the meta file
|
||||||
|
return zip
|
||||||
|
.file(metafile)
|
||||||
|
.async("uint8array")
|
||||||
|
.then((d: Uint8Array) => {
|
||||||
|
const meta = JSON.parse(
|
||||||
|
new TextDecoder("utf-8").decode(d)
|
||||||
|
);
|
||||||
|
return this.installFiles(files, zip, meta)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string[]} files
|
||||||
|
* @param {*} zip
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private installFiles(
|
||||||
|
files: string[],
|
||||||
|
zip: any,
|
||||||
|
meta: GenericObject<any>
|
||||||
|
): Promise<any> {
|
||||||
|
if (files.length === 0) {
|
||||||
|
return this.installMeta(meta);
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const file = files.splice(0, 1)[0];
|
||||||
|
const path = `${this.basedir()}/${file}`;
|
||||||
|
return zip
|
||||||
|
.file(file)
|
||||||
|
.async("uint8array")
|
||||||
|
.then((d: Uint8Array) => {
|
||||||
|
return path
|
||||||
|
.asFileHandle()
|
||||||
|
.setCache(new Blob([d], { type: "octet/stream" }))
|
||||||
|
.write("text/plain")
|
||||||
|
.then((r) => {
|
||||||
|
if (r.error) {
|
||||||
|
return reject(r.error);
|
||||||
|
}
|
||||||
|
return this.installFiles(files, zip, meta)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {GenericObject<any>} meta
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private installMeta(meta: GenericObject<any>): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const file = `${
|
||||||
|
this.app.meta().path
|
||||||
|
}/extensions.json`.asFileHandle();
|
||||||
|
try {
|
||||||
|
const data = await file.read("json");
|
||||||
|
const names = [];
|
||||||
|
for (let v of data) {
|
||||||
|
names.push(v.name);
|
||||||
|
}
|
||||||
|
const idx = names.indexOf(meta.name);
|
||||||
|
if (idx >= 0) {
|
||||||
|
data.splice(idx, 1);
|
||||||
|
}
|
||||||
|
data.push(meta);
|
||||||
|
try {
|
||||||
|
await file.setCache(data).write("object");
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @memberof ExtensionMaker
|
||||||
|
*/
|
||||||
|
private installZip(path: string): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.import(["os://scripts/jszip.min.js"])
|
||||||
|
.then(() => {
|
||||||
|
path.asFileHandle()
|
||||||
|
.read("binary")
|
||||||
|
.then((data) => {
|
||||||
|
JSZip.loadAsync(data)
|
||||||
|
.then((zip: any) => {
|
||||||
|
const pth = this.basedir();
|
||||||
|
const dir = [];
|
||||||
|
const files = [];
|
||||||
|
for (let name in zip.files) {
|
||||||
|
const file = zip.files[name];
|
||||||
|
if (file.dir) {
|
||||||
|
dir.push(pth + "/" + name);
|
||||||
|
} else {
|
||||||
|
files.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir.length > 0) {
|
||||||
|
this.mkdirAll(dir)
|
||||||
|
.then(() => {
|
||||||
|
this.installExtension(
|
||||||
|
files,
|
||||||
|
zip
|
||||||
|
)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) =>
|
||||||
|
reject(__e(e))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
} else {
|
||||||
|
this.installExtension(files, zip)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App.extensions.ExtensionMaker = ExtensionMaker;
|
||||||
|
}
|
@ -1,10 +1,16 @@
|
|||||||
module_files = CommandPalette.js main.js BaseExtension.js
|
module_files = main.js BaseExtension.js
|
||||||
|
|
||||||
libfiles =
|
libfiles =
|
||||||
|
|
||||||
cssfiles = css/main.css
|
cssfiles = css/main.css
|
||||||
|
|
||||||
copyfiles = assets/scheme.html package.json extensions.json extensions
|
copyfiles = assets/scheme.html \
|
||||||
|
package.json \
|
||||||
|
extensions.json \
|
||||||
|
libs \
|
||||||
|
templates \
|
||||||
|
$(DIST)/AntOSDK.js \
|
||||||
|
$(DIST)/ExtensionMaker.js
|
||||||
|
|
||||||
|
|
||||||
PKG_NAME=CodePad
|
PKG_NAME=CodePad
|
||||||
|
@ -1,222 +0,0 @@
|
|||||||
(function() {
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
// import the CodePad application module
|
|
||||||
const App = this.OS.APP.CodePad;
|
|
||||||
|
|
||||||
// define the extension
|
|
||||||
App.extensions.AntOSDK = class AntOSDK extends App.BaseExtension {
|
|
||||||
constructor(app) {
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public functions
|
|
||||||
create() {
|
|
||||||
return this.app.openDialog("FileDialog", {
|
|
||||||
title: "__(New Project at)",
|
|
||||||
file: { basename: __("ProjectName") },
|
|
||||||
mimes: ["dir"]
|
|
||||||
}).then(d => {
|
|
||||||
return this.mktpl(d.file.path, d.name, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
const dir = this.app.currdir;
|
|
||||||
if (!dir || !dir.basename) { return this.create(); }
|
|
||||||
return dir.read()
|
|
||||||
.then(d => {
|
|
||||||
if (d.error) { return this.notify(__("Cannot read folder: {0}", dir.path)); }
|
|
||||||
if (d.result.length !== 0) { return this.notify(__("The folder is not empty: {0}", dir.path)); }
|
|
||||||
return this.mktpl(dir.parent().path, dir.basename);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buildnrun() {
|
|
||||||
return this.metadata("project.json").then(meta => {
|
|
||||||
return this.build(meta, true).then(() => {
|
|
||||||
return this.run(meta).catch(e => this.error(__("Unable to run project"), e));
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Unable to build project"), e);
|
|
||||||
});
|
|
||||||
}).catch(e => this.error(__("Unable to read meta-data"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
release() {
|
|
||||||
return this.metadata("project.json").then(meta => {
|
|
||||||
return this.build(meta, false).then(() => {
|
|
||||||
return this.mkar(`${meta.root}/build/debug`, `${meta.root}/build/release/${meta.name}.zip`)
|
|
||||||
.catch(e => this.error(__("Unable to create package archive"), e));
|
|
||||||
}).catch(e => {},
|
|
||||||
this.error(__("Unable to build project"), e)
|
|
||||||
);
|
|
||||||
}).catch(e => this.error(__("Unable to read meta-data"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// private functions
|
|
||||||
mktpl(path, name, flag) {
|
|
||||||
const rpath = `${path}/${name}`;
|
|
||||||
const dirs = [
|
|
||||||
`${rpath}/javascripts`,
|
|
||||||
`${rpath}/css`,
|
|
||||||
`${rpath}/coffees`,
|
|
||||||
`${rpath}/assets`
|
|
||||||
];
|
|
||||||
if (flag) { dirs.unshift(rpath); }
|
|
||||||
const files = [
|
|
||||||
["templates/sdk-main.tpl", `${rpath}/coffees/main.coffee`],
|
|
||||||
["templates/sdk-package.tpl", `${rpath}/package.json`],
|
|
||||||
["templates/sdk-project.tpl", `${rpath}/project.json`],
|
|
||||||
["templates/sdk-README.tpl", `${rpath}/README.md`],
|
|
||||||
["templates/sdk-scheme.tpl", `${rpath}/assets/scheme.html`]
|
|
||||||
];
|
|
||||||
return this.mkdirAll(dirs)
|
|
||||||
.then(() => {
|
|
||||||
return this.mkfileAll(files, path, name)
|
|
||||||
.then(() => {
|
|
||||||
this.app.currdir = rpath.asFileHandle();
|
|
||||||
this.app.initSideBar();
|
|
||||||
return this.app.openFile(`${rpath}/README.md`.asFileHandle());
|
|
||||||
}).catch(e => this.error(__("Unable to create template files"), e));
|
|
||||||
}).catch(e => this.error(__("Unable to create project directory"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
verify(list) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(); }
|
|
||||||
const file = (list.splice(0, 1))[0].asFileHandle();
|
|
||||||
this.notify(__("Verifying: {0}", file.path));
|
|
||||||
return file.read().then(data => {
|
|
||||||
try {
|
|
||||||
CoffeeScript.nodes(data);
|
|
||||||
return this.verify(list)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
} catch (ex) {
|
|
||||||
return reject(__e(ex));
|
|
||||||
}
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(meta) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.import([
|
|
||||||
`${this.basedir()}/coffeescript.js`,
|
|
||||||
`${this.basedir()}/terser.min.js`
|
|
||||||
]).then(() => {
|
|
||||||
const list = (Array.from(meta.coffees).map((v) => `${meta.root}/${v}`));
|
|
||||||
return this.verify((Array.from(list))).then(() => {
|
|
||||||
return this.cat(list).then(code => {
|
|
||||||
const jsrc = CoffeeScript.compile(code);
|
|
||||||
this.notify(__("Compiled successful"));
|
|
||||||
return resolve(jsrc);
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
build(meta, debug) {
|
|
||||||
const dirs = [
|
|
||||||
`${meta.root}/build`,
|
|
||||||
`${meta.root}/build/debug`,
|
|
||||||
`${meta.root}/build/release`
|
|
||||||
];
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.mkdirAll(dirs).then(() => {
|
|
||||||
return this.compile(meta).then(src => {
|
|
||||||
let v;
|
|
||||||
return this.cat(((() => {
|
|
||||||
const result = [];
|
|
||||||
for (v of Array.from(meta.javascripts)) { result.push(`${meta.root}/${v}`);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})()), src)
|
|
||||||
.then(jsrc => new Promise(function(r, e) {
|
|
||||||
let code = jsrc;
|
|
||||||
if (!debug) {
|
|
||||||
const options = {
|
|
||||||
toplevel: true,
|
|
||||||
compress: {
|
|
||||||
passes: 3,
|
|
||||||
//pure_getters: true,
|
|
||||||
//unsafe: true,
|
|
||||||
},
|
|
||||||
mangle: true,
|
|
||||||
output: {
|
|
||||||
//beautify: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const result = Terser.minify(jsrc, options);
|
|
||||||
if (result.error) {
|
|
||||||
this.notify(__("Unable to minify code: {0}", result.error));
|
|
||||||
} else {
|
|
||||||
({
|
|
||||||
code
|
|
||||||
} = result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `${meta.root}/build/debug/main.js`
|
|
||||||
.asFileHandle()
|
|
||||||
.setCache(code)
|
|
||||||
.write("text/plain")
|
|
||||||
.then(d => r()).catch(ex => e(__e(ex)));
|
|
||||||
})).then(() => {
|
|
||||||
return new Promise((r, e) => {
|
|
||||||
return this.cat(((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (v of Array.from(meta.css)) { result1.push(`${meta.root}/${v}`);
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})()), "")
|
|
||||||
.then(function(txt) {
|
|
||||||
if (txt === "") { return r(); }
|
|
||||||
return `${meta.root}/build/debug/main.css`
|
|
||||||
.asFileHandle()
|
|
||||||
.setCache(txt)
|
|
||||||
.write("text/plain")
|
|
||||||
.then(d => r()).catch(ex => e(__e(ex)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).then(() => {
|
|
||||||
return this.copy(((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (v of Array.from(meta.copies)) { result1.push(`${meta.root}/${v}`);
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})()), `${meta.root}/build/debug`);
|
|
||||||
}).then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run(meta) {
|
|
||||||
return `${meta.root}/build/debug/package.json`
|
|
||||||
.asFileHandle()
|
|
||||||
.read("json")
|
|
||||||
.then(v => {
|
|
||||||
v.text = v.name;
|
|
||||||
v.path = `${meta.root}/build/debug`;
|
|
||||||
v.filename = meta.name;
|
|
||||||
v.type = "app";
|
|
||||||
v.mime = "antos/app";
|
|
||||||
if (v.icon) { v.icon = `${v.path}/${v.icon}`; }
|
|
||||||
if (!v.iconclass && !v.icon) { v.iconclass = "fa fa-adn"; }
|
|
||||||
this.notify(__("Installing..."));
|
|
||||||
this.app.systemsetting.system.packages[meta.name] = v;
|
|
||||||
this.notify(__("Running {0}...", meta.name));
|
|
||||||
return this.app._gui.forceLaunch(meta.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}).call(this);
|
|
@ -1,261 +0,0 @@
|
|||||||
(function() {
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
// import the CodePad application module
|
|
||||||
const App = this.OS.APP.CodePad;
|
|
||||||
|
|
||||||
// define the extension
|
|
||||||
App.extensions.ExtensionMaker = class ExtensionMaker extends App.BaseExtension {
|
|
||||||
constructor(app) {
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public functions
|
|
||||||
create() {
|
|
||||||
return this.app.openDialog("FileDialog", {
|
|
||||||
title: "__(New CodePad extension at)",
|
|
||||||
file: { basename: __("ExtensionName") },
|
|
||||||
mimes: ["dir"]
|
|
||||||
}).then(d => {
|
|
||||||
return this.mktpl(d.file.path, d.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buildnrun() {
|
|
||||||
return this.metadata("extension.json").then(meta => {
|
|
||||||
return this.build(meta).then(() => {
|
|
||||||
return this.run(meta).catch(e => this.error(__("Unable to run extension"), e));
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Unable to build extension"), e);
|
|
||||||
});
|
|
||||||
}).catch(e => this.error(__("Unable to read meta-data"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
release() {
|
|
||||||
return this.metadata("extension.json").then(meta => {
|
|
||||||
return this.build(meta).then(() => {
|
|
||||||
return this.mkar(`${meta.root}/build/debug`,
|
|
||||||
`${meta.root}/build/release/${meta.meta.name}.zip`)
|
|
||||||
.catch(e => this.error(__("Unable to create archive"), e));
|
|
||||||
}).catch(e => {},
|
|
||||||
this.error(__("Unable to build extension"), e)
|
|
||||||
);
|
|
||||||
}).catch(e => this.error(__("Unable to read meta-data"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
return this.app.openDialog("FileDialog", {
|
|
||||||
title: "__(Select extension archive)",
|
|
||||||
mimes: [".*/zip"]
|
|
||||||
}).then(d => {
|
|
||||||
return this.installZip(d.file.path)
|
|
||||||
.then(() => {
|
|
||||||
this.notify(__("Extension installed"));
|
|
||||||
return this.app.loadExtensionMetaData();
|
|
||||||
}).catch(e => this.error(__("Unable to install extension"), e));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// private functions
|
|
||||||
mktpl(path, name) {
|
|
||||||
const rpath = `${path}/${name}`;
|
|
||||||
const dirs = [
|
|
||||||
rpath,
|
|
||||||
`${rpath}/build`,
|
|
||||||
`${rpath}/build/release`,
|
|
||||||
`${rpath}/build/debug`
|
|
||||||
];
|
|
||||||
const files = [
|
|
||||||
["templates/ext-main.tpl", `${rpath}/${name}.coffee`],
|
|
||||||
["templates/ext-extension.tpl", `${rpath}/extension.json`],
|
|
||||||
];
|
|
||||||
return this.mkdirAll(dirs)
|
|
||||||
.then(() => {
|
|
||||||
return this.mkfileAll(files, path, name)
|
|
||||||
.then(() => {
|
|
||||||
this.app.currdir = rpath.asFileHandle();
|
|
||||||
this.app.initSideBar();
|
|
||||||
return this.app.openFile(`${rpath}/${name}.coffee`.asFileHandle());
|
|
||||||
}).catch(e => this.error(__("Unable to create extension template"), e));
|
|
||||||
}).catch(e => this.error(__("Unable to create extension directories"), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
verify(list) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) { return resolve(); }
|
|
||||||
const file = (list.splice(0, 1))[0].asFileHandle();
|
|
||||||
this.notify(__("Verifying: {0}", file.path));
|
|
||||||
return file.read().then(data => {
|
|
||||||
try {
|
|
||||||
CoffeeScript.nodes(data);
|
|
||||||
return this.verify(list)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
} catch (ex) {
|
|
||||||
return reject(__e(ex));
|
|
||||||
}
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(meta) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.import([`${this.basedir()}/coffeescript.js`]).then(() => {
|
|
||||||
const list = (Array.from(meta.coffees).map((v) => `${meta.root}/${v}`));
|
|
||||||
return this.verify((Array.from(list))).then(() => {
|
|
||||||
return this.cat(list).then(code => {
|
|
||||||
const jsrc = CoffeeScript.compile(code);
|
|
||||||
this.notify(__("Compiled successful"));
|
|
||||||
return resolve(jsrc);
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
build(meta) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.compile(meta).then(src => {
|
|
||||||
let v;
|
|
||||||
return this.cat(((() => {
|
|
||||||
const result = [];
|
|
||||||
for (v of Array.from(meta.javascripts)) { result.push(`${meta.root}/${v}`);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})()), src)
|
|
||||||
.then(jsrc => new Promise((r, e) => `${meta.root}/build/debug/${meta.meta.name}.js`
|
|
||||||
.asFileHandle()
|
|
||||||
.setCache(jsrc)
|
|
||||||
.write("text/plain")
|
|
||||||
.then(d => r()).catch(ex => e(__e(ex))))).then(() => new Promise((r, e) => `${meta.root}/build/debug/extension.json`
|
|
||||||
.asFileHandle()
|
|
||||||
.setCache(meta.meta)
|
|
||||||
.write("object")
|
|
||||||
.then(data => r(data)).catch(ex => e(__e(ex))))).then(() => {
|
|
||||||
return this.copy(((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (v of Array.from(meta.copies)) { result1.push(`${meta.root}/${v}`);
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})()), `${meta.root}/build/debug`);
|
|
||||||
}).then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run(meta) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const path = `${meta.root}/build/debug/${meta.meta.name}.js`;
|
|
||||||
if (this.app._api.shared[path]) { delete this.app._api.shared[path]; }
|
|
||||||
return this.app._api.requires(path)
|
|
||||||
.then(() => {
|
|
||||||
let v;
|
|
||||||
if (this.app.extensions[meta.meta.name]) {
|
|
||||||
this.app.extensions[meta.meta.name].child = [];
|
|
||||||
for (v of Array.from(meta.meta.actions)) { this.app.extensions[meta.meta.name].addAction(v); }
|
|
||||||
} else {
|
|
||||||
this.app.extensions[meta.meta.name] = new App.CMDMenu(meta.meta.text);
|
|
||||||
this.app.extensions[meta.meta.name].name = meta.meta.name;
|
|
||||||
for (v of Array.from(meta.meta.actions)) { this.app.extensions[meta.meta.name].addAction(v); }
|
|
||||||
this.app.spotlight.addAction(this.app.extensions[meta.meta.name]);
|
|
||||||
this.app.extensions[meta.meta.name].onchildselect(e => {
|
|
||||||
return this.app.loadAndRunExtensionAction(e.data.item.get("data"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.app.spotlight.run(this.app);
|
|
||||||
return resolve();
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
installExtension(files, zip) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const idx = files.indexOf("extension.json");
|
|
||||||
if (idx < 0) { reject(this.app._api.throwe(__("No meta-data found"))); }
|
|
||||||
const metafile = (files.splice(idx, 1))[0];
|
|
||||||
// read the meta file
|
|
||||||
return zip.file(metafile).async("uint8array").then(d => {
|
|
||||||
const meta = JSON.parse(new TextDecoder("utf-8").decode(d));
|
|
||||||
return this.installFiles(files, zip, meta)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
installFiles(files, zip, meta) {
|
|
||||||
if (files.length === 0) { return this.installMeta(meta); }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const file = (files.splice(0, 1))[0];
|
|
||||||
const path = `${this.basedir()}/${file}`;
|
|
||||||
return zip.file(file).async("uint8array").then(d => {
|
|
||||||
return path.asFileHandle()
|
|
||||||
.setCache(new Blob([d], { type: "octet/stream" }))
|
|
||||||
.write("text/plain").then(r => {
|
|
||||||
if (r.error) { return reject(r.error); }
|
|
||||||
return this.installFiles(files, zip, meta)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
installMeta(meta) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const file = `${this.app.meta().path}/extensions.json`.asFileHandle();
|
|
||||||
return file.read("json").then(function(data) {
|
|
||||||
for (let v of Array.from(data)) { const names = (v.name); }
|
|
||||||
const idx = name.indexOf(meta.name);
|
|
||||||
if (idx >= 0) { data.splice(idx, 1); }
|
|
||||||
data.push(meta);
|
|
||||||
return file.setCache(data)
|
|
||||||
.write("object")
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
installZip(path) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.import(["os://scripts/jszip.min.js"]).then(() => {
|
|
||||||
return path.asFileHandle().read("binary").then(data => {
|
|
||||||
return JSZip.loadAsync(data).then(zip => {
|
|
||||||
const pth = this.basedir();
|
|
||||||
const dir = [];
|
|
||||||
const files = [];
|
|
||||||
for (let name in zip.files) {
|
|
||||||
const file = zip.files[name];
|
|
||||||
if (file.dir) {
|
|
||||||
dir.push(pth + "/" + name);
|
|
||||||
} else {
|
|
||||||
files.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dir.length > 0) {
|
|
||||||
return this.mkdirAll(dir)
|
|
||||||
.then(() => {
|
|
||||||
return this.installExtension(files, zip)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e)(() => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
} else {
|
|
||||||
return this.installExtension(files, zip)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch(e => reject(__e(e)));
|
|
||||||
}
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
}).catch(e => reject(__e(e)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}).call(this);
|
|
@ -1,628 +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
|
|
||||||
*/
|
|
||||||
const Ant = this;
|
|
||||||
|
|
||||||
class CodePad extends this.OS.GUI.BaseApplication {
|
|
||||||
constructor(args) {
|
|
||||||
super("CodePad", args);
|
|
||||||
this.currfile = "Untitled".asFileHandle();
|
|
||||||
this.currdir = undefined;
|
|
||||||
if (this.args && (this.args.length > 0)) {
|
|
||||||
if (this.args[0].type === "dir") {
|
|
||||||
this.currdir = this.args[0].path.asFileHandle();
|
|
||||||
} else {
|
|
||||||
this.currfile = this.args[0].path.asFileHandle();
|
|
||||||
this.currdir = this.currfile.parent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
this.extensions = {};
|
|
||||||
this.fileview = this.find("fileview");
|
|
||||||
this.sidebar = this.find("sidebar");
|
|
||||||
this.tabbar = this.find("tabbar");
|
|
||||||
this.langstat = this.find("langstat");
|
|
||||||
this.editorstat = this.find("editorstat");
|
|
||||||
|
|
||||||
this.fileview.set("fetch", path => new Promise(function(resolve, reject) {
|
|
||||||
let dir = path;
|
|
||||||
if (typeof path === "string") { dir = path.asFileHandle(); }
|
|
||||||
return dir.read().then(function(d) {
|
|
||||||
if (d.error) { return reject(d.error); }
|
|
||||||
return resolve(d.result);}).catch(e => reject(__e(e)));
|
|
||||||
}));
|
|
||||||
return this.setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
ace.config.set('basePath', '/scripts/ace');
|
|
||||||
ace.require("ace/ext/language_tools");
|
|
||||||
this.editor = ace.edit(this.find("datarea"));
|
|
||||||
this.editor.setOptions({
|
|
||||||
enableBasicAutocompletion: true,
|
|
||||||
enableSnippets: true,
|
|
||||||
enableLiveAutocompletion: true,
|
|
||||||
highlightActiveLine: true,
|
|
||||||
highlightSelectedWord: true,
|
|
||||||
behavioursEnabled: true,
|
|
||||||
wrap: true,
|
|
||||||
fontSize: "11pt",
|
|
||||||
showInvisibles: true
|
|
||||||
});
|
|
||||||
//themes = ace.require "ace/ext/themelist"
|
|
||||||
this.editor.setTheme("ace/theme/monokai");
|
|
||||||
this.modes = ace.require("ace/ext/modelist");
|
|
||||||
this.editor.completers.push({ getCompletions( editor, session, pos, prefix, callback ) {} });
|
|
||||||
this.editor.getSession().setUseWrapMode(true);
|
|
||||||
this.editormux = false;
|
|
||||||
this.editor.on("input", () => {
|
|
||||||
if (this.editormux) {
|
|
||||||
this.editormux = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!this.currfile.dirty) {
|
|
||||||
this.currfile.dirty = true;
|
|
||||||
this.currfile.text += "*";
|
|
||||||
return this.tabbar.update();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.editor.getSession().selection.on("changeCursor", e => {
|
|
||||||
return this.updateStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tabbar.set("ontabselect", e => {
|
|
||||||
return this.selecteTab($(e.data.item).index());
|
|
||||||
});
|
|
||||||
this.tabbar.set("ontabclose", e => {
|
|
||||||
const it = e.data.item;
|
|
||||||
if (!it) { return false; }
|
|
||||||
if (!it.get("data").dirty) { return this.closeTab(it); }
|
|
||||||
this.openDialog("YesNoDialog", {
|
|
||||||
title: __("Close tab"),
|
|
||||||
text: __("Close without saving ?")
|
|
||||||
}).then(d => {
|
|
||||||
if (d) { return this.closeTab(it); }
|
|
||||||
return this.editor.focus();
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
this.fileview.set("onfileopen", e => {
|
|
||||||
if (!e.data || !e.data.path) { return; }
|
|
||||||
if (e.data.type === "dir") { return; }
|
|
||||||
return this.openFile(e.data.path.asFileHandle());
|
|
||||||
});
|
|
||||||
|
|
||||||
this.fileview.set("onfileselect", e => {
|
|
||||||
if (!e.data || !e.data.path) { return; }
|
|
||||||
if (e.data.type === "dir") { return; }
|
|
||||||
const i = this.findTabByFile(e.data.path.asFileHandle());
|
|
||||||
if (i !== -1) { return this.tabbar.set("selected", i); }
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on("resize", () => this.editor.resize());
|
|
||||||
this.on("focus", () => this.editor.focus());
|
|
||||||
this.spotlight = new CMDMenu(__("Command palette"));
|
|
||||||
this.bindKey("ALT-P", () => this.spotlight.run(this));
|
|
||||||
this.find("datarea").contextmenuHandle = (e, m) => {
|
|
||||||
m.set("items", [{
|
|
||||||
text: __("Command palete"),
|
|
||||||
onmenuselect: e => {
|
|
||||||
return this.spotlight.run(this);
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
return m.show(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.fileview.contextmenuHandle = (e, m) => {
|
|
||||||
m.set("items", [
|
|
||||||
{ text: "__(New file)", id: "new" },
|
|
||||||
{ text: "__(New folder)", id: "newdir" },
|
|
||||||
{ text: "__(Rename)", id: "rename" },
|
|
||||||
{ text: "__(Delete)", id: "delete" }
|
|
||||||
]);
|
|
||||||
m.set("onmenuselect", e => {
|
|
||||||
return this.ctxFileMenuHandle(e);
|
|
||||||
});
|
|
||||||
return m.show(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.bindKey("ALT-N", () => this.menuAction("new"));
|
|
||||||
this.bindKey("ALT-O", () => this.menuAction("open"));
|
|
||||||
this.bindKey("ALT-F", () => this.menuAction("opendir"));
|
|
||||||
this.bindKey("CTRL-S", () => this.menuAction("save"));
|
|
||||||
this.bindKey("ALT-W", () => this.menuAction("saveas"));
|
|
||||||
|
|
||||||
this.fileview.set("ondragndrop", e => {
|
|
||||||
const src = e.data.from.get("data").path.asFileHandle();
|
|
||||||
const des = e.data.to.get("data").path;
|
|
||||||
return src.move(`${des}/${src.basename}`)
|
|
||||||
.then(function(d) {
|
|
||||||
e.data.to.update(des);
|
|
||||||
return e.data.from.get("parent").update(src.parent().path);}).catch(e => this.error(__("Unable to move file/folder"), e));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on("filechange", data => {
|
|
||||||
let {
|
|
||||||
path
|
|
||||||
} = data.file;
|
|
||||||
if (data.type === "file") { ({
|
|
||||||
path
|
|
||||||
} = data.file.parent()); }
|
|
||||||
return this.fileview.update(path);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.loadExtensionMetaData();
|
|
||||||
this.initCommandPalete();
|
|
||||||
this.initSideBar();
|
|
||||||
return this.openFile(this.currfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
openFile(file) {
|
|
||||||
//find tab
|
|
||||||
const i = this.findTabByFile(file);
|
|
||||||
if (i !== -1) { return this.tabbar.set("selected", i); }
|
|
||||||
if (file.path.toString() === "Untitled") { return this.newTab(file); }
|
|
||||||
|
|
||||||
return file.read()
|
|
||||||
.then(d => {
|
|
||||||
file.cache = d || "";
|
|
||||||
return this.newTab(file);
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Unable to open: {0}", file.path), e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findTabByFile(file) {
|
|
||||||
const lst = this.tabbar.get("items");
|
|
||||||
const its = ((() => {
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < lst.length; i++) {
|
|
||||||
const d = lst[i];
|
|
||||||
if (d.hash() === file.hash()) {
|
|
||||||
result.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})());
|
|
||||||
if (its.length === 0) { return -1; }
|
|
||||||
return its[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
newTab(file) {
|
|
||||||
file.text = file.basename ? file.basename : file.path;
|
|
||||||
if (!file.cache) { file.cache = ""; }
|
|
||||||
file.um = new ace.UndoManager();
|
|
||||||
this.currfile.selected = false;
|
|
||||||
file.selected = true;
|
|
||||||
//console.log cnt
|
|
||||||
return this.tabbar.push(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
closeTab(it) {
|
|
||||||
this.tabbar.remove(it);
|
|
||||||
const cnt = this.tabbar.get("items").length;
|
|
||||||
|
|
||||||
if (cnt === 0) {
|
|
||||||
this.openFile("Untitled".asFileHandle());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.tabbar.set("selected", cnt - 1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
selecteTab(i) {
|
|
||||||
//return if i is @tabbar.get "selidx"
|
|
||||||
const file = (this.tabbar.get("items"))[i];
|
|
||||||
if (!file) { return; }
|
|
||||||
this.scheme.set("apptitle", file.text.toString());
|
|
||||||
//return if file is @currfile
|
|
||||||
if (this.currfile !== file) {
|
|
||||||
this.currfile.cache = this.editor.getValue();
|
|
||||||
this.currfile.cursor = this.editor.selection.getCursor();
|
|
||||||
this.currfile.selected = false;
|
|
||||||
this.currfile = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file.langmode) {
|
|
||||||
if (file.path.toString() !== "Untitled") {
|
|
||||||
const m = this.modes.getModeForPath(file.path);
|
|
||||||
file.langmode = { caption: m.caption, mode: m.mode };
|
|
||||||
} else {
|
|
||||||
file.langmode = { caption: "Text", mode: "ace/mode/text" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.editormux = true;
|
|
||||||
this.editor.getSession().setUndoManager(new ace.UndoManager());
|
|
||||||
this.editor.setValue(file.cache, -1);
|
|
||||||
this.editor.getSession().setMode(file.langmode.mode);
|
|
||||||
if (file.cursor) {
|
|
||||||
this.editor.renderer.scrollCursorIntoView({
|
|
||||||
row: file.cursor.row, column: file.cursor.column
|
|
||||||
}, 0.5);
|
|
||||||
this.editor.selection.moveTo(file.cursor.row, file.cursor.column);
|
|
||||||
}
|
|
||||||
this.editor.getSession().setUndoManager(file.um);
|
|
||||||
this.updateStatus();
|
|
||||||
return this.editor.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatus() {
|
|
||||||
const c = this.editor.session.selection.getCursor();
|
|
||||||
const l = this.editor.session.getLength();
|
|
||||||
this.editorstat.set("text", __("Row {0}, col {1}, lines: {2}", c.row + 1, c.column + 1, l));
|
|
||||||
return this.langstat.set("text", this.currfile.langmode.caption);
|
|
||||||
}
|
|
||||||
|
|
||||||
initSideBar() {
|
|
||||||
if (this.currdir) {
|
|
||||||
$(this.sidebar).show();
|
|
||||||
this.fileview.set("path", this.currdir.path);
|
|
||||||
} else {
|
|
||||||
$(this.sidebar).hide();
|
|
||||||
}
|
|
||||||
return this.trigger("resize");
|
|
||||||
}
|
|
||||||
|
|
||||||
addAction(action) {
|
|
||||||
this.spotlight.addAction(action);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addActions(list) {
|
|
||||||
this.spotlight.addActions(list);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
initCommandPalete() {
|
|
||||||
let v;
|
|
||||||
const themes = ace.require("ace/ext/themelist");
|
|
||||||
const cmdtheme = new CMDMenu(__("Change theme"));
|
|
||||||
for (let k in themes.themesByName) { v = themes.themesByName[k]; cmdtheme.addAction({ text: v.caption, theme: v.theme }); }
|
|
||||||
cmdtheme.onchildselect(function(d, r) {
|
|
||||||
const data = d.data.item.get("data");
|
|
||||||
r.editor.setTheme(data.theme);
|
|
||||||
return r.editor.focus();
|
|
||||||
});
|
|
||||||
this.spotlight.addAction(cmdtheme);
|
|
||||||
const cmdmode = new CMDMenu(__("Change language mode"));
|
|
||||||
for (v of Array.from(this.modes.modes)) { cmdmode.addAction({ text: v.caption, mode: v.mode }); }
|
|
||||||
cmdmode.onchildselect(function(d, r) {
|
|
||||||
const data = d.data.item.get("data");
|
|
||||||
r.editor.session.setMode(data.mode);
|
|
||||||
r.currfile.langmode = { caption: data.text, mode: data.mode };
|
|
||||||
r.updateStatus();
|
|
||||||
return r.editor.focus();
|
|
||||||
});
|
|
||||||
this.spotlight.addAction(cmdmode);
|
|
||||||
return this.addAction(CMDMenu.fromMenu(this.fileMenu()));
|
|
||||||
}
|
|
||||||
|
|
||||||
loadExtensionMetaData() {
|
|
||||||
return `${this.meta().path}/extensions.json`
|
|
||||||
.asFileHandle()
|
|
||||||
.read("json")
|
|
||||||
.then(d => {
|
|
||||||
return (() => {
|
|
||||||
const result = [];
|
|
||||||
for (var ext of Array.from(d)) {
|
|
||||||
if (this.extensions[ext.name]) {
|
|
||||||
this.extensions[ext.name].child = [];
|
|
||||||
result.push((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (let v of Array.from(ext.actions)) { result1.push(this.extensions[ext.name].addAction(v));
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})());
|
|
||||||
} else {
|
|
||||||
this.extensions[ext.name] = new CMDMenu(ext.text);
|
|
||||||
this.extensions[ext.name].name = ext.name;
|
|
||||||
for (let v of Array.from(ext.actions)) { this.extensions[ext.name].addAction(v); }
|
|
||||||
this.spotlight.addAction(this.extensions[ext.name]);
|
|
||||||
result.push(this.extensions[ext.name].onchildselect(e => {
|
|
||||||
return this.loadAndRunExtensionAction(e.data.item.get("data"));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})();
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Cannot load extension meta data"), e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
runExtensionAction(name, action) {
|
|
||||||
if (!CodePad.extensions[name]) { return this.error(__("Unable to find extension: {0}", name)); }
|
|
||||||
const ext = new (CodePad.extensions[name])(this);
|
|
||||||
if (!ext[action]) { return this.error(__("Unable to find action: {0}", action)); }
|
|
||||||
return ext.preload()
|
|
||||||
.then(() => ext[action]()).catch(e => {
|
|
||||||
return this.error(__("Unable to preload extension"), e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadAndRunExtensionAction(data) {
|
|
||||||
const {
|
|
||||||
name
|
|
||||||
} = data.parent;
|
|
||||||
const action = data.name;
|
|
||||||
//verify if the extension is load
|
|
||||||
if (!CodePad.extensions[name]) {
|
|
||||||
//load the extension
|
|
||||||
const path = `${this.meta().path}/extensions/${name}.js`;
|
|
||||||
return this._api.requires(path)
|
|
||||||
.then(() => this.runExtensionAction(name, action))
|
|
||||||
.catch(e => {
|
|
||||||
return this.error(__("unable to load extension: {0}", name), e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return this.runExtensionAction(name, action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileMenu() {
|
|
||||||
return {
|
|
||||||
text: __("File"),
|
|
||||||
child: [
|
|
||||||
{ text: __("New"), dataid: "new", shortcut: "A-N" },
|
|
||||||
{ text: __("Open"), dataid: "open", shortcut: "A-O" },
|
|
||||||
{ text: __("Open Folder"), dataid: "opendir", shortcut: "A-F" },
|
|
||||||
{ text: __("Save"), dataid: "save", shortcut: "C-S" },
|
|
||||||
{ text: __("Save as"), dataid: "saveas", shortcut: "A-W" }
|
|
||||||
],
|
|
||||||
onchildselect: (e, r) => {
|
|
||||||
return this.menuAction(e.data.item.get("data").dataid, r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxFileMenuHandle(e) {
|
|
||||||
const el = e.data.item;
|
|
||||||
if (!el) { return; }
|
|
||||||
const data = el.get("data");
|
|
||||||
if (!data) { return; }
|
|
||||||
let file = this.fileview.get("selectedFile");
|
|
||||||
let dir = this.currdir;
|
|
||||||
if (file && (file.type === "dir")) { dir = file.path.asFileHandle(); }
|
|
||||||
if (file && (file.type === "file")) { dir = file.path.asFileHandle().parent(); }
|
|
||||||
|
|
||||||
switch (data.id) {
|
|
||||||
case "new":
|
|
||||||
if (!dir) { return; }
|
|
||||||
return this.openDialog("PromptDialog", {
|
|
||||||
title: "__(New file)",
|
|
||||||
label: "__(File name)"
|
|
||||||
})
|
|
||||||
.then(d => {
|
|
||||||
const fp = `${dir.path}/${d}`.asFileHandle();
|
|
||||||
return fp.write("text/plain")
|
|
||||||
.then(r => {
|
|
||||||
return this.fileview.update(dir.path);
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Fail to create: {0}", e.stack), e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
case "newdir":
|
|
||||||
if (!dir) { return; }
|
|
||||||
return this.openDialog("PromptDialog", {
|
|
||||||
title: "__(New folder)",
|
|
||||||
label: "__(Folder name)"
|
|
||||||
})
|
|
||||||
.then(d => {
|
|
||||||
return dir.mk(d)
|
|
||||||
.then(r => {
|
|
||||||
return this.fileview.update(dir.path);
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Fail to create: {0}", dir.path), e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
case "rename":
|
|
||||||
if (!file) { return; }
|
|
||||||
return this.openDialog("PromptDialog", {
|
|
||||||
title: "__(Rename)",
|
|
||||||
label: "__(File name)",
|
|
||||||
value: file.filename
|
|
||||||
})
|
|
||||||
.then(d => {
|
|
||||||
if (d === file.filename) { return; }
|
|
||||||
file = file.path.asFileHandle();
|
|
||||||
dir = file.parent();
|
|
||||||
return file.move(`${dir.path}/${d}`)
|
|
||||||
.then(r => {
|
|
||||||
return this.fileview.update(dir.path);
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Fail to rename: {0}", file.path), e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
case "delete":
|
|
||||||
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; }
|
|
||||||
file = file.path.asFileHandle();
|
|
||||||
dir = file.parent();
|
|
||||||
return file.remove()
|
|
||||||
.then(r => {
|
|
||||||
return this.fileview.update(dir.path);
|
|
||||||
}).catch(e => {
|
|
||||||
return this.error(__("Fail to delete: {0}", file.path), e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
save(file) {
|
|
||||||
return file.write("text/plain")
|
|
||||||
.then(d => {
|
|
||||||
file.dirty = false;
|
|
||||||
file.text = file.basename;
|
|
||||||
this.tabbar.update();
|
|
||||||
return this.scheme.set("apptitle", `${this.currfile.basename}`);
|
|
||||||
}).catch(e => this.error(__("Unable to save file: {0}", file.path), e));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
saveAs() {
|
|
||||||
return this.openDialog("FileDialog", {
|
|
||||||
title: __("Save as"),
|
|
||||||
file: this.currfile
|
|
||||||
})
|
|
||||||
.then(f => {
|
|
||||||
let d = f.file.path.asFileHandle();
|
|
||||||
if (f.file.type === "file") { d = d.parent(); }
|
|
||||||
this.currfile.setPath(`${d.path}/${f.name}`);
|
|
||||||
return this.save(this.currfile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
menuAction(dataid, r) {
|
|
||||||
let me = this;
|
|
||||||
if (r) { me = r; }
|
|
||||||
switch (dataid) {
|
|
||||||
case "new":
|
|
||||||
return me.openFile("Untitled".asFileHandle());
|
|
||||||
case "open":
|
|
||||||
return me.openDialog("FileDialog", {
|
|
||||||
title: __("Open file"),
|
|
||||||
mimes: (Array.from(me.meta().mimes).filter((v) => v !== "dir"))
|
|
||||||
})
|
|
||||||
.then(f => me.openFile(f.file.path.asFileHandle()));
|
|
||||||
case "opendir":
|
|
||||||
return me.openDialog("FileDialog", {
|
|
||||||
title: __("Open folder"),
|
|
||||||
mimes: ["dir"]
|
|
||||||
})
|
|
||||||
.then(function(f) {
|
|
||||||
me.currdir = f.file.path.asFileHandle();
|
|
||||||
return me.initSideBar();
|
|
||||||
});
|
|
||||||
case "save":
|
|
||||||
me.currfile.cache = me.editor.getValue();
|
|
||||||
if (me.currfile.basename) { return me.save(me.currfile); }
|
|
||||||
return me.saveAs();
|
|
||||||
case "saveas":
|
|
||||||
me.currfile.cache = me.editor.getValue();
|
|
||||||
return me.saveAs();
|
|
||||||
default:
|
|
||||||
return console.log(dataid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup(evt) {
|
|
||||||
let v;
|
|
||||||
const dirties = ((() => {
|
|
||||||
const result = [];
|
|
||||||
for (v of Array.from(this.tabbar.get("items"))) { if (v.dirty) {
|
|
||||||
result.push(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})());
|
|
||||||
if (dirties.length === 0) { return; }
|
|
||||||
evt.preventDefault();
|
|
||||||
return this.openDialog("YesNoDialog", {
|
|
||||||
title: "__(Quit)",
|
|
||||||
text: __("Ignore all unsaved files: {0} ?", ((() => {
|
|
||||||
const result1 = [];
|
|
||||||
for (v of Array.from(dirties)) { result1.push(v.filename());
|
|
||||||
}
|
|
||||||
return result1;
|
|
||||||
})()).join(", ") )
|
|
||||||
}).then(d => {
|
|
||||||
if (d) {
|
|
||||||
for (v of Array.from(dirties)) { v.dirty = false; }
|
|
||||||
return this.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
menu() {
|
|
||||||
const menu = [
|
|
||||||
this.fileMenu(),
|
|
||||||
{
|
|
||||||
text: "__(View)",
|
|
||||||
child: [
|
|
||||||
{ text: "__(Command Palette)", dataid: "cmdpalette", shortcut: "A-P" }
|
|
||||||
],
|
|
||||||
onchildselect: (e, r) => {
|
|
||||||
return this.spotlight.run(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CMDMenu {
|
|
||||||
constructor(text, shortcut) {
|
|
||||||
this.text = text;
|
|
||||||
this.shortcut = shortcut;
|
|
||||||
this.child = [];
|
|
||||||
this.parent = undefined;
|
|
||||||
this.select = function(e) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
addAction(v) {
|
|
||||||
v.parent = this;
|
|
||||||
this.child.push(v);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addActions(list) {
|
|
||||||
return Array.from(list).map((v) => this.addAction(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
onchildselect(f) {
|
|
||||||
this.select = f;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
run(root) {
|
|
||||||
return root.openDialog(new CommandPalette(), this)
|
|
||||||
.then(d => {
|
|
||||||
const data = d.data.item.get("data");
|
|
||||||
if (data.run) { return data.run(root); }
|
|
||||||
return this.select(d, root);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CMDMenu.fromMenu = function(mn) {
|
|
||||||
const m = new CMDMenu(mn.text, mn.shortcut);
|
|
||||||
m.onchildselect(mn.onchildselect);
|
|
||||||
for (let v of Array.from(mn.child)) {
|
|
||||||
if (v.child) {
|
|
||||||
m.addAction(CMDMenu.fromMenu(v));
|
|
||||||
} else {
|
|
||||||
m.addAction(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
};
|
|
||||||
|
|
||||||
CodePad.CMDMenu = CMDMenu;
|
|
||||||
|
|
||||||
CodePad.dependencies = [
|
|
||||||
"os://scripts/ace/ace.js",
|
|
||||||
"os://scripts/ace/ext-language_tools.js",
|
|
||||||
"os://scripts/ace/ext-modelist.js",
|
|
||||||
"os://scripts/ace/ext-themelist.js"
|
|
||||||
];
|
|
||||||
this.OS.register("CodePad", CodePad);
|
|
1203
src/packages/CodePad/main.ts
Normal file
1203
src/packages/CodePad/main.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
# import the CodePad application module
|
# import the CodePad application module
|
||||||
App = this.OS.APP.CodePad
|
App = this.OS.application.CodePad
|
||||||
|
|
||||||
# define the extension
|
# define the extension
|
||||||
class App.extensions.{0} extends App.BaseExtension
|
class App.extensions.{0} extends App.BaseExtension
|
@ -1,4 +1,4 @@
|
|||||||
class {0} extends this.OS.GUI.BaseApplication
|
class {0} extends this.OS.application.BaseApplication
|
||||||
constructor: ( args ) ->
|
constructor: ( args ) ->
|
||||||
super "{0}", args
|
super "{0}", args
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
BLUE=\033[1;34m
|
BLUE=\033[1;34m
|
||||||
NC=\033[0m
|
NC=\033[0m
|
||||||
|
DIST=../../../dist/packages/$(PKG_NAME)
|
||||||
main: title clean js css copy
|
main: title clean js css copy
|
||||||
|
|
||||||
title:
|
title:
|
||||||
@ -9,7 +9,7 @@ title:
|
|||||||
|
|
||||||
module:
|
module:
|
||||||
- mkdir build
|
- mkdir build
|
||||||
for f in $(module_files); do (cat "../../../dist/packages/$(PKG_NAME)/$${f}"; echo) >>"build/main.js";done
|
for f in $(module_files); do (cat "$(DIST)/$${f}"; echo) >>"build/main.js";done
|
||||||
|
|
||||||
js: module
|
js: module
|
||||||
for f in $(libfiles); do (cat "$${f}"; echo) >> build/main.js; done
|
for f in $(libfiles); do (cat "$${f}"; echo) >> build/main.js; done
|
||||||
|
241
tests/testTag.ts
241
tests/testTag.ts
@ -472,8 +472,16 @@ test("Test gridview setter/getter", () => {
|
|||||||
expect(grid.selectedCell).toBe(cell.domel);
|
expect(grid.selectedCell).toBe(cell.domel);
|
||||||
expect(grid.selectedRow).toBe(row.domel);
|
expect(grid.selectedRow).toBe(row.domel);
|
||||||
expect(grid.selectedRows.length).toBe(2);
|
expect(grid.selectedRows.length).toBe(2);
|
||||||
const toprow: any = [{ text: "text -3" }, { text: "text -2" }, { text: "text -1" }];
|
const toprow: any = [
|
||||||
const botrow: any = [{ text: "text 10" }, { text: "text 11" }, { text: "text 12" }];
|
{ text: "text -3" },
|
||||||
|
{ text: "text -2" },
|
||||||
|
{ text: "text -1" },
|
||||||
|
];
|
||||||
|
const botrow: any = [
|
||||||
|
{ text: "text 10" },
|
||||||
|
{ text: "text 11" },
|
||||||
|
{ text: "text 12" },
|
||||||
|
];
|
||||||
grid.unshift(toprow);
|
grid.unshift(toprow);
|
||||||
grid.push(botrow);
|
grid.push(botrow);
|
||||||
expect(grid.rows.length).toBe(5);
|
expect(grid.rows.length).toBe(5);
|
||||||
@ -515,16 +523,229 @@ test("Test gridview behavior", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Treeview
|
// Treeview
|
||||||
test("Treeview item setter/getter", ()=>{
|
test("Treeview item setter/getter", () => {
|
||||||
|
const item = new OS.GUI.tag.SimpleTreeViewItem();
|
||||||
});
|
item.uify();
|
||||||
test("Treeview item behavior", ()=>{
|
const tdata = get_treedata();
|
||||||
|
item.data = tdata;
|
||||||
|
expect(item.data).toBe(tdata);
|
||||||
|
expect(item.nodes).toBe(tdata.nodes);
|
||||||
|
expect(item.open).toBe(false);
|
||||||
|
expect(item.indent).toBe(0);
|
||||||
|
expect(item.treepath).toBe(item.aid.toString());
|
||||||
|
expect(item.parent).toBeUndefined();
|
||||||
|
item.update("expand");
|
||||||
|
expect(item.open).toBe(true);
|
||||||
|
const child = item.nodes[2].domel;
|
||||||
|
expect(child.data).toBe(item.nodes[2]);
|
||||||
|
expect(child.indent).toBe(1);
|
||||||
|
expect(child.open).toBe(true);
|
||||||
|
const childtree = $(child).closest("afx-tree-view")[0];
|
||||||
|
expect(childtree).toBeDefined();
|
||||||
|
expect(child.treepath).toBe(`${item.aid}/${childtree.aid}`);
|
||||||
|
expect(child.parent).toBe(childtree);
|
||||||
|
child.selected = true;
|
||||||
|
expect(child.selected).toBe(true);
|
||||||
});
|
});
|
||||||
// Treeview
|
// Treeview
|
||||||
test("Treeview setter/getter", ()=>{
|
test("Treeview setter/getter", () => {
|
||||||
|
const item = new OS.GUI.tag.TreeViewTag();
|
||||||
|
item.uify();
|
||||||
|
const tdata = get_treedata();
|
||||||
|
item.data = tdata;
|
||||||
|
item.expandAll();
|
||||||
|
expect(item.selectedItem).toBeUndefined();
|
||||||
|
expect(item.data).toBe(tdata);
|
||||||
|
expect(item.treeroot).toBeUndefined();
|
||||||
|
expect(item.treepath).toBe(item.aid.toString());
|
||||||
|
expect(item.indent).toBe(0);
|
||||||
|
expect(item.dragndrop).toBe(false);
|
||||||
|
expect(item.itemtag).toBe("afx-tree-view-item");
|
||||||
|
const child = item.data.nodes[2].domel;
|
||||||
|
expect(child).toBeDefined();
|
||||||
|
const childtree = $(child).closest("afx-tree-view")[0];
|
||||||
|
expect(child.treeroot).toBe(item);
|
||||||
|
expect(childtree.is_leaf()).toBe(false);
|
||||||
|
});
|
||||||
|
test("Treeview behavior", () => {
|
||||||
|
const item = new OS.GUI.tag.TreeViewTag();
|
||||||
|
item.uify();
|
||||||
|
const tdata = get_treedata();
|
||||||
|
item.data = tdata;
|
||||||
|
item.expandAll();
|
||||||
|
const child = item.data.nodes[2].domel;
|
||||||
|
const cb = jest.fn();
|
||||||
|
item.ontreeselect = cb;
|
||||||
|
item.ontreedbclick = cb;
|
||||||
|
|
||||||
|
$(">div", child).trigger("click");
|
||||||
|
expect(cb).toBeCalledTimes(1);
|
||||||
|
expect(item.selectedItem).toBe(child);
|
||||||
|
const anotherchild = item.data.nodes[1].domel;
|
||||||
|
anotherchild.selected = true;
|
||||||
|
expect(cb).toBeCalledTimes(2);
|
||||||
|
expect(item.selectedItem).toBe(anotherchild);
|
||||||
|
expect(child.selected).toBe(false);
|
||||||
|
$(">div", child).trigger("dblclick");
|
||||||
|
expect(cb).toBeCalledTimes(3);
|
||||||
|
expect(item.selectedItem).toBe(child);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calendar tag
|
||||||
|
test("Calendar tag setter/getter", () => {
|
||||||
|
const item = new OS.GUI.tag.CalendarTag();
|
||||||
|
item.uify();
|
||||||
|
const now = {
|
||||||
|
d: new Date().getDate(),
|
||||||
|
m: new Date().getMonth(),
|
||||||
|
y: new Date().getFullYear(),
|
||||||
|
};
|
||||||
|
expect(item.selectedDate).toStrictEqual(new Date(now.y, now.m, now.d));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Calendar tag behavior", () => {
|
||||||
|
const item = new OS.GUI.tag.CalendarTag();
|
||||||
|
const cb = jest.fn();
|
||||||
|
item.ondateselect = cb;
|
||||||
|
item.uify();
|
||||||
|
expect(cb).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// File view tag
|
||||||
|
|
||||||
|
function get_files_data() {
|
||||||
|
return JSON.parse(`\
|
||||||
|
[{
|
||||||
|
"permissions": " (755)",
|
||||||
|
"type": "dir",
|
||||||
|
"mtime": "2017-07-23T22:53:10",
|
||||||
|
"size": 102,
|
||||||
|
"path": "home:////desktop",
|
||||||
|
"ctime": "2017-07-23T22:53:10",
|
||||||
|
"filename": "desktop",
|
||||||
|
"perm": {
|
||||||
|
"owner": {
|
||||||
|
"write": true,
|
||||||
|
"read": true,
|
||||||
|
"exec": true
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": true
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mime": "",
|
||||||
|
"uid": 501,
|
||||||
|
"gid": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permissions": " (644)",
|
||||||
|
"type": "file",
|
||||||
|
"mtime": "2017-07-30T00:55:34",
|
||||||
|
"size": 2821,
|
||||||
|
"path": "home:////settings.json",
|
||||||
|
"ctime": "2017-07-30T00:55:34",
|
||||||
|
"filename": "settings.json",
|
||||||
|
"perm": {
|
||||||
|
"owner": {
|
||||||
|
"write": true,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mime": "application/json",
|
||||||
|
"uid": 501,
|
||||||
|
"gid": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permissions": " (644)",
|
||||||
|
"type": "file",
|
||||||
|
"mtime": "2017-07-11T20:30:51",
|
||||||
|
"size": 575,
|
||||||
|
"path": "home:////helloworld.xml",
|
||||||
|
"ctime": "2017-07-11T20:30:51",
|
||||||
|
"filename": "helloworld.xml",
|
||||||
|
"perm": {
|
||||||
|
"owner": {
|
||||||
|
"write": true,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"write": false,
|
||||||
|
"read": true,
|
||||||
|
"exec": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mime": "application/xml",
|
||||||
|
"uid": 501,
|
||||||
|
"gid": 20
|
||||||
|
}
|
||||||
|
]`);
|
||||||
|
}
|
||||||
|
test("File view setter/getter", () => {
|
||||||
|
const fileview = new OS.GUI.tag.FileViewTag();
|
||||||
|
fileview.uify();
|
||||||
|
expect(fileview.data.length).toBe(0);
|
||||||
|
expect(fileview.status).toBe(true);
|
||||||
|
expect(fileview.view).toBe("list");
|
||||||
|
expect(fileview.showhidden).toBe(false);
|
||||||
|
expect(fileview.chdir).toBe(true);
|
||||||
|
fileview.status = false;
|
||||||
|
expect(fileview.status).toBe(false);
|
||||||
|
fileview.view = "icon";
|
||||||
|
expect(fileview.view).toBe("icon");
|
||||||
|
fileview.showhidden = true;
|
||||||
|
expect(fileview.showhidden).toBe(true);
|
||||||
|
fileview.chdir = false;
|
||||||
|
expect(fileview.chdir).toBe(false);
|
||||||
|
expect(fileview.selectedFile).toBeUndefined();
|
||||||
|
fileview.path = "home://";
|
||||||
|
expect(fileview.path).toBe("home://");
|
||||||
|
const data = get_files_data();
|
||||||
|
fileview.data = data;
|
||||||
|
expect(fileview.data).toBe(data);
|
||||||
|
|
||||||
});
|
});
|
||||||
test("Treeview behavior", ()=>{
|
|
||||||
|
|
||||||
});
|
test("File view behavior", () => {
|
||||||
|
const fileview = new OS.GUI.tag.FileViewTag();
|
||||||
|
fileview.uify();
|
||||||
|
fileview.view = "icon";
|
||||||
|
const cb = jest.fn();
|
||||||
|
fileview.onfileselect = cb;
|
||||||
|
fileview.onfileopen = cb;
|
||||||
|
const data = get_files_data();
|
||||||
|
data[2].selected = true;
|
||||||
|
fileview.data = data;
|
||||||
|
expect(cb).toBeCalledTimes(1);
|
||||||
|
const el = fileview.selectedFile;
|
||||||
|
expect(el).toBe(data[2]);
|
||||||
|
$("li", el.domel).trigger("dblclick");
|
||||||
|
expect(cb).toBeCalledTimes(2);
|
||||||
|
/* fileview.view = "tree";
|
||||||
|
fileview.update("expand");
|
||||||
|
const treeitem = fileview.data[0].domel;
|
||||||
|
expect(treeitem.tagName).toBe("AFX-TREE-VIEW-ITEM"); */
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user