mirror of
https://github.com/lxsang/antos-frontend.git
synced 2024-12-27 01:38:21 +01:00
move some API from CodePad to system API
This commit is contained in:
parent
b2e2cbeda5
commit
e657c98688
Binary file not shown.
418
src/core/vfs.ts
418
src/core/vfs.ts
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
//along with this program. If not, see https://www.gnu.org/licenses/.
|
//along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
type VFSFileHandleClass = { new (...args: any[]): OS.API.VFS.BaseFileHandle };
|
type VFSFileHandleClass = { new(...args: any[]): OS.API.VFS.BaseFileHandle };
|
||||||
interface String {
|
interface String {
|
||||||
/**
|
/**
|
||||||
* Convert a string to VFS file handle.
|
* Convert a string to VFS file handle.
|
||||||
@ -164,6 +164,8 @@ namespace OS {
|
|||||||
* AntOS Virtual File System (VFS)
|
* AntOS Virtual File System (VFS)
|
||||||
*/
|
*/
|
||||||
export namespace VFS {
|
export namespace VFS {
|
||||||
|
declare var JSZip: any;
|
||||||
|
|
||||||
String.prototype.asFileHandle = function (): BaseFileHandle {
|
String.prototype.asFileHandle = function (): BaseFileHandle {
|
||||||
const list = this.split("://");
|
const list = this.split("://");
|
||||||
const handles = API.VFS.findHandles(list[0]);
|
const handles = API.VFS.findHandles(list[0]);
|
||||||
@ -1316,8 +1318,7 @@ namespace OS {
|
|||||||
* @class PackageFileHandle
|
* @class PackageFileHandle
|
||||||
* @extends {RemoteFileHandle}
|
* @extends {RemoteFileHandle}
|
||||||
*/
|
*/
|
||||||
export class PackageFileHandle extends RemoteFileHandle
|
export class PackageFileHandle extends RemoteFileHandle {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Creates an instance of PackageFileHandle.
|
*Creates an instance of PackageFileHandle.
|
||||||
@ -1325,12 +1326,11 @@ namespace OS {
|
|||||||
* @memberof PackageFileHandle
|
* @memberof PackageFileHandle
|
||||||
*/
|
*/
|
||||||
constructor(pkg_path: string) {
|
constructor(pkg_path: string) {
|
||||||
var error:FormattedString|string;
|
var error: FormattedString | string;
|
||||||
var pkg_name: string;
|
var pkg_name: string;
|
||||||
super(pkg_path);
|
super(pkg_path);
|
||||||
// now find the correct path
|
// now find the correct path
|
||||||
if(!this.genealogy || this.genealogy.length == 0)
|
if (!this.genealogy || this.genealogy.length == 0) {
|
||||||
{
|
|
||||||
error = __("Invalid package path");
|
error = __("Invalid package path");
|
||||||
announcer.oserror(error, API.throwe(error));
|
announcer.oserror(error, API.throwe(error));
|
||||||
throw new Error(error.__());
|
throw new Error(error.__());
|
||||||
@ -1338,14 +1338,12 @@ namespace OS {
|
|||||||
else {
|
else {
|
||||||
// get the correct path of the package
|
// get the correct path of the package
|
||||||
pkg_name = this.genealogy.shift();
|
pkg_name = this.genealogy.shift();
|
||||||
if(OS.setting.system.packages[pkg_name])
|
if (OS.setting.system.packages[pkg_name]) {
|
||||||
{
|
|
||||||
this.setPath(OS.setting.system.packages[pkg_name].path + "/" + this.genealogy.join("/"));
|
this.setPath(OS.setting.system.packages[pkg_name].path + "/" + this.genealogy.join("/"));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
error = __("Package not found {0}", pkg_name);
|
error = __("Package not found {0}", pkg_name);
|
||||||
announcer.oserror(error,API.throwe(error));
|
announcer.oserror(error, API.throwe(error));
|
||||||
throw new Error(error.__());
|
throw new Error(error.__());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1427,8 +1425,7 @@ namespace OS {
|
|||||||
const result = [];
|
const result = [];
|
||||||
for (let k in OS.setting.system.packages) {
|
for (let k in OS.setting.system.packages) {
|
||||||
const v = OS.setting.system.packages[k];
|
const v = OS.setting.system.packages[k];
|
||||||
if(v.app)
|
if (v.app) {
|
||||||
{
|
|
||||||
result.push(v);
|
result.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1599,7 +1596,7 @@ namespace OS {
|
|||||||
//read the file
|
//read the file
|
||||||
if (t === "binary") {
|
if (t === "binary") {
|
||||||
//return API.handle.fileblob(this.path);
|
//return API.handle.fileblob(this.path);
|
||||||
return API.blob(this.path+ "?_=" + new Date().getTime());
|
return API.blob(this.path + "?_=" + new Date().getTime());
|
||||||
}
|
}
|
||||||
return API.get(this.path, t ? t : "text");
|
return API.get(this.path, t ? t : "text");
|
||||||
}
|
}
|
||||||
@ -1760,6 +1757,399 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
API.VFS.register("^shared$", SharedFileHandle);
|
API.VFS.register("^shared$", SharedFileHandle);
|
||||||
|
|
||||||
|
/**Utilities global functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a file content from a zip archive
|
||||||
|
*
|
||||||
|
* The content type should be:
|
||||||
|
* - base64 : the result will be a string, the binary in a base64 form.
|
||||||
|
* - text (or string): the result will be an unicode string.
|
||||||
|
* - binarystring: the result will be a string in “binary” form, using 1 byte per char (2 bytes).
|
||||||
|
* - array: the result will be an Array of bytes (numbers between 0 and 255).
|
||||||
|
* - uint8array : the result will be a Uint8Array. This requires a compatible browser.
|
||||||
|
* - arraybuffer : the result will be a ArrayBuffer. This requires a compatible browser.
|
||||||
|
* - blob : the result will be a Blob. This requires a compatible browser.
|
||||||
|
* - nodebuffer : the result will be a nodejs Buffer. This requires nodejs.
|
||||||
|
*
|
||||||
|
* If file_name is not specified, the first file_name in the zip archive will be read
|
||||||
|
* @export
|
||||||
|
* @param {string} file zip file
|
||||||
|
* @param {string} type content type to read
|
||||||
|
* @param {string} [file_name] the file should be read from the zip archive
|
||||||
|
* @return {*} {Promise<any>}
|
||||||
|
*/
|
||||||
|
export function readFileFromZip(file: string, type: string, file_name?: string): Promise<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
await API.requires("os://scripts/jszip.min.js");
|
||||||
|
try {
|
||||||
|
const data = await file.asFileHandle().read("binary");
|
||||||
|
try {
|
||||||
|
const zip = await JSZip.loadAsync(data);
|
||||||
|
if (!file_name) {
|
||||||
|
for (let name in zip.files) {
|
||||||
|
file_name = name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const udata = await zip.file(file_name).async(type);
|
||||||
|
resolve(udata);
|
||||||
|
} catch (e_2) {
|
||||||
|
return reject(__e(e_2));
|
||||||
|
}
|
||||||
|
} catch (e_1) {
|
||||||
|
return reject(__e(e_1));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
} catch (e_3) {
|
||||||
|
return reject(__e(e_3));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cat al file to a single out-put
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string[]} list list of VFS files
|
||||||
|
* @param {string} data input data string that will be cat to the files content
|
||||||
|
* @return {*} {Promise<string>}
|
||||||
|
*/
|
||||||
|
export function 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 cat(list, data)
|
||||||
|
.then((d) => resolve(d))
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read all files content to on the list
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string[]} list list of VFS files
|
||||||
|
* @param {GenericObject<string>[]} contents content array
|
||||||
|
* @return {*} {Promise<GenericObject<string>[]>}
|
||||||
|
*/
|
||||||
|
export function read_files(list: string[], contents: GenericObject<string>[]): Promise<GenericObject<string>[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve(contents);
|
||||||
|
}
|
||||||
|
const file = list.splice(0, 1)[0].asFileHandle();
|
||||||
|
return file
|
||||||
|
.read()
|
||||||
|
.then((text: string) => {
|
||||||
|
contents.push({
|
||||||
|
path: file.path,
|
||||||
|
content: text
|
||||||
|
});
|
||||||
|
return read_files(list, contents)
|
||||||
|
.then((d) => resolve(d))
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy files to a folder
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string[]} files list of files
|
||||||
|
* @param {string} to destination folder
|
||||||
|
* @return {*} {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function copy(files: string[], to: string): Promise<void> {
|
||||||
|
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 copy(
|
||||||
|
list,
|
||||||
|
`${desdir.path}/${file.basename}`
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return 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: ArrayBuffer) => {
|
||||||
|
const d = await tof
|
||||||
|
.setCache(
|
||||||
|
new Blob([data], {
|
||||||
|
type: file.info.mime,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.write(file.info.mime);
|
||||||
|
try {
|
||||||
|
await copy(files, to);
|
||||||
|
return resolve();
|
||||||
|
} catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a list of files to the zip archive
|
||||||
|
*
|
||||||
|
* @param {string[]} list list of VFS files
|
||||||
|
* @param {*} zip JSZip handle
|
||||||
|
* @param {string} base root path of all added files in the zip
|
||||||
|
* @return {*} {Promise<any>}
|
||||||
|
*/
|
||||||
|
function 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 aradd(
|
||||||
|
l,
|
||||||
|
zip,
|
||||||
|
`${base}${file.basename}/`
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return 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(async (d: any) => {
|
||||||
|
const zpath = `${base}${file.basename}`.replace(
|
||||||
|
/^\/+|\/+$/g,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
zip.file(zpath, d, { binary: true });
|
||||||
|
try {
|
||||||
|
await aradd(list, zip, base);
|
||||||
|
return resolve(zip);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return reject(__e(e));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a zip archive from a folder
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} src source folder
|
||||||
|
* @param {string} dest destination archive
|
||||||
|
* @return {*} {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function mkar(src: string, dest: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return new Promise(async (r, e) => {
|
||||||
|
try {
|
||||||
|
await API.requires("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 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();
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of directories
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string[]} list of directories to be created
|
||||||
|
* @return {*} {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function mkdirAll(list: string[]): Promise<void> {
|
||||||
|
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) => {
|
||||||
|
return mkdirAll(list)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {Array<string[]>} list of templates mapping files
|
||||||
|
* @param {string} path path stored create files
|
||||||
|
* @param {string} name
|
||||||
|
* @return {*} {Promise<void>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make files from a set of template files
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {Array<string[]>} list mapping paths between templates files and created files
|
||||||
|
* @param {string} path files destination
|
||||||
|
* @param {(data: string) => string} callback: pre-processing files content before writing to destination files
|
||||||
|
* @return {*} {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function mktpl(
|
||||||
|
list: Array<string[]>,
|
||||||
|
path: string,
|
||||||
|
callback: (data: string) => string
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
const item = list.splice(0, 1)[0];
|
||||||
|
return `${path}/${item[0]}`
|
||||||
|
.asFileHandle()
|
||||||
|
.read()
|
||||||
|
.then((data) => {
|
||||||
|
const file = item[1].asFileHandle();
|
||||||
|
return file
|
||||||
|
.setCache(callback(data))
|
||||||
|
.write("text/plain")
|
||||||
|
.then(() => {
|
||||||
|
return mktpl(list, path, callback)
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e: Error) => reject(__e(e)));
|
||||||
|
})
|
||||||
|
.catch((e) => reject(__e(e)));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,41 +7,121 @@ namespace OS {
|
|||||||
* Wrapper model for the ACE text editor
|
* Wrapper model for the ACE text editor
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @class CodePadACEModel
|
* @class ACEModel
|
||||||
* @extends {CodePadBaseEditorModel}
|
* @extends {BaseEditorModel}
|
||||||
*/
|
*/
|
||||||
export class CodePadACEModel extends CodePadBaseEditorModel {
|
export class ACEModel extends BaseEditorModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current editor mode
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {GenericObject<any>}
|
||||||
|
* @memberof ACEModel
|
||||||
|
*/
|
||||||
|
private mode: GenericObject<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to ACE language modes
|
* Reference to ACE language modes
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {GenericObject<any>}
|
* @type {GenericObject<any>}
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
private modes: GenericObject<any>;
|
private modes: GenericObject<any>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of CodePadACEModel.
|
* Creates an instance of ACEModel.
|
||||||
* @param {CodePad} app CodePad instance
|
* @param {ACEModel} app instance
|
||||||
* @param {GUI.tag.TabBarTag} tabbar tabbar element
|
* @param {GUI.tag.TabBarTag} tabbar tabbar element
|
||||||
* @param {HTMLElement} editorarea main editor container element
|
* @param {HTMLElement} editorarea main editor container element
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
constructor(app: CodePad, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
constructor(app: BaseApplication, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
||||||
ace.config.set("basePath", "scripts/ace");
|
ace.config.set("basePath", "scripts/ace");
|
||||||
ace.require("ace/ext/language_tools");
|
ace.require("ace/ext/language_tools");
|
||||||
super(app, tabbar, editorarea);
|
super(app, tabbar, editorarea);
|
||||||
this.modes = ace.require("ace/ext/modelist");
|
this.modes = ace.require("ace/ext/modelist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the editor
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @memberof ACEModel
|
||||||
|
*/
|
||||||
|
protected resetEditor(): void {
|
||||||
|
this.setValue("");
|
||||||
|
this.editor.getSession().setUndoManager(new ace.UndoManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a text model from the current editor session
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @return {*}
|
||||||
|
* @memberof ACEModel
|
||||||
|
*/
|
||||||
|
protected getTexModel() {
|
||||||
|
const textModel = {} as any;
|
||||||
|
textModel.cursor = this.editor.getCursorPosition();
|
||||||
|
textModel.cache = this.getValue();
|
||||||
|
textModel.um = this.editor.session.getUndoManager();
|
||||||
|
textModel.langmode = this.mode;
|
||||||
|
return textModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set text model to current editor session
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {*} model
|
||||||
|
* @memberof ACEModel
|
||||||
|
*/
|
||||||
|
protected setTextModel(model: any): void {
|
||||||
|
this.editor.getSession().setUndoManager(new ace.UndoManager());
|
||||||
|
this.setValue(model.cache);
|
||||||
|
this.setMode(model.langmode);
|
||||||
|
|
||||||
|
if (model.cursor) {
|
||||||
|
this.setCursor(model.cursor);
|
||||||
|
}
|
||||||
|
this.editor.getSession().setUndoManager(model.um);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new editor model from file
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @param {EditorFileHandle} file
|
||||||
|
* @return {*} {*}
|
||||||
|
* @memberof ACEModel
|
||||||
|
*/
|
||||||
|
protected newTextModelFrom(file: EditorFileHandle): any {
|
||||||
|
const textModel = {} as any;
|
||||||
|
textModel.um = new ace.UndoManager();
|
||||||
|
textModel.cache = file.cache;
|
||||||
|
textModel.cursor = undefined;
|
||||||
|
if (file.path.toString() !== "Untitled") {
|
||||||
|
textModel.langmode = this.getModeForPath(file.path);
|
||||||
|
} else {
|
||||||
|
textModel.langmode = {
|
||||||
|
text: "Text",
|
||||||
|
mode: "ace/mode/text",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return textModel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get language modes
|
* Get language modes
|
||||||
*
|
*
|
||||||
* @return {*} {GenericObject<any>[]}
|
* @return {*} {GenericObject<any>[]}
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
getModes(): GenericObject<any>[] {
|
getModes(): GenericObject<any>[] {
|
||||||
const list = [];
|
const list = [];
|
||||||
@ -57,33 +137,20 @@ namespace OS {
|
|||||||
* Set the editor theme
|
* Set the editor theme
|
||||||
*
|
*
|
||||||
* @param {string} theme theme name
|
* @param {string} theme theme name
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
setTheme(theme: string): void {
|
setTheme(theme: string): void {
|
||||||
this.editor.setTheme(theme);
|
this.editor.setTheme(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the editor undo manager
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @param {GenericObject<any>} um
|
|
||||||
* @memberof CodePadACEModel
|
|
||||||
*/
|
|
||||||
protected setUndoManager(um: GenericObject<any>): void {
|
|
||||||
this.editor.getSession().setUndoManager(um);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the editor cursor
|
* Set the editor cursor
|
||||||
*
|
*
|
||||||
* @protected
|
* @private
|
||||||
* @param {GenericObject<any>} c cursor option
|
* @param {GenericObject<any>} c cursor option
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
protected setCursor(c: GenericObject<any>): void {
|
private setCursor(c: GenericObject<any>): void {
|
||||||
this.editor.renderer.scrollCursorIntoView(
|
this.editor.renderer.scrollCursorIntoView(
|
||||||
{
|
{
|
||||||
row: c.row,
|
row: c.row,
|
||||||
@ -110,43 +177,21 @@ namespace OS {
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param {GenericObject<any>} m language mode object
|
* @param {GenericObject<any>} m language mode object
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
setMode(m: GenericObject<any>): void {
|
setMode(m: GenericObject<any>): void {
|
||||||
this.currfile.langmode = m;
|
this.mode = m;
|
||||||
this.editor.getSession().setMode(m.mode);
|
this.editor.getSession().setMode(m.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current editor cursor position
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @return {*} {GenericObject<any>}
|
|
||||||
* @memberof CodePadACEModel
|
|
||||||
*/
|
|
||||||
protected getCursor(): GenericObject<any> {
|
|
||||||
return this.editor.getCursorPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a new UndoManage instance
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @return {*} {GenericObject<any>}
|
|
||||||
* @memberof CodePadACEModel
|
|
||||||
*/
|
|
||||||
protected newUndoManager(): GenericObject<any> {
|
|
||||||
return new ace.UndoManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to the editor instance
|
* Reference to the editor instance
|
||||||
*
|
*
|
||||||
* @protected
|
* @protected
|
||||||
* @type {GenericObject<any>}
|
* @type {GenericObject<any>}
|
||||||
* @memberof CodePad
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
protected editor: GenericObject<any>;
|
protected editor: GenericObject<any>;
|
||||||
|
|
||||||
@ -156,7 +201,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @protected
|
* @protected
|
||||||
* @param {HTMLElement} el editor container DOM
|
* @param {HTMLElement} el editor container DOM
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
protected editorSetup(el: HTMLElement): void {
|
protected editorSetup(el: HTMLElement): void {
|
||||||
this.editor = ace.edit(el);
|
this.editor = ace.edit(el);
|
||||||
@ -191,7 +236,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @param {string} evt_str event name
|
* @param {string} evt_str event name
|
||||||
* @param {() => void} callback callback function
|
* @param {() => void} callback callback function
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
on(evt_str: string, callback: () => void): void {
|
on(evt_str: string, callback: () => void): void {
|
||||||
switch (evt_str) {
|
switch (evt_str) {
|
||||||
@ -213,7 +258,7 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Resize the editor
|
* Resize the editor
|
||||||
*
|
*
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
resize(): void {
|
resize(): void {
|
||||||
this.editor.resize();
|
this.editor.resize();
|
||||||
@ -223,7 +268,7 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Focus on the editor
|
* Focus on the editor
|
||||||
*
|
*
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
focus(): void {
|
focus(): void {
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
@ -236,9 +281,9 @@ namespace OS {
|
|||||||
* @protected
|
* @protected
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @return {*} {GenericObject<any>}
|
* @return {*} {GenericObject<any>}
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
protected getModeForPath(path: string): GenericObject<any> {
|
protected getModeForPath(path: string): GenericObject<any> {
|
||||||
const m = this.modes.getModeForPath(path);
|
const m = this.modes.getModeForPath(path);
|
||||||
return {
|
return {
|
||||||
text: m.caption,
|
text: m.caption,
|
||||||
@ -250,7 +295,7 @@ namespace OS {
|
|||||||
* Get the editor status
|
* Get the editor status
|
||||||
*
|
*
|
||||||
* @return {*} {GenericObject<any>}
|
* @return {*} {GenericObject<any>}
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
getEditorStatus(): GenericObject<any> {
|
getEditorStatus(): GenericObject<any> {
|
||||||
const c = this.editor.session.selection.getCursor();
|
const c = this.editor.session.selection.getCursor();
|
||||||
@ -259,7 +304,7 @@ namespace OS {
|
|||||||
row: c.row,
|
row: c.row,
|
||||||
column: c.column,
|
column: c.column,
|
||||||
line: l,
|
line: l,
|
||||||
langmode: this.currfile.langmode,
|
langmode: this.mode,
|
||||||
file: this.currfile.path
|
file: this.currfile.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +314,7 @@ namespace OS {
|
|||||||
* Get editor value
|
* Get editor value
|
||||||
*
|
*
|
||||||
* @return {*} {string}
|
* @return {*} {string}
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
return this.editor.getValue();
|
return this.editor.getValue();
|
||||||
@ -280,7 +325,7 @@ namespace OS {
|
|||||||
* Set editor value
|
* Set editor value
|
||||||
*
|
*
|
||||||
* @param {string} value
|
* @param {string} value
|
||||||
* @memberof CodePadACEModel
|
* @memberof ACEModel
|
||||||
*/
|
*/
|
||||||
setValue(value: string): void {
|
setValue(value: string): void {
|
||||||
this.editor.setValue(value, -1);
|
this.editor.setValue(value, -1);
|
||||||
|
@ -113,7 +113,7 @@ namespace OS {
|
|||||||
try {
|
try {
|
||||||
await this.build(meta, false);
|
await this.build(meta, false);
|
||||||
try {
|
try {
|
||||||
return this.mkar(
|
return API.VFS.mkar(
|
||||||
`${meta.root}/build/debug`,
|
`${meta.root}/build/debug`,
|
||||||
`${meta.root}/build/release/${meta.name}.zip`
|
`${meta.root}/build/release/${meta.name}.zip`
|
||||||
);
|
);
|
||||||
@ -160,14 +160,16 @@ namespace OS {
|
|||||||
["templates/sdk-README.tpl", `${rpath}/README.md`],
|
["templates/sdk-README.tpl", `${rpath}/README.md`],
|
||||||
["templates/sdk-scheme.tpl", `${rpath}/assets/scheme.html`],
|
["templates/sdk-scheme.tpl", `${rpath}/assets/scheme.html`],
|
||||||
];
|
];
|
||||||
this.mkdirAll(dirs)
|
API.VFS.mkdirAll(dirs)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
try {
|
try {
|
||||||
await this.mkfileAll(files, path, name);
|
await API.VFS.mktpl(files, this.basedir(), (data) => {
|
||||||
|
return data.format(name, `${path}/${name}`);
|
||||||
|
});
|
||||||
this.app.currdir = rpath.asFileHandle();
|
this.app.currdir = rpath.asFileHandle();
|
||||||
this.app.toggleSideBar();
|
this.app.toggleSideBar();
|
||||||
return this.app.eum.active.openFile(
|
return this.app.eum.active.openFile(
|
||||||
`${rpath}/README.md`.asFileHandle() as application.CodePadFileHandle
|
`${rpath}/README.md`.asFileHandle() as application.EditorFileHandle
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return this.logger().error(
|
return this.logger().error(
|
||||||
@ -226,7 +228,7 @@ namespace OS {
|
|||||||
return resolve(AntOSDK.corelib["ts"]);
|
return resolve(AntOSDK.corelib["ts"]);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const code = await this.loadzip(`${path}.zip`, "text");
|
const code = await API.VFS.readFileFromZip(`${path}.zip`, "text");
|
||||||
AntOSDK.corelib["ts"] = ts.createSourceFile(path, code, ts.ScriptTarget.Latest);
|
AntOSDK.corelib["ts"] = ts.createSourceFile(path, code, ts.ScriptTarget.Latest);
|
||||||
return resolve(AntOSDK.corelib["ts"]);
|
return resolve(AntOSDK.corelib["ts"]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -252,7 +254,7 @@ namespace OS {
|
|||||||
try {
|
try {
|
||||||
await this.load_corelib(core_lib);
|
await this.load_corelib(core_lib);
|
||||||
const arr = [];
|
const arr = [];
|
||||||
this.read_files(files, arr).then((_result) => {
|
API.VFS.read_files(files, arr).then((_result) => {
|
||||||
const libs: string[] = arr.map((e) => e.path)
|
const libs: string[] = arr.map((e) => e.path)
|
||||||
libs.unshift(core_lib);
|
libs.unshift(core_lib);
|
||||||
const src_files: GenericObject<any> = {};
|
const src_files: GenericObject<any> = {};
|
||||||
@ -310,10 +312,14 @@ namespace OS {
|
|||||||
const libs = [
|
const libs = [
|
||||||
`${this.basedir()}/libs/terser.min.js`,
|
`${this.basedir()}/libs/terser.min.js`,
|
||||||
];
|
];
|
||||||
|
if (!meta.coffees)
|
||||||
|
meta.coffees = [];
|
||||||
if (meta.coffees.length > 0) {
|
if (meta.coffees.length > 0) {
|
||||||
libs.push(`${this.basedir()}/libs/coffeescript.js`);
|
libs.push(`${this.basedir()}/libs/coffeescript.js`);
|
||||||
}
|
}
|
||||||
if (meta.ts.length > 0) {
|
if (!meta.ts)
|
||||||
|
meta.ts = [];
|
||||||
|
if (meta.ts && meta.ts.length > 0) {
|
||||||
libs.push("os://scripts/jszip.min.js");
|
libs.push("os://scripts/jszip.min.js");
|
||||||
libs.push(`${this.basedir()}/libs/typescript.min.js`)
|
libs.push(`${this.basedir()}/libs/typescript.min.js`)
|
||||||
}
|
}
|
||||||
@ -347,14 +353,13 @@ namespace OS {
|
|||||||
*/
|
*/
|
||||||
private compile_coffee(list: string[]): Promise<string> {
|
private compile_coffee(list: string[]): Promise<string> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
if(list.length == 0)
|
if (list.length == 0) {
|
||||||
{
|
|
||||||
return resolve("");
|
return resolve("");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.verify_coffee(list.map((x: string) => x));
|
await this.verify_coffee(list.map((x: string) => x));
|
||||||
try {
|
try {
|
||||||
const code = await this.cat(list, "");
|
const code = await API.VFS.cat(list, "");
|
||||||
const jsrc = CoffeeScript.compile(code);
|
const jsrc = CoffeeScript.compile(code);
|
||||||
this.logger().info(__("Compiled successful"));
|
this.logger().info(__("Compiled successful"));
|
||||||
return resolve(jsrc);
|
return resolve(jsrc);
|
||||||
@ -384,12 +389,12 @@ namespace OS {
|
|||||||
];
|
];
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
await this.mkdirAll(dirs);
|
await API.VFS.mkdirAll(dirs);
|
||||||
try {
|
try {
|
||||||
const src = await this.compile(meta);
|
const src = await this.compile(meta);
|
||||||
let v: string;
|
let v: string;
|
||||||
try {
|
try {
|
||||||
let jsrc = await this.cat(
|
let jsrc = await API.VFS.cat(
|
||||||
(() => {
|
(() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
for (v of meta.javascripts) {
|
for (v of meta.javascripts) {
|
||||||
@ -438,7 +443,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
await new Promise<void>(async (r, e) => {
|
await new Promise<void>(async (r, e) => {
|
||||||
const txt = await this.cat(
|
const txt = await API.VFS.cat(
|
||||||
(() => {
|
(() => {
|
||||||
const result1 = [];
|
const result1 = [];
|
||||||
for (v of meta.css) {
|
for (v of meta.css) {
|
||||||
@ -461,7 +466,7 @@ namespace OS {
|
|||||||
return e(__e(ex_1));
|
return e(__e(ex_1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await this.copy(
|
await API.VFS.copy(
|
||||||
(() => {
|
(() => {
|
||||||
const result1_1 = [];
|
const result1_1 = [];
|
||||||
for (v of meta.copies) {
|
for (v of meta.copies) {
|
||||||
|
@ -1,32 +1,61 @@
|
|||||||
namespace OS {
|
namespace OS {
|
||||||
export namespace application {
|
export namespace application {
|
||||||
|
|
||||||
export abstract class CodePadBaseEditorModel {
|
/**
|
||||||
|
* Extends the [[RemoteFileHandle]] interface with some useful
|
||||||
|
* properties used by the Editor API
|
||||||
|
*/
|
||||||
|
export type EditorFileHandle = API.VFS.RemoteFileHandle & {
|
||||||
|
/**
|
||||||
|
* The text will be displayed on the tab bar when opened
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
text: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor text model attached to the file
|
||||||
|
* modification history of the file
|
||||||
|
*
|
||||||
|
* @type {any}
|
||||||
|
*/
|
||||||
|
textModel: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether the file is selected
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
selected: boolean;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export abstract class BaseEditorModel {
|
||||||
/**
|
/**
|
||||||
* Reference to the current editing file handle
|
* Reference to the current editing file handle
|
||||||
*
|
*
|
||||||
* @protected
|
* @protected
|
||||||
* @type {CodePadFileHandle}
|
* @type {EditorFileHandle}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
protected currfile: CodePadFileHandle;
|
protected currfile: EditorFileHandle;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Referent to the parent app
|
* Referent to the parent app
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {CodePad}
|
* @type {BaseApplication}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private app: CodePad;
|
private app: BaseApplication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to the editor tab bar UI
|
* Reference to the editor tab bar UI
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {GUI.tag.TabBarTag}
|
* @type {GUI.tag.TabBarTag}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private tabbar: GUI.tag.TabBarTag;
|
private tabbar: GUI.tag.TabBarTag;
|
||||||
|
|
||||||
@ -36,7 +65,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {HTMLElement}
|
* @type {HTMLElement}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
|
|
||||||
@ -47,22 +76,22 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private editormux: boolean;
|
private editormux: boolean;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of CodePadBaseEditorModel.
|
* Creates an instance of BaseEditorModel.
|
||||||
*
|
*
|
||||||
* @param {CodePad} app parent app
|
* @param {Antedit} app parent app
|
||||||
* @param {GUI.tag.TabBarTag} tabbar tabbar DOM element
|
* @param {GUI.tag.TabBarTag} tabbar tabbar DOM element
|
||||||
* @param {HTMLElement} editorarea editor container DOM element
|
* @param {HTMLElement} editorarea editor container DOM element
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
constructor(app: CodePad, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
constructor(app: BaseApplication, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
||||||
this.container = editorarea;
|
this.container = editorarea;
|
||||||
this.currfile = "Untitled".asFileHandle() as CodePadFileHandle;
|
this.currfile = "Untitled".asFileHandle() as EditorFileHandle;
|
||||||
this.tabbar = tabbar;
|
this.tabbar = tabbar;
|
||||||
this.editorSetup(editorarea);
|
this.editorSetup(editorarea);
|
||||||
this.app = app;
|
this.app = app;
|
||||||
@ -118,11 +147,11 @@ namespace OS {
|
|||||||
* Find a tab on the tabbar corresponding to a file handle
|
* Find a tab on the tabbar corresponding to a file handle
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {CodePadFileHandle} file then file handle to search
|
* @param {EditorFileHandle} file then file handle to search
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private findTabByFile(file: CodePadFileHandle): number {
|
private findTabByFile(file: EditorFileHandle): number {
|
||||||
const lst = this.tabbar.items;
|
const lst = this.tabbar.items;
|
||||||
const its = (() => {
|
const its = (() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
@ -144,15 +173,15 @@ namespace OS {
|
|||||||
* Create new tab when opening a file
|
* Create new tab when opening a file
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {CodePadFileHandle} file
|
* @param {EditorFileHandle} file
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private newTab(file: CodePadFileHandle): void {
|
private newTab(file: EditorFileHandle): void {
|
||||||
file.text = file.basename ? file.basename : file.path;
|
file.text = file.basename ? file.basename : file.path;
|
||||||
if (!file.cache) {
|
if (!file.cache) {
|
||||||
file.cache = "";
|
file.cache = "";
|
||||||
}
|
}
|
||||||
file.um = this.newUndoManager();
|
file.textModel = this.newTextModelFrom(file);
|
||||||
this.currfile.selected = false;
|
this.currfile.selected = false;
|
||||||
file.selected = true;
|
file.selected = true;
|
||||||
//console.log cnt
|
//console.log cnt
|
||||||
@ -165,7 +194,7 @@ namespace OS {
|
|||||||
* @private
|
* @private
|
||||||
* @param {GUI.tag.ListViewItemTag} it reference to the tab to close
|
* @param {GUI.tag.ListViewItemTag} it reference to the tab to close
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private closeTab(it: GUI.tag.ListViewItemTag): boolean {
|
private closeTab(it: GUI.tag.ListViewItemTag): boolean {
|
||||||
this.tabbar.delete(it);
|
this.tabbar.delete(it);
|
||||||
@ -173,7 +202,7 @@ namespace OS {
|
|||||||
|
|
||||||
if (cnt === 0) {
|
if (cnt === 0) {
|
||||||
this.openFile(
|
this.openFile(
|
||||||
"Untitled".asFileHandle() as CodePadFileHandle
|
"Untitled".asFileHandle() as EditorFileHandle
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -187,41 +216,23 @@ namespace OS {
|
|||||||
* @private
|
* @private
|
||||||
* @param {number} i tab index
|
* @param {number} i tab index
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private selecteTab(i: number): void {
|
private selecteTab(i: number): void {
|
||||||
//return if i is @tabbar.get "selidx"
|
//return if i is @tabbar.get "selidx"
|
||||||
const file = this.tabbar.items[i] as CodePadFileHandle;
|
const file = this.tabbar.items[i] as EditorFileHandle;
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//return if file is @currfile
|
//return if file is @currfile
|
||||||
if (this.currfile !== file) {
|
if (this.currfile !== file) {
|
||||||
this.currfile.cache = this.getValue();
|
this.currfile.textModel = this.getTexModel();
|
||||||
this.currfile.cursor = this.getCursor();
|
|
||||||
this.currfile.selected = false;
|
this.currfile.selected = false;
|
||||||
this.currfile = file;
|
this.currfile = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file.langmode) {
|
|
||||||
if (file.path.toString() !== "Untitled") {
|
|
||||||
file.langmode = this.getModeForPath(file.path);
|
|
||||||
} else {
|
|
||||||
file.langmode = {
|
|
||||||
text: "Text",
|
|
||||||
mode: "ace/mode/text",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.editormux = true;
|
this.editormux = true;
|
||||||
this.setUndoManager(this.newUndoManager());
|
this.setTextModel(file.textModel);
|
||||||
this.setValue(file.cache);
|
|
||||||
this.setMode(file.langmode);
|
|
||||||
|
|
||||||
if (file.cursor) {
|
|
||||||
this.setCursor(file.cursor);
|
|
||||||
}
|
|
||||||
this.setUndoManager(file.um);
|
|
||||||
if (this.onstatuschange)
|
if (this.onstatuschange)
|
||||||
this.onstatuschange(this.getEditorStatus());
|
this.onstatuschange(this.getEditorStatus());
|
||||||
this.focus();
|
this.focus();
|
||||||
@ -231,12 +242,12 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Select an opened file, this will select the corresponding tab
|
* Select an opened file, this will select the corresponding tab
|
||||||
*
|
*
|
||||||
* @param {(CodePadFileHandle | string)} file
|
* @param {(EditorFileHandle | string)} file
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
selectFile(file: CodePadFileHandle | string): void {
|
selectFile(file: EditorFileHandle | string): void {
|
||||||
const i = this.findTabByFile(
|
const i = this.findTabByFile(
|
||||||
file.asFileHandle() as CodePadFileHandle
|
file.asFileHandle() as EditorFileHandle
|
||||||
);
|
);
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
this.tabbar.selected = i;
|
this.tabbar.selected = i;
|
||||||
@ -247,11 +258,11 @@ namespace OS {
|
|||||||
* the just select the tab
|
* the just select the tab
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param {CodePadFileHandle} file file to open
|
* @param {EditorFileHandle} file file to open
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
openFile(file: CodePadFileHandle): void {
|
openFile(file: EditorFileHandle): void {
|
||||||
//find tab
|
//find tab
|
||||||
const i = this.findTabByFile(file);
|
const i = this.findTabByFile(file);
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
@ -280,10 +291,10 @@ namespace OS {
|
|||||||
* write a file
|
* write a file
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {CodePadFileHandle} file
|
* @param {EditorFileHandle} file
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
private write(file: CodePadFileHandle): void {
|
private write(file: EditorFileHandle): void {
|
||||||
this.currfile.cache = this.getValue();
|
this.currfile.cache = this.getValue();
|
||||||
file.write("text/plain")
|
file.write("text/plain")
|
||||||
.then((d) => {
|
.then((d) => {
|
||||||
@ -301,7 +312,7 @@ namespace OS {
|
|||||||
* Save the current opened file
|
* Save the current opened file
|
||||||
*
|
*
|
||||||
* @return {*} {void}
|
* @return {*} {void}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
save(): void {
|
save(): void {
|
||||||
this.currfile.cache = this.getValue();
|
this.currfile.cache = this.getValue();
|
||||||
@ -315,7 +326,7 @@ namespace OS {
|
|||||||
* Save the current file as another file
|
* Save the current file as another file
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
* @memberof CodePad
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
saveAs(): void {
|
saveAs(): void {
|
||||||
this.app.openDialog("FileDialog", {
|
this.app.openDialog("FileDialog", {
|
||||||
@ -334,10 +345,10 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Get all dirty file handles in the editor
|
* Get all dirty file handles in the editor
|
||||||
*
|
*
|
||||||
* @return {*} {CodePadFileHandle[]}
|
* @return {*} {EditorFileHandle[]}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
dirties(): CodePadFileHandle[] {
|
dirties(): EditorFileHandle[] {
|
||||||
const result = [];
|
const result = [];
|
||||||
for (let v of Array.from(this.tabbar.items)) {
|
for (let v of Array.from(this.tabbar.items)) {
|
||||||
if (v.dirty) {
|
if (v.dirty) {
|
||||||
@ -350,7 +361,7 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Context menu handle for the editor
|
* Context menu handle for the editor
|
||||||
*
|
*
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
set contextmenuHandle(cb: (e: any, m: any) => void) {
|
set contextmenuHandle(cb: (e: any, m: any) => void) {
|
||||||
this.container.contextmenuHandle = cb;
|
this.container.contextmenuHandle = cb;
|
||||||
@ -360,19 +371,18 @@ namespace OS {
|
|||||||
/**
|
/**
|
||||||
* Close all opened files
|
* Close all opened files
|
||||||
*
|
*
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
closeAll(): void {
|
closeAll(): void {
|
||||||
this.tabbar.items = [];
|
this.tabbar.items = [];
|
||||||
this.setValue("");
|
this.resetEditor();
|
||||||
this.setUndoManager(this.newUndoManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the editor is dirty
|
* Check whether the editor is dirty
|
||||||
*
|
*
|
||||||
* @return {*} {boolean}
|
* @return {*} {boolean}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
isDirty(): boolean {
|
isDirty(): boolean {
|
||||||
return this.dirties().length > 0;
|
return this.dirties().length > 0;
|
||||||
@ -386,7 +396,7 @@ namespace OS {
|
|||||||
* @protected
|
* @protected
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {HTMLElement} el
|
* @param {HTMLElement} el
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
protected abstract editorSetup(el: HTMLElement): void;
|
protected abstract editorSetup(el: HTMLElement): void;
|
||||||
|
|
||||||
@ -399,7 +409,7 @@ namespace OS {
|
|||||||
* @abstract
|
* @abstract
|
||||||
* @param {string} evt_str
|
* @param {string} evt_str
|
||||||
* @param {() => void} callback
|
* @param {() => void} callback
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract on(evt_str: string, callback: () => void): void;
|
abstract on(evt_str: string, callback: () => void): void;
|
||||||
|
|
||||||
@ -410,7 +420,7 @@ namespace OS {
|
|||||||
* Should be implemented by subclasses
|
* Should be implemented by subclasses
|
||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract resize(): void;
|
abstract resize(): void;
|
||||||
|
|
||||||
@ -421,7 +431,7 @@ namespace OS {
|
|||||||
* Should be implemented by subclasses
|
* Should be implemented by subclasses
|
||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract focus(): void;
|
abstract focus(): void;
|
||||||
|
|
||||||
@ -435,7 +445,7 @@ namespace OS {
|
|||||||
* @abstract
|
* @abstract
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @return {*} {GenericObject<any>}
|
* @return {*} {GenericObject<any>}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
protected abstract getModeForPath(path: string): GenericObject<any>;
|
protected abstract getModeForPath(path: string): GenericObject<any>;
|
||||||
|
|
||||||
@ -447,7 +457,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @return {*} {GenericObject<any>}
|
* @return {*} {GenericObject<any>}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract getEditorStatus(): GenericObject<any>;
|
abstract getEditorStatus(): GenericObject<any>;
|
||||||
|
|
||||||
@ -459,7 +469,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @return {*} {string}
|
* @return {*} {string}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract getValue(): string;
|
abstract getValue(): string;
|
||||||
|
|
||||||
@ -471,51 +481,10 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {string} value
|
* @param {string} value
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract setValue(value: string): void;
|
abstract setValue(value: string): void;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current editor position
|
|
||||||
*
|
|
||||||
* Should be implemented by subclasses
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @abstract
|
|
||||||
* @return {*} {GenericObject<any>}
|
|
||||||
* @memberof CodePadBaseEditorModel
|
|
||||||
*/
|
|
||||||
protected abstract getCursor(): GenericObject<any>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance of UndoManager
|
|
||||||
*
|
|
||||||
* This is specific to each editor, so
|
|
||||||
* it should be implemented by subclasses
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @abstract
|
|
||||||
* @return {*} {GenericObject<any>}
|
|
||||||
* @memberof CodePadBaseEditorModel
|
|
||||||
*/
|
|
||||||
protected abstract newUndoManager(): GenericObject<any>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the editor UndoManager
|
|
||||||
*
|
|
||||||
* Should be implemented by subclasses
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @abstract
|
|
||||||
* @param {GenericObject<any>} um
|
|
||||||
* @memberof CodePadBaseEditorModel
|
|
||||||
*/
|
|
||||||
protected abstract setUndoManager(um: GenericObject<any>): void;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the editor language mode
|
* Set the editor language mode
|
||||||
*
|
*
|
||||||
@ -523,24 +492,54 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {GenericObject<any>} m
|
* @param {GenericObject<any>} m
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract setMode(m: GenericObject<any>): void;
|
abstract setMode(m: GenericObject<any>): void;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set current editor cursor position
|
* Get textModel from the current editor session
|
||||||
*
|
|
||||||
* Should be implemented by subclasses
|
|
||||||
*
|
*
|
||||||
* @protected
|
* @protected
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {GenericObject<any>} c
|
* @return {*} {*}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
protected abstract setCursor(c: GenericObject<any>): void;
|
protected abstract getTexModel(): any;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set text model to the current editor session
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @abstract
|
||||||
|
* @param {*} model
|
||||||
|
* @memberof BaseEditorModel
|
||||||
|
*/
|
||||||
|
protected abstract setTextModel(model: any): void;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new text model from the VFS file
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @abstract
|
||||||
|
* @param {EditorFileHandle} file
|
||||||
|
* @return {*} {*}
|
||||||
|
* @memberof BaseEditorModel
|
||||||
|
*/
|
||||||
|
protected abstract newTextModelFrom(file: EditorFileHandle): any;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the editor
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @abstract
|
||||||
|
* @memberof BaseEditorModel
|
||||||
|
*/
|
||||||
|
protected abstract resetEditor(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current editor theme
|
* Set the current editor theme
|
||||||
*
|
*
|
||||||
@ -548,7 +547,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {string} theme
|
* @param {string} theme
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract setTheme(theme: string): void;
|
abstract setTheme(theme: string): void;
|
||||||
|
|
||||||
@ -558,7 +557,7 @@ namespace OS {
|
|||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
* @return {*} {GenericObject<any>[]}
|
* @return {*} {GenericObject<any>[]}
|
||||||
* @memberof CodePadBaseEditorModel
|
* @memberof BaseEditorModel
|
||||||
*/
|
*/
|
||||||
abstract getModes(): GenericObject<any>[];
|
abstract getModes(): GenericObject<any>[];
|
||||||
}
|
}
|
||||||
|
@ -38,39 +38,6 @@ namespace OS {
|
|||||||
return API.require(libs);
|
return API.require(libs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get content of a file compressed in a zip archive
|
|
||||||
*
|
|
||||||
* @param {*} file
|
|
||||||
* @memberof BaseExtension
|
|
||||||
*/
|
|
||||||
loadzip(file: string, type:string): Promise<any>
|
|
||||||
{
|
|
||||||
return new Promise(async (resolve, reject) =>{
|
|
||||||
try {
|
|
||||||
const data = await file.asFileHandle().read("binary");
|
|
||||||
try {
|
|
||||||
const zip = await JSZip.loadAsync(data);
|
|
||||||
let file_name = "";
|
|
||||||
for (let name in zip.files) {
|
|
||||||
file_name = name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const udata = await zip.file(file_name).async(type);
|
|
||||||
resolve(udata);
|
|
||||||
} catch (e_2) {
|
|
||||||
return reject(__e(e_2));
|
|
||||||
}
|
|
||||||
} catch (e_1) {
|
|
||||||
return reject(__e(e_1));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return reject(__e(e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@ -136,352 +103,6 @@ namespace OS {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Cat all files to a single output string
|
|
||||||
*
|
|
||||||
* @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)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read all file content in the list
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @param {string[]} list
|
|
||||||
* @return {*} {Promise<GenericObject<string>>}
|
|
||||||
* @memberof BaseExtension
|
|
||||||
*/
|
|
||||||
protected read_files(list:string[], contents: GenericObject<string>[]): Promise<GenericObject<string>[]>
|
|
||||||
{
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (list.length === 0) {
|
|
||||||
return resolve(contents);
|
|
||||||
}
|
|
||||||
const file = list.splice(0, 1)[0].asFileHandle();
|
|
||||||
return file
|
|
||||||
.read()
|
|
||||||
.then((text: string) => {
|
|
||||||
contents.push({
|
|
||||||
path: file.path,
|
|
||||||
content: text
|
|
||||||
});
|
|
||||||
return this.read_files(list, contents)
|
|
||||||
.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<void> {
|
|
||||||
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: ArrayBuffer) => {
|
|
||||||
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(async (d: any) => {
|
|
||||||
const zpath = `${base}${file.basename}`.replace(
|
|
||||||
/^\/+|\/+$/g,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
zip.file(zpath, d, { binary: true });
|
|
||||||
try {
|
|
||||||
await this.aradd(list, zip, base);
|
|
||||||
return resolve(zip);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return 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<void> {
|
|
||||||
this.logger().info(__("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.logger().info(
|
|
||||||
__(
|
|
||||||
"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<void> {
|
|
||||||
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.observable.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<void> {
|
|
||||||
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)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -68,7 +68,7 @@ namespace OS {
|
|||||||
try {
|
try {
|
||||||
await this.build(meta);
|
await this.build(meta);
|
||||||
try {
|
try {
|
||||||
return this.mkar(
|
return API.VFS.mkar(
|
||||||
`${meta.root}/build/debug`,
|
`${meta.root}/build/debug`,
|
||||||
`${meta.root}/build/release/${meta.meta.name}.zip`
|
`${meta.root}/build/release/${meta.meta.name}.zip`
|
||||||
);
|
);
|
||||||
@ -157,14 +157,16 @@ namespace OS {
|
|||||||
["templates/ext-main.tpl", `${rpath}/${name}.coffee`],
|
["templates/ext-main.tpl", `${rpath}/${name}.coffee`],
|
||||||
["templates/ext-extension.tpl", `${rpath}/extension.json`],
|
["templates/ext-extension.tpl", `${rpath}/extension.json`],
|
||||||
];
|
];
|
||||||
this.mkdirAll(dirs)
|
API.VFS.mkdirAll(dirs)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
try {
|
try {
|
||||||
await this.mkfileAll(files, path, name);
|
await API.VFS.mktpl(files, this.basedir(), (data)=>{
|
||||||
|
return data.format(name, `${path}/${name}`);
|
||||||
|
});
|
||||||
this.app.currdir = rpath.asFileHandle();
|
this.app.currdir = rpath.asFileHandle();
|
||||||
this.app.toggleSideBar();
|
this.app.toggleSideBar();
|
||||||
return this.app.eum.active.openFile(
|
return this.app.eum.active.openFile(
|
||||||
`${rpath}/${name}.coffee`.asFileHandle() as application.CodePadFileHandle
|
`${rpath}/${name}.coffee`.asFileHandle() as application.EditorFileHandle
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return this.logger().error(
|
return this.logger().error(
|
||||||
@ -227,7 +229,7 @@ namespace OS {
|
|||||||
try {
|
try {
|
||||||
await this.verify(list.map((x: string) => x));
|
await this.verify(list.map((x: string) => x));
|
||||||
try {
|
try {
|
||||||
const code = await this.cat(list, "");
|
const code = await API.VFS.cat(list, "");
|
||||||
const jsrc = CoffeeScript.compile(code);
|
const jsrc = CoffeeScript.compile(code);
|
||||||
this.logger().info(__("Compiled successful"));
|
this.logger().info(__("Compiled successful"));
|
||||||
return resolve(jsrc);
|
return resolve(jsrc);
|
||||||
@ -257,7 +259,7 @@ namespace OS {
|
|||||||
const src = await this.compile(meta);
|
const src = await this.compile(meta);
|
||||||
let v: string;
|
let v: string;
|
||||||
try {
|
try {
|
||||||
const jsrc = await this.cat(
|
const jsrc = await API.VFS.cat(
|
||||||
(() => {
|
(() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
for (v of meta.javascripts) {
|
for (v of meta.javascripts) {
|
||||||
@ -283,7 +285,7 @@ namespace OS {
|
|||||||
.then((data) => r(data))
|
.then((data) => r(data))
|
||||||
.catch((ex_1) => e(__e(ex_1)))
|
.catch((ex_1) => e(__e(ex_1)))
|
||||||
);
|
);
|
||||||
await this.copy(
|
await API.VFS.copy(
|
||||||
(() => {
|
(() => {
|
||||||
const result1 = [];
|
const result1 = [];
|
||||||
for (v of meta.copies) {
|
for (v of meta.copies) {
|
||||||
@ -503,7 +505,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dir.length > 0) {
|
if (dir.length > 0) {
|
||||||
this.mkdirAll(dir)
|
API.VFS.mkdirAll(dir)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.installExtension(
|
this.installExtension(
|
||||||
files,
|
files,
|
||||||
|
Binary file not shown.
@ -1,47 +1,5 @@
|
|||||||
namespace OS {
|
namespace OS {
|
||||||
export namespace application {
|
export namespace application {
|
||||||
/**
|
|
||||||
* Extends the [[RemoteFileHandle]] interface with some useful
|
|
||||||
* properties used by [[CodePad]]
|
|
||||||
*/
|
|
||||||
export type CodePadFileHandle = API.VFS.RemoteFileHandle & {
|
|
||||||
/**
|
|
||||||
* The text will be displayed on the tab bar when opened
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
text: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ACE Undo manager of the current file, stores the
|
|
||||||
* modification history of the file
|
|
||||||
*
|
|
||||||
* @type {GenericObject<any>}
|
|
||||||
*/
|
|
||||||
um: GenericObject<any>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate whether the file is selected
|
|
||||||
*
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
selected: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the latest cursor position on the editor
|
|
||||||
* when editing the file
|
|
||||||
*
|
|
||||||
* @type {GenericObject<any>}
|
|
||||||
*/
|
|
||||||
cursor: GenericObject<any>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Language mode setting of the file
|
|
||||||
*
|
|
||||||
* @type {GenericObject<string>}
|
|
||||||
*/
|
|
||||||
langmode: GenericObject<string>;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* [[CodePad]]'s [[CommandPalette]] action type definition
|
* [[CodePad]]'s [[CommandPalette]] action type definition
|
||||||
*/
|
*/
|
||||||
@ -252,14 +210,14 @@ namespace OS {
|
|||||||
|
|
||||||
// add editor instance
|
// add editor instance
|
||||||
this.eum
|
this.eum
|
||||||
.add(new CodePadACEModel(
|
.add(new ACEModel(
|
||||||
this,
|
this,
|
||||||
this.find("left-tabbar") as GUI.tag.TabBarTag,
|
this.find("left-tabbar") as GUI.tag.TabBarTag,
|
||||||
this.find("left-editorarea")) as CodePadBaseEditorModel)
|
this.find("left-editorarea")) as BaseEditorModel)
|
||||||
.add(new CodePadACEModel(
|
.add(new ACEModel(
|
||||||
this,
|
this,
|
||||||
this.find("right-tabbar") as GUI.tag.TabBarTag,
|
this.find("right-tabbar") as GUI.tag.TabBarTag,
|
||||||
this.find("right-editorarea")) as CodePadBaseEditorModel);
|
this.find("right-editorarea")) as BaseEditorModel);
|
||||||
|
|
||||||
this.eum.onstatuschange = (st) =>
|
this.eum.onstatuschange = (st) =>
|
||||||
this.updateStatus(st)
|
this.updateStatus(st)
|
||||||
@ -283,13 +241,13 @@ namespace OS {
|
|||||||
return reject(__e(e));
|
return reject(__e(e));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let file = "Untitled".asFileHandle() as CodePadFileHandle;
|
let file = "Untitled".asFileHandle() as EditorFileHandle;
|
||||||
if (this.args && this.args.length > 0) {
|
if (this.args && this.args.length > 0) {
|
||||||
this.addRecent(this.args[0].path);
|
this.addRecent(this.args[0].path);
|
||||||
if (this.args[0].type === "dir") {
|
if (this.args[0].type === "dir") {
|
||||||
this.currdir = this.args[0].path.asFileHandle() as CodePadFileHandle;
|
this.currdir = this.args[0].path.asFileHandle() as EditorFileHandle;
|
||||||
} else {
|
} else {
|
||||||
file = this.args[0].path.asFileHandle() as CodePadFileHandle;
|
file = this.args[0].path.asFileHandle() as EditorFileHandle;
|
||||||
this.currdir = file.parent();
|
this.currdir = file.parent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +274,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
this.addRecent(e.data.path);
|
this.addRecent(e.data.path);
|
||||||
return this.eum.active.openFile(
|
return this.eum.active.openFile(
|
||||||
e.data.path.asFileHandle() as CodePadFileHandle
|
e.data.path.asFileHandle() as EditorFileHandle
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -519,7 +477,7 @@ namespace OS {
|
|||||||
else {
|
else {
|
||||||
$(right_pannel).show();
|
$(right_pannel).show();
|
||||||
this.split_mode = true;
|
this.split_mode = true;
|
||||||
right_editor.openFile("Untitled".asFileHandle() as CodePadFileHandle);
|
right_editor.openFile("Untitled".asFileHandle() as EditorFileHandle);
|
||||||
right_editor.focus();
|
right_editor.focus();
|
||||||
}
|
}
|
||||||
this.trigger("resize");
|
this.trigger("resize");
|
||||||
@ -977,7 +935,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
switch (dataid) {
|
switch (dataid) {
|
||||||
case "new":
|
case "new":
|
||||||
return me.eum.active.openFile("Untitled".asFileHandle() as CodePadFileHandle);
|
return me.eum.active.openFile("Untitled".asFileHandle() as EditorFileHandle);
|
||||||
case "open":
|
case "open":
|
||||||
return me
|
return me
|
||||||
.openDialog("FileDialog", {
|
.openDialog("FileDialog", {
|
||||||
@ -1081,7 +1039,7 @@ namespace OS {
|
|||||||
],
|
],
|
||||||
onchildselect: (
|
onchildselect: (
|
||||||
e: GUI.TagEventType<GUI.tag.MenuEventData>,
|
e: GUI.TagEventType<GUI.tag.MenuEventData>,
|
||||||
r: CodePadFileHandle
|
r: EditorFileHandle
|
||||||
) => {
|
) => {
|
||||||
switch (e.data.item.data.dataid) {
|
switch (e.data.item.data.dataid) {
|
||||||
case "cmdpalette":
|
case "cmdpalette":
|
||||||
@ -1225,19 +1183,19 @@ namespace OS {
|
|||||||
* Referent to the active editor model
|
* Referent to the active editor model
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {CodePadBaseEditorModel}
|
* @type {BaseEditorModel}
|
||||||
* @memberof EditorModelManager
|
* @memberof EditorModelManager
|
||||||
*/
|
*/
|
||||||
private active_editor: CodePadBaseEditorModel;
|
private active_editor: BaseEditorModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a list of editor models
|
* Store a list of editor models
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @type {CodePadBaseEditorModel[]}
|
* @type {BaseEditorModel[]}
|
||||||
* @memberof EditorModelManager
|
* @memberof EditorModelManager
|
||||||
*/
|
*/
|
||||||
private models: CodePadBaseEditorModel[];
|
private models: BaseEditorModel[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of EditorModelManager.
|
* Creates an instance of EditorModelManager.
|
||||||
@ -1248,7 +1206,7 @@ namespace OS {
|
|||||||
this.models = [];
|
this.models = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get editors(): CodePadBaseEditorModel[] {
|
get editors(): BaseEditorModel[] {
|
||||||
return this.models;
|
return this.models;
|
||||||
}
|
}
|
||||||
set contextmenuHandle(cb: (e: any, m: any) => void) {
|
set contextmenuHandle(cb: (e: any, m: any) => void) {
|
||||||
@ -1261,20 +1219,20 @@ namespace OS {
|
|||||||
* Get the active editor model
|
* Get the active editor model
|
||||||
*
|
*
|
||||||
* @readonly
|
* @readonly
|
||||||
* @type {CodePadBaseEditorModel}
|
* @type {BaseEditorModel}
|
||||||
* @memberof EditorModelManager
|
* @memberof EditorModelManager
|
||||||
*/
|
*/
|
||||||
get active(): CodePadBaseEditorModel {
|
get active(): BaseEditorModel {
|
||||||
return this.active_editor;
|
return this.active_editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a model to the manager
|
* Add a model to the manager
|
||||||
*
|
*
|
||||||
* @param {CodePadBaseEditorModel} model
|
* @param {BaseEditorModel} model
|
||||||
* @memberof EditorModelManager
|
* @memberof EditorModelManager
|
||||||
*/
|
*/
|
||||||
add(model: CodePadBaseEditorModel): EditorModelManager {
|
add(model: BaseEditorModel): EditorModelManager {
|
||||||
this.models.push(model);
|
this.models.push(model);
|
||||||
if (!this.active_editor)
|
if (!this.active_editor)
|
||||||
this.active_editor = model;
|
this.active_editor = model;
|
||||||
@ -1290,7 +1248,7 @@ namespace OS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dirties(): CodePadFileHandle[] {
|
dirties(): EditorFileHandle[] {
|
||||||
let list = [];
|
let list = [];
|
||||||
for (let ed of this.models) {
|
for (let ed of this.models) {
|
||||||
list = list.concat(ed.dirties());
|
list = list.concat(ed.dirties());
|
||||||
|
Loading…
Reference in New Issue
Block a user