diff --git a/release/antos-1.2.0.tar.gz b/release/antos-1.2.0.tar.gz index 5746d34..cd51d0a 100644 Binary files a/release/antos-1.2.0.tar.gz and b/release/antos-1.2.0.tar.gz differ diff --git a/src/core/vfs.ts b/src/core/vfs.ts index 2aab59a..2697428 100644 --- a/src/core/vfs.ts +++ b/src/core/vfs.ts @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License //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 { /** * Convert a string to VFS file handle. @@ -164,6 +164,8 @@ namespace OS { * AntOS Virtual File System (VFS) */ export namespace VFS { + declare var JSZip: any; + String.prototype.asFileHandle = function (): BaseFileHandle { const list = this.split("://"); const handles = API.VFS.findHandles(list[0]); @@ -1298,7 +1300,7 @@ namespace OS { register("^(home|desktop|os|Untitled)$", RemoteFileHandle); - + /** * Package file is remote file ([[RemoteFileHandle]]) located either in * the local user packages location or system packages @@ -1316,8 +1318,7 @@ namespace OS { * @class PackageFileHandle * @extends {RemoteFileHandle} */ - export class PackageFileHandle extends RemoteFileHandle - { + export class PackageFileHandle extends RemoteFileHandle { /** *Creates an instance of PackageFileHandle. @@ -1325,12 +1326,11 @@ namespace OS { * @memberof PackageFileHandle */ constructor(pkg_path: string) { - var error:FormattedString|string; + var error: FormattedString | string; var pkg_name: string; super(pkg_path); // now find the correct path - if(!this.genealogy || this.genealogy.length == 0) - { + if (!this.genealogy || this.genealogy.length == 0) { error = __("Invalid package path"); announcer.oserror(error, API.throwe(error)); throw new Error(error.__()); @@ -1338,14 +1338,12 @@ namespace OS { else { // get the correct path of the package 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("/")); } - else - { + else { error = __("Package not found {0}", pkg_name); - announcer.oserror(error,API.throwe(error)); + announcer.oserror(error, API.throwe(error)); throw new Error(error.__()); } } @@ -1427,8 +1425,7 @@ namespace OS { const result = []; for (let k in OS.setting.system.packages) { const v = OS.setting.system.packages[k]; - if(v.app) - { + if (v.app) { result.push(v); } } @@ -1599,7 +1596,7 @@ namespace OS { //read the file if (t === "binary") { //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"); } @@ -1760,6 +1757,399 @@ namespace OS { } 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} + */ + export function readFileFromZip(file: string, type: string, file_name?: string): Promise { + 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} + */ + export function cat(list: string[], data: string): Promise { + 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[]} contents content array + * @return {*} {Promise[]>} + */ + export function read_files(list: string[], contents: GenericObject[]): Promise[]> { + 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} + */ + export function copy(files: string[], to: string): Promise { + 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} + */ + function aradd(list: string[], zip: any, base: string): Promise { + 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 + | ArrayLike; + }) => { + 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} + */ + export function mkar(src: string, dest: string): Promise { + 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} + */ + export function mkdirAll(list: string[]): Promise { + 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} list of templates mapping files + * @param {string} path path stored create files + * @param {string} name + * @return {*} {Promise} + */ + + /** + * Make files from a set of template files + * + * @export + * @param {Array} 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} + */ + export function mktpl( + list: Array, + path: string, + callback: (data: string) => string + ): Promise { + 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))); + }); + } } } } diff --git a/src/packages/CodePad/ACEModel.ts b/src/packages/CodePad/ACEModel.ts index 28b1d98..bf64d00 100644 --- a/src/packages/CodePad/ACEModel.ts +++ b/src/packages/CodePad/ACEModel.ts @@ -7,41 +7,121 @@ namespace OS { * Wrapper model for the ACE text editor * * @export - * @class CodePadACEModel - * @extends {CodePadBaseEditorModel} + * @class ACEModel + * @extends {BaseEditorModel} */ - export class CodePadACEModel extends CodePadBaseEditorModel { + export class ACEModel extends BaseEditorModel { + + /** + * Current editor mode + * + * @private + * @type {GenericObject} + * @memberof ACEModel + */ + private mode: GenericObject; /** * Reference to ACE language modes * * @private * @type {GenericObject} - * @memberof CodePadACEModel + * @memberof ACEModel */ private modes: GenericObject; /** - * Creates an instance of CodePadACEModel. - * @param {CodePad} app CodePad instance + * Creates an instance of ACEModel. + * @param {ACEModel} app instance * @param {GUI.tag.TabBarTag} tabbar tabbar 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.require("ace/ext/language_tools"); super(app, tabbar, editorarea); 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 * * @return {*} {GenericObject[]} - * @memberof CodePadACEModel + * @memberof ACEModel */ getModes(): GenericObject[] { const list = []; @@ -57,33 +137,20 @@ namespace OS { * Set the editor theme * * @param {string} theme theme name - * @memberof CodePadACEModel + * @memberof ACEModel */ setTheme(theme: string): void { this.editor.setTheme(theme); } - - /** - * Set the editor undo manager - * - * @protected - * @param {GenericObject} um - * @memberof CodePadACEModel - */ - protected setUndoManager(um: GenericObject): void { - this.editor.getSession().setUndoManager(um); - } - - /** * Set the editor cursor * - * @protected + * @private * @param {GenericObject} c cursor option - * @memberof CodePadACEModel + * @memberof ACEModel */ - protected setCursor(c: GenericObject): void { + private setCursor(c: GenericObject): void { this.editor.renderer.scrollCursorIntoView( { row: c.row, @@ -110,43 +177,21 @@ namespace OS { * ``` * * @param {GenericObject} m language mode object - * @memberof CodePadACEModel + * @memberof ACEModel */ setMode(m: GenericObject): void { - this.currfile.langmode = m; + this.mode = m; this.editor.getSession().setMode(m.mode); } - /** - * Get current editor cursor position - * - * @protected - * @return {*} {GenericObject} - * @memberof CodePadACEModel - */ - protected getCursor(): GenericObject { - return this.editor.getCursorPosition(); - } - - - /** - * create a new UndoManage instance - * - * @protected - * @return {*} {GenericObject} - * @memberof CodePadACEModel - */ - protected newUndoManager(): GenericObject { - return new ace.UndoManager(); - } /** * Reference to the editor instance * * @protected * @type {GenericObject} - * @memberof CodePad + * @memberof ACEModel */ protected editor: GenericObject; @@ -156,7 +201,7 @@ namespace OS { * * @protected * @param {HTMLElement} el editor container DOM - * @memberof CodePadACEModel + * @memberof ACEModel */ protected editorSetup(el: HTMLElement): void { this.editor = ace.edit(el); @@ -191,7 +236,7 @@ namespace OS { * * @param {string} evt_str event name * @param {() => void} callback callback function - * @memberof CodePadACEModel + * @memberof ACEModel */ on(evt_str: string, callback: () => void): void { switch (evt_str) { @@ -213,7 +258,7 @@ namespace OS { /** * Resize the editor * - * @memberof CodePadACEModel + * @memberof ACEModel */ resize(): void { this.editor.resize(); @@ -223,7 +268,7 @@ namespace OS { /** * Focus on the editor * - * @memberof CodePadACEModel + * @memberof ACEModel */ focus(): void { this.editor.focus(); @@ -236,9 +281,9 @@ namespace OS { * @protected * @param {string} path * @return {*} {GenericObject} - * @memberof CodePadACEModel + * @memberof ACEModel */ - protected getModeForPath(path: string): GenericObject { + protected getModeForPath(path: string): GenericObject { const m = this.modes.getModeForPath(path); return { text: m.caption, @@ -250,7 +295,7 @@ namespace OS { * Get the editor status * * @return {*} {GenericObject} - * @memberof CodePadACEModel + * @memberof ACEModel */ getEditorStatus(): GenericObject { const c = this.editor.session.selection.getCursor(); @@ -259,7 +304,7 @@ namespace OS { row: c.row, column: c.column, line: l, - langmode: this.currfile.langmode, + langmode: this.mode, file: this.currfile.path } } @@ -269,7 +314,7 @@ namespace OS { * Get editor value * * @return {*} {string} - * @memberof CodePadACEModel + * @memberof ACEModel */ getValue(): string { return this.editor.getValue(); @@ -280,7 +325,7 @@ namespace OS { * Set editor value * * @param {string} value - * @memberof CodePadACEModel + * @memberof ACEModel */ setValue(value: string): void { this.editor.setValue(value, -1); diff --git a/src/packages/CodePad/AntOSDK.ts b/src/packages/CodePad/AntOSDK.ts index ef59cd3..321e5f6 100644 --- a/src/packages/CodePad/AntOSDK.ts +++ b/src/packages/CodePad/AntOSDK.ts @@ -113,7 +113,7 @@ namespace OS { try { await this.build(meta, false); try { - return this.mkar( + return API.VFS.mkar( `${meta.root}/build/debug`, `${meta.root}/build/release/${meta.name}.zip` ); @@ -160,14 +160,16 @@ namespace OS { ["templates/sdk-README.tpl", `${rpath}/README.md`], ["templates/sdk-scheme.tpl", `${rpath}/assets/scheme.html`], ]; - this.mkdirAll(dirs) + API.VFS.mkdirAll(dirs) .then(async () => { 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.toggleSideBar(); return this.app.eum.active.openFile( - `${rpath}/README.md`.asFileHandle() as application.CodePadFileHandle + `${rpath}/README.md`.asFileHandle() as application.EditorFileHandle ); } catch (e) { return this.logger().error( @@ -226,7 +228,7 @@ namespace OS { return resolve(AntOSDK.corelib["ts"]); } 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); return resolve(AntOSDK.corelib["ts"]); } catch (e) { @@ -252,7 +254,7 @@ namespace OS { try { await this.load_corelib(core_lib); 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) libs.unshift(core_lib); const src_files: GenericObject = {}; @@ -310,10 +312,14 @@ namespace OS { const libs = [ `${this.basedir()}/libs/terser.min.js`, ]; + if (!meta.coffees) + meta.coffees = []; if (meta.coffees.length > 0) { 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(`${this.basedir()}/libs/typescript.min.js`) } @@ -347,14 +353,13 @@ namespace OS { */ private compile_coffee(list: string[]): Promise { return new Promise(async (resolve, reject) => { - if(list.length == 0) - { + if (list.length == 0) { return resolve(""); } try { await this.verify_coffee(list.map((x: string) => x)); try { - const code = await this.cat(list, ""); + const code = await API.VFS.cat(list, ""); const jsrc = CoffeeScript.compile(code); this.logger().info(__("Compiled successful")); return resolve(jsrc); @@ -384,12 +389,12 @@ namespace OS { ]; return new Promise(async (resolve, reject) => { try { - await this.mkdirAll(dirs); + await API.VFS.mkdirAll(dirs); try { const src = await this.compile(meta); let v: string; try { - let jsrc = await this.cat( + let jsrc = await API.VFS.cat( (() => { const result = []; for (v of meta.javascripts) { @@ -438,7 +443,7 @@ namespace OS { } }); await new Promise(async (r, e) => { - const txt = await this.cat( + const txt = await API.VFS.cat( (() => { const result1 = []; for (v of meta.css) { @@ -461,7 +466,7 @@ namespace OS { return e(__e(ex_1)); } }); - await this.copy( + await API.VFS.copy( (() => { const result1_1 = []; for (v of meta.copies) { diff --git a/src/packages/CodePad/BaseEditorModel.ts b/src/packages/CodePad/BaseEditorModel.ts index 06281ec..1463608 100644 --- a/src/packages/CodePad/BaseEditorModel.ts +++ b/src/packages/CodePad/BaseEditorModel.ts @@ -1,32 +1,61 @@ namespace OS { 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 * * @protected - * @type {CodePadFileHandle} - * @memberof CodePad + * @type {EditorFileHandle} + * @memberof BaseEditorModel */ - protected currfile: CodePadFileHandle; + protected currfile: EditorFileHandle; /** * Referent to the parent app * * @private - * @type {CodePad} - * @memberof CodePadBaseEditorModel + * @type {BaseApplication} + * @memberof BaseEditorModel */ - private app: CodePad; + private app: BaseApplication; /** * Reference to the editor tab bar UI * * @private * @type {GUI.tag.TabBarTag} - * @memberof CodePad + * @memberof BaseEditorModel */ private tabbar: GUI.tag.TabBarTag; @@ -36,7 +65,7 @@ namespace OS { * * @private * @type {HTMLElement} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ private container: HTMLElement; @@ -47,22 +76,22 @@ namespace OS { * * @private * @type {boolean} - * @memberof CodePad + * @memberof BaseEditorModel */ 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 {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.currfile = "Untitled".asFileHandle() as CodePadFileHandle; + this.currfile = "Untitled".asFileHandle() as EditorFileHandle; this.tabbar = tabbar; this.editorSetup(editorarea); this.app = app; @@ -118,11 +147,11 @@ namespace OS { * Find a tab on the tabbar corresponding to a file handle * * @private - * @param {CodePadFileHandle} file then file handle to search + * @param {EditorFileHandle} file then file handle to search * @returns {number} - * @memberof CodePad + * @memberof BaseEditorModel */ - private findTabByFile(file: CodePadFileHandle): number { + private findTabByFile(file: EditorFileHandle): number { const lst = this.tabbar.items; const its = (() => { const result = []; @@ -144,15 +173,15 @@ namespace OS { * Create new tab when opening a file * * @private - * @param {CodePadFileHandle} file - * @memberof CodePad + * @param {EditorFileHandle} file + * @memberof BaseEditorModel */ - private newTab(file: CodePadFileHandle): void { + private newTab(file: EditorFileHandle): void { file.text = file.basename ? file.basename : file.path; if (!file.cache) { file.cache = ""; } - file.um = this.newUndoManager(); + file.textModel = this.newTextModelFrom(file); this.currfile.selected = false; file.selected = true; //console.log cnt @@ -165,7 +194,7 @@ namespace OS { * @private * @param {GUI.tag.ListViewItemTag} it reference to the tab to close * @returns {boolean} - * @memberof CodePad + * @memberof BaseEditorModel */ private closeTab(it: GUI.tag.ListViewItemTag): boolean { this.tabbar.delete(it); @@ -173,7 +202,7 @@ namespace OS { if (cnt === 0) { this.openFile( - "Untitled".asFileHandle() as CodePadFileHandle + "Untitled".asFileHandle() as EditorFileHandle ); return false; } @@ -187,41 +216,23 @@ namespace OS { * @private * @param {number} i tab index * @returns {void} - * @memberof CodePad + * @memberof BaseEditorModel */ private selecteTab(i: number): void { //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) { return; } //return if file is @currfile if (this.currfile !== file) { - this.currfile.cache = this.getValue(); - this.currfile.cursor = this.getCursor(); + this.currfile.textModel = this.getTexModel(); this.currfile.selected = false; 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.setUndoManager(this.newUndoManager()); - this.setValue(file.cache); - this.setMode(file.langmode); - - if (file.cursor) { - this.setCursor(file.cursor); - } - this.setUndoManager(file.um); + this.setTextModel(file.textModel); if (this.onstatuschange) this.onstatuschange(this.getEditorStatus()); this.focus(); @@ -231,12 +242,12 @@ namespace OS { /** * Select an opened file, this will select the corresponding tab * - * @param {(CodePadFileHandle | string)} file - * @memberof CodePadBaseEditorModel + * @param {(EditorFileHandle | string)} file + * @memberof BaseEditorModel */ - selectFile(file: CodePadFileHandle | string): void { + selectFile(file: EditorFileHandle | string): void { const i = this.findTabByFile( - file.asFileHandle() as CodePadFileHandle + file.asFileHandle() as EditorFileHandle ); if (i !== -1) { this.tabbar.selected = i; @@ -247,11 +258,11 @@ namespace OS { * the just select the tab * * - * @param {CodePadFileHandle} file file to open + * @param {EditorFileHandle} file file to open * @returns {void} - * @memberof CodePad + * @memberof BaseEditorModel */ - openFile(file: CodePadFileHandle): void { + openFile(file: EditorFileHandle): void { //find tab const i = this.findTabByFile(file); if (i !== -1) { @@ -280,10 +291,10 @@ namespace OS { * write a file * * @private - * @param {CodePadFileHandle} file - * @memberof CodePad + * @param {EditorFileHandle} file + * @memberof BaseEditorModel */ - private write(file: CodePadFileHandle): void { + private write(file: EditorFileHandle): void { this.currfile.cache = this.getValue(); file.write("text/plain") .then((d) => { @@ -301,7 +312,7 @@ namespace OS { * Save the current opened file * * @return {*} {void} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ save(): void { this.currfile.cache = this.getValue(); @@ -315,7 +326,7 @@ namespace OS { * Save the current file as another file * * @public - * @memberof CodePad + * @memberof BaseEditorModel */ saveAs(): void { this.app.openDialog("FileDialog", { @@ -334,10 +345,10 @@ namespace OS { /** * Get all dirty file handles in the editor * - * @return {*} {CodePadFileHandle[]} - * @memberof CodePadBaseEditorModel + * @return {*} {EditorFileHandle[]} + * @memberof BaseEditorModel */ - dirties(): CodePadFileHandle[] { + dirties(): EditorFileHandle[] { const result = []; for (let v of Array.from(this.tabbar.items)) { if (v.dirty) { @@ -350,7 +361,7 @@ namespace OS { /** * Context menu handle for the editor * - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ set contextmenuHandle(cb: (e: any, m: any) => void) { this.container.contextmenuHandle = cb; @@ -360,19 +371,18 @@ namespace OS { /** * Close all opened files * - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ closeAll(): void { this.tabbar.items = []; - this.setValue(""); - this.setUndoManager(this.newUndoManager()); + this.resetEditor(); } /** * Check whether the editor is dirty * * @return {*} {boolean} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ isDirty(): boolean { return this.dirties().length > 0; @@ -386,7 +396,7 @@ namespace OS { * @protected * @abstract * @param {HTMLElement} el - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ protected abstract editorSetup(el: HTMLElement): void; @@ -399,7 +409,7 @@ namespace OS { * @abstract * @param {string} evt_str * @param {() => void} callback - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract on(evt_str: string, callback: () => void): void; @@ -410,7 +420,7 @@ namespace OS { * Should be implemented by subclasses * * @abstract - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract resize(): void; @@ -421,7 +431,7 @@ namespace OS { * Should be implemented by subclasses * * @abstract - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract focus(): void; @@ -435,7 +445,7 @@ namespace OS { * @abstract * @param {string} path * @return {*} {GenericObject} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ protected abstract getModeForPath(path: string): GenericObject; @@ -447,7 +457,7 @@ namespace OS { * * @abstract * @return {*} {GenericObject} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract getEditorStatus(): GenericObject; @@ -459,7 +469,7 @@ namespace OS { * * @abstract * @return {*} {string} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract getValue(): string; @@ -471,51 +481,10 @@ namespace OS { * * @abstract * @param {string} value - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract setValue(value: string): void; - - /** - * Get the current editor position - * - * Should be implemented by subclasses - * - * @protected - * @abstract - * @return {*} {GenericObject} - * @memberof CodePadBaseEditorModel - */ - protected abstract getCursor(): GenericObject; - - - /** - * Create new instance of UndoManager - * - * This is specific to each editor, so - * it should be implemented by subclasses - * - * @protected - * @abstract - * @return {*} {GenericObject} - * @memberof CodePadBaseEditorModel - */ - protected abstract newUndoManager(): GenericObject; - - - /** - * Set the editor UndoManager - * - * Should be implemented by subclasses - * - * @protected - * @abstract - * @param {GenericObject} um - * @memberof CodePadBaseEditorModel - */ - protected abstract setUndoManager(um: GenericObject): void; - - /** * Set the editor language mode * @@ -523,24 +492,54 @@ namespace OS { * * @abstract * @param {GenericObject} m - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract setMode(m: GenericObject): void; /** - * Set current editor cursor position - * - * Should be implemented by subclasses + * Get textModel from the current editor session * * @protected * @abstract - * @param {GenericObject} c - * @memberof CodePadBaseEditorModel + * @return {*} {*} + * @memberof BaseEditorModel */ - protected abstract setCursor(c: GenericObject): 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 * @@ -548,7 +547,7 @@ namespace OS { * * @abstract * @param {string} theme - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract setTheme(theme: string): void; @@ -558,7 +557,7 @@ namespace OS { * * @abstract * @return {*} {GenericObject[]} - * @memberof CodePadBaseEditorModel + * @memberof BaseEditorModel */ abstract getModes(): GenericObject[]; } diff --git a/src/packages/CodePad/BaseExtension.ts b/src/packages/CodePad/BaseExtension.ts index 2db53db..240ccfc 100644 --- a/src/packages/CodePad/BaseExtension.ts +++ b/src/packages/CodePad/BaseExtension.ts @@ -37,40 +37,7 @@ namespace OS { import(libs: string[]): Promise { return API.require(libs); } - - - /** - * Get content of a file compressed in a zip archive - * - * @param {*} file - * @memberof BaseExtension - */ - loadzip(file: string, type:string): Promise - { - 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 []; } - /** - * Cat all files to a single output string - * - * @protected - * @param {string[]} list - * @param {string} data - * @returns {Promise} - * @memberof BaseExtension - */ - protected cat(list: string[], data: string): Promise { - 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>} - * @memberof BaseExtension - */ - protected read_files(list:string[], contents: GenericObject[]): Promise[]> - { - 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} - * @memberof BaseExtension - */ - protected copy(files: string[], to: string): Promise { - 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} - * @memberof BaseExtension - */ - private aradd(list: string[], zip: any, base: string): Promise { - 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 - | ArrayLike; - }) => { - 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} - * @memberof BaseExtension - */ - protected mkar(src: string, dest: string): Promise { - 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} - * @memberof BaseExtension - */ - protected mkdirAll(list: string[]): Promise { - 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} - * @memberof BaseExtension - */ - protected mkfileAll( - list: Array, - path: string, - name: string - ): Promise { - 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))); - }); - } /** * diff --git a/src/packages/CodePad/ExtensionMaker.ts b/src/packages/CodePad/ExtensionMaker.ts index d95ca7e..602b099 100644 --- a/src/packages/CodePad/ExtensionMaker.ts +++ b/src/packages/CodePad/ExtensionMaker.ts @@ -68,7 +68,7 @@ namespace OS { try { await this.build(meta); try { - return this.mkar( + return API.VFS.mkar( `${meta.root}/build/debug`, `${meta.root}/build/release/${meta.meta.name}.zip` ); @@ -157,14 +157,16 @@ namespace OS { ["templates/ext-main.tpl", `${rpath}/${name}.coffee`], ["templates/ext-extension.tpl", `${rpath}/extension.json`], ]; - this.mkdirAll(dirs) + API.VFS.mkdirAll(dirs) .then(async () => { 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.toggleSideBar(); return this.app.eum.active.openFile( - `${rpath}/${name}.coffee`.asFileHandle() as application.CodePadFileHandle + `${rpath}/${name}.coffee`.asFileHandle() as application.EditorFileHandle ); } catch (e) { return this.logger().error( @@ -227,7 +229,7 @@ namespace OS { try { await this.verify(list.map((x: string) => x)); try { - const code = await this.cat(list, ""); + const code = await API.VFS.cat(list, ""); const jsrc = CoffeeScript.compile(code); this.logger().info(__("Compiled successful")); return resolve(jsrc); @@ -257,7 +259,7 @@ namespace OS { const src = await this.compile(meta); let v: string; try { - const jsrc = await this.cat( + const jsrc = await API.VFS.cat( (() => { const result = []; for (v of meta.javascripts) { @@ -283,7 +285,7 @@ namespace OS { .then((data) => r(data)) .catch((ex_1) => e(__e(ex_1))) ); - await this.copy( + await API.VFS.copy( (() => { const result1 = []; for (v of meta.copies) { @@ -503,7 +505,7 @@ namespace OS { } } if (dir.length > 0) { - this.mkdirAll(dir) + API.VFS.mkdirAll(dir) .then(() => { this.installExtension( files, diff --git a/src/packages/CodePad/libs/corelib.d.ts.zip b/src/packages/CodePad/libs/corelib.d.ts.zip index 1f842d1..122ace6 100644 Binary files a/src/packages/CodePad/libs/corelib.d.ts.zip and b/src/packages/CodePad/libs/corelib.d.ts.zip differ diff --git a/src/packages/CodePad/main.ts b/src/packages/CodePad/main.ts index 0eba518..8e70c80 100644 --- a/src/packages/CodePad/main.ts +++ b/src/packages/CodePad/main.ts @@ -1,47 +1,5 @@ namespace OS { 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} - */ - um: GenericObject; - - /** - * Indicate whether the file is selected - * - * @type {boolean} - */ - selected: boolean; - - /** - * Store the latest cursor position on the editor - * when editing the file - * - * @type {GenericObject} - */ - cursor: GenericObject; - - /** - * Language mode setting of the file - * - * @type {GenericObject} - */ - langmode: GenericObject; - }; /** * [[CodePad]]'s [[CommandPalette]] action type definition */ @@ -252,14 +210,14 @@ namespace OS { // add editor instance this.eum - .add(new CodePadACEModel( + .add(new ACEModel( this, this.find("left-tabbar") as GUI.tag.TabBarTag, - this.find("left-editorarea")) as CodePadBaseEditorModel) - .add(new CodePadACEModel( + this.find("left-editorarea")) as BaseEditorModel) + .add(new ACEModel( this, 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.updateStatus(st) @@ -283,13 +241,13 @@ namespace OS { return reject(__e(e)); } }); - let file = "Untitled".asFileHandle() as CodePadFileHandle; + let file = "Untitled".asFileHandle() as EditorFileHandle; if (this.args && this.args.length > 0) { this.addRecent(this.args[0].path); 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 { - file = this.args[0].path.asFileHandle() as CodePadFileHandle; + file = this.args[0].path.asFileHandle() as EditorFileHandle; this.currdir = file.parent(); } } @@ -316,7 +274,7 @@ namespace OS { } this.addRecent(e.data.path); return this.eum.active.openFile( - e.data.path.asFileHandle() as CodePadFileHandle + e.data.path.asFileHandle() as EditorFileHandle ); }; @@ -519,7 +477,7 @@ namespace OS { else { $(right_pannel).show(); this.split_mode = true; - right_editor.openFile("Untitled".asFileHandle() as CodePadFileHandle); + right_editor.openFile("Untitled".asFileHandle() as EditorFileHandle); right_editor.focus(); } this.trigger("resize"); @@ -977,7 +935,7 @@ namespace OS { } switch (dataid) { case "new": - return me.eum.active.openFile("Untitled".asFileHandle() as CodePadFileHandle); + return me.eum.active.openFile("Untitled".asFileHandle() as EditorFileHandle); case "open": return me .openDialog("FileDialog", { @@ -1081,7 +1039,7 @@ namespace OS { ], onchildselect: ( e: GUI.TagEventType, - r: CodePadFileHandle + r: EditorFileHandle ) => { switch (e.data.item.data.dataid) { case "cmdpalette": @@ -1225,19 +1183,19 @@ namespace OS { * Referent to the active editor model * * @private - * @type {CodePadBaseEditorModel} + * @type {BaseEditorModel} * @memberof EditorModelManager */ - private active_editor: CodePadBaseEditorModel; + private active_editor: BaseEditorModel; /** * Store a list of editor models * * @private - * @type {CodePadBaseEditorModel[]} + * @type {BaseEditorModel[]} * @memberof EditorModelManager */ - private models: CodePadBaseEditorModel[]; + private models: BaseEditorModel[]; /** * Creates an instance of EditorModelManager. @@ -1248,7 +1206,7 @@ namespace OS { this.models = []; } - get editors(): CodePadBaseEditorModel[] { + get editors(): BaseEditorModel[] { return this.models; } set contextmenuHandle(cb: (e: any, m: any) => void) { @@ -1261,20 +1219,20 @@ namespace OS { * Get the active editor model * * @readonly - * @type {CodePadBaseEditorModel} + * @type {BaseEditorModel} * @memberof EditorModelManager */ - get active(): CodePadBaseEditorModel { + get active(): BaseEditorModel { return this.active_editor; } /** * Add a model to the manager * - * @param {CodePadBaseEditorModel} model + * @param {BaseEditorModel} model * @memberof EditorModelManager */ - add(model: CodePadBaseEditorModel): EditorModelManager { + add(model: BaseEditorModel): EditorModelManager { this.models.push(model); if (!this.active_editor) this.active_editor = model; @@ -1290,7 +1248,7 @@ namespace OS { } } - dirties(): CodePadFileHandle[] { + dirties(): EditorFileHandle[] { let list = []; for (let ed of this.models) { list = list.concat(ed.dirties());