add some JSDoc to the code

This commit is contained in:
lxsang 2020-06-10 11:15:01 +02:00
parent edbffeb2b8
commit 6365081f56
22 changed files with 1562 additions and 370 deletions

View File

@ -1,6 +1,7 @@
BUILDDIR?=build/htdocs/os BUILDDIR?=/opt/www/htdocs/os
DOCDIR?=/opt/www/htdocs/docs/antos/api
BLUE=\033[1;34m BLUE=\033[1;34m
NC=\033[0m NC=\033[0m
@ -156,6 +157,9 @@ uglify:
release: main uglify release: main uglify
doc:
typedoc --mode file --excludeNotExported --hideGenerator --out $(DOCDIR)
clean: clean:
rm -rf $(BUILDDIR)/resources rm -rf $(BUILDDIR)/resources
rm -rf $(BUILDDIR)/scripts rm -rf $(BUILDDIR)/scripts

View File

@ -5,44 +5,28 @@
[![Build Status](https://travis-ci.org/lxsang/antos.svg?branch=master)](https://travis-ci.org/lxsang/antos) [![Build Status](https://travis-ci.org/lxsang/antos.svg?branch=master)](https://travis-ci.org/lxsang/antos)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Flxsang%2Fantos.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Flxsang%2Fantos?ref=badge_shield) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Flxsang%2Fantos.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Flxsang%2Fantos?ref=badge_shield)
Server or Embedded Linux are often headless, so accessing the resource on these systems is not always obvious. The aim of this project is to develop a client core API that enables desktop like experience to remote server's resource accessing using web technologies. AntOS is based on jQuery and Riot, it is designed to be used along with our [**antd**](https://github.com/lxsang/ant-http) server and Lua based server side app, but it can also be adapted to any server side languages (PHP, etc) and server, by implementing all the system calls API defined in core/handlers/RemoteHandler.coffee. Basically, application design for the web os relies on these system calls to communicating with the server. The API defines the core UI, system calls (to server), Virtual File system, virtual database and the necessary libraries for easing the development of webOS's applications. Applications can be developped with coffee/javascript/css without the need of a server side script. AntOS is a front-end API that mimics the traditional desktop environment on the web browser. The front-end can connect to a remote server and acts as a virtual desktop environment (VDE). The original purpose of AntOS is to provide visual tools to access and control resource on remote server
and embedded linux environment. With its application API and the provided SDK, AntOS facilitates the
development and deployment of user specific applications.
This repository contains only the front-end API. To have fully functional VDE, AntOS need to connect
to the corresponding server side API.
Note that, the development of the project is in early alpha state, so bugs are very welcome :)
The WebOS is tested on recent Firefox, Chrome and Safari, however i did not test it on IE or Edge since i have no Windows device :)
## Demo ## Demo
A demo of the web desktop is available at my page [https://os.lxsang.me](https://os.lxsang.me) using username: demo and password: demo A demo of the VDE is available at my page [https://os.lxsang.me](https://os.lxsang.me) using username: demo and password: demo
![Screenshot](screenshot.png "Screenshot")
## AntOS applications ## AntOS applications
[https://github.com/lxsang/antosdk-apps](https://github.com/lxsang/antosdk-apps) [https://github.com/lxsang/antosdk-apps](https://github.com/lxsang/antosdk-apps)
## Dependencies ## Documentation
- npm install @types/jquery - API documentation: [https://doc.iohuv.dev/antos/api/](https://doc.iohuv.dev/antos/api/)
- typescript
- sudo npm install terser -g (optional)
- uglifycss (optional)
- jest, tes-jest (typescript test) (optional)
- npm install @types/jest
-
## Build
Note that this is only the client API, to make it work for your application, you need to implement all the system calls in core/handlers/RemoteHandler.coffee using a server side scripting language (e.g. PHP). I'm planning to release an API documentation which describes what need to be sent and what will be returned for each system call in near future (i'm kind of very busy right now :) ).
I'm a big fan of the Make system, so i use it as a build system for all of my projects. So, to build AntOS:
1. You need to have *make* installed. Then since most of the API is written in Coffee script, you will need it to be installed too.
2. Edit the BUILDDIR variable in the Makefile file to point to where you want to put the built API
3. Type `make` then you are good to go.
It you have any problem, please contact me or open an issue, i'll try to response ASAP.
## Licence ## Licence
Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com> Copyright 2017-2020 Xuan Sang LE <xsang.le AT gmail DOT com>
AnTOS is is licensed under the GNU General Public License v3.0, see the LICENCE file for more information AnTOS is is licensed under the GNU General Public License v3.0, see the LICENCE file for more information

View File

@ -219,10 +219,10 @@ namespace OS {
* *
* *
* @export * @export
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @param {Error} e * @param {Error} e
*/ */
export function osfail(m: string | FormatedString, e: Error): void { export function osfail(m: string | FormattedString, e: Error): void {
announcer.ostrigger("fail", { m, e }); announcer.ostrigger("fail", { m, e });
} }
@ -230,10 +230,10 @@ namespace OS {
* *
* *
* @export * @export
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @param {Error} e * @param {Error} e
*/ */
export function oserror(m: string | FormatedString, e: Error): void { export function oserror(m: string | FormattedString, e: Error): void {
announcer.ostrigger("error", { m, e }); announcer.ostrigger("error", { m, e });
} }
@ -241,9 +241,9 @@ namespace OS {
* *
* *
* @export * @export
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
*/ */
export function osinfo(m: string | FormatedString): void { export function osinfo(m: string | FormattedString): void {
announcer.ostrigger("info", { m, e: null }); announcer.ostrigger("info", { m, e: null });
} }

View File

@ -302,10 +302,10 @@ namespace OS {
/** /**
* *
* *
* @returns {(string| FormatedString)} * @returns {(string| FormattedString)}
* @memberof BaseApplication * @memberof BaseApplication
*/ */
title(): string| FormatedString { title(): string| FormattedString {
return (this.scheme as GUI.tag.WindowTag).apptitle; return (this.scheme as GUI.tag.WindowTag).apptitle;
} }

View File

@ -393,14 +393,14 @@ namespace OS {
* *
* @protected * @protected
* @param {string} t * @param {string} t
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @param {Error} [e] * @param {Error} [e]
* @returns {void} * @returns {void}
* @memberof BaseModel * @memberof BaseModel
*/ */
protected publish( protected publish(
t: string, t: string,
m: string | FormatedString, m: string | FormattedString,
e?: Error e?: Error
): void { ): void {
const mt = this.meta(); const mt = this.meta();
@ -423,34 +423,34 @@ namespace OS {
/** /**
* *
* *
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @returns {void} * @returns {void}
* @memberof BaseModel * @memberof BaseModel
*/ */
notify(m: string | FormatedString): void { notify(m: string | FormattedString): void {
return this.publish("notification", m); return this.publish("notification", m);
} }
/** /**
* *
* *
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @returns {void} * @returns {void}
* @memberof BaseModel * @memberof BaseModel
*/ */
warn(m: string | FormatedString): void { warn(m: string | FormattedString): void {
return this.publish("warning", m); return this.publish("warning", m);
} }
/** /**
* *
* *
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @param {Error} [e] * @param {Error} [e]
* @returns * @returns
* @memberof BaseModel * @memberof BaseModel
*/ */
error(m: string | FormatedString, e?: Error) { error(m: string | FormattedString, e?: Error) {
return this.publish("error", m, e ? e : this._api.throwe(m)); return this.publish("error", m, e ? e : this._api.throwe(m));
} }

View File

@ -1,13 +1,4 @@
/* // Copyright 2017-2020 Xuan Sang LE <xsang.le AT gmail DOT com>
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS202: Simplify dynamic range loops
* DS205: Consider reworking code to avoid use of IIFEs
* DS208: Avoid top-level this
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public // AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information // License v3.0, see the LICENCE file for more information
@ -40,7 +31,7 @@ interface String {
unescape(): string; unescape(): string;
asUint8Array(): Uint8Array; asUint8Array(): Uint8Array;
format(...args: any[]): string; format(...args: any[]): string;
f(...args: any[]): OS.FormatedString; f(...args: any[]): OS.FormattedString;
__(): string; __(): string;
l(): string; l(): string;
trimLeft(arg: string): string; trimLeft(arg: string): string;
@ -71,9 +62,9 @@ interface GenericObject<T> {
* *
* *
* @param {...any[]} args * @param {...any[]} args
* @returns {(OS.FormatedString | string)} * @returns {(OS.FormattedString | string)}
*/ */
declare function __(...args: any[]): OS.FormatedString | string; declare function __(...args: any[]): OS.FormattedString | string;
/** /**
* *
@ -111,13 +102,13 @@ namespace OS {
return range; return range;
} }
Ant.__ = function (...args: any[]): FormatedString | string { Ant.__ = function (...args: any[]): FormattedString | string {
if (!(args.length > 0)) { if (!(args.length > 0)) {
return "Undefined"; return "Undefined";
} }
const d = args[0]; const d = args[0];
d.l(); d.l();
return new FormatedString( return new FormattedString(
d, d,
__range__(1, args.length - 1, true).map((i) => args[i]) __range__(1, args.length - 1, true).map((i) => args[i])
); );
@ -134,9 +125,9 @@ namespace OS {
* *
* *
* @export * @export
* @class FormatedString * @class FormattedString
*/ */
export class FormatedString { export class FormattedString {
fs: string; fs: string;
values: any[]; values: any[];
constructor(fs: string, args: any[]) { constructor(fs: string, args: any[]) {
@ -158,7 +149,7 @@ namespace OS {
* *
* *
* @returns {string} * @returns {string}
* @memberof FormatedString * @memberof FormattedString
*/ */
toString(): string { toString(): string {
return this.__(); return this.__();
@ -168,7 +159,7 @@ namespace OS {
* *
* *
* @returns {string} * @returns {string}
* @memberof FormatedString * @memberof FormattedString
*/ */
__(): string { __(): string {
return this.fs return this.fs
@ -186,7 +177,7 @@ namespace OS {
* *
* *
* @returns {number} * @returns {number}
* @memberof FormatedString * @memberof FormattedString
*/ */
hash(): number { hash(): number {
return this.__().hash(); return this.__().hash();
@ -197,7 +188,7 @@ namespace OS {
* *
* @param {(string | RegExp)} t * @param {(string | RegExp)} t
* @returns {RegExpMatchArray} * @returns {RegExpMatchArray}
* @memberof FormatedString * @memberof FormattedString
*/ */
match(t: string | RegExp): RegExpMatchArray { match(t: string | RegExp): RegExpMatchArray {
return this.__().match(t); return this.__().match(t);
@ -207,7 +198,7 @@ namespace OS {
* *
* *
* @returns {string} * @returns {string}
* @memberof FormatedString * @memberof FormattedString
*/ */
asBase64(): string { asBase64(): string {
return this.__().asBase64(); return this.__().asBase64();
@ -217,7 +208,7 @@ namespace OS {
* *
* *
* @returns {string} * @returns {string}
* @memberof FormatedString * @memberof FormattedString
*/ */
unescape(): string { unescape(): string {
return this.__().unescape(); return this.__().unescape();
@ -227,7 +218,7 @@ namespace OS {
* *
* *
* @returns {Uint8Array} * @returns {Uint8Array}
* @memberof FormatedString * @memberof FormattedString
*/ */
asUint8Array(): Uint8Array { asUint8Array(): Uint8Array {
return this.__().asUint8Array(); return this.__().asUint8Array();
@ -237,7 +228,7 @@ namespace OS {
* *
* *
* @param {...any[]} args * @param {...any[]} args
* @memberof FormatedString * @memberof FormattedString
*/ */
format(...args: any[]): void { format(...args: any[]): void {
__range__(0, args.length - 1, true).map( __range__(0, args.length - 1, true).map(
@ -444,8 +435,8 @@ namespace OS {
}; };
} }
String.prototype.f = function (...args: any[]): FormatedString { String.prototype.f = function (...args: any[]): FormattedString {
return new FormatedString(this, args); return new FormattedString(this, args);
}; };
String.prototype.__ = function (): string { String.prototype.__ = function (): string {
@ -810,12 +801,16 @@ namespace OS {
} }
/** /**
* * Perform an REST GET request
* *
* @export * @export
* @param {string} p * @param {string} p the URI of the request
* @param {string} [t=undefined] * @param {string} [t=undefined] the response data type:
* @returns {Promise<any>} * - jsonp: the response is an json object
* - script: the response is a javascript code
* - xm, html: the response is a XML/HTNL object
* - text: plain text
* @returns {Promise<any>} a Promise on the requested data
*/ */
export function get(p: string, t: string = undefined): Promise<any> { export function get(p: string, t: string = undefined): Promise<any> {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
@ -1083,10 +1078,10 @@ namespace OS {
* *
* *
* @export * @export
* @param {(string | FormatedString)} n * @param {(string | FormattedString)} n
* @returns {Error} * @returns {Error}
*/ */
export function throwe(n: string | FormatedString): Error { export function throwe(n: string | FormattedString): Error {
let err = undefined; let err = undefined;
try { try {
throw new Error(n.__()); throw new Error(n.__());

View File

@ -44,7 +44,7 @@ namespace OS {
* @interface BasicItemType * @interface BasicItemType
*/ */
export interface BasicItemType { export interface BasicItemType {
text: string | FormatedString; text: string | FormattedString;
children?: BasicItemType[]; children?: BasicItemType[];
nodes?: BasicItemType[]; nodes?: BasicItemType[];
[propName: string]: any; [propName: string]: any;

View File

@ -1,9 +1,4 @@
/* // Copyright 2017-2020 Xuan Sang LE <xsang.le AT gmail DOT com>
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public // AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information // License v3.0, see the LICENCE file for more information
@ -23,48 +18,172 @@
namespace OS { namespace OS {
export namespace API { export namespace API {
/**
* Interface for user login data
*
* @export
* @interface UserLoginType
*/
export interface UserLoginType { export interface UserLoginType {
/**
* The user credential
*
* @type {string}
* @memberof UserLoginType
*/
username: string; username: string;
/**
* The user password
*
* @type {string}
* @memberof UserLoginType
*/
password: string; password: string;
} }
/**
* Interface for a command sent to
* server side package manage, it contains two field:
*
* @export
* @interface PackageCommandType
*/
export interface PackageCommandType { export interface PackageCommandType {
/**
* Command name, should be: `init`, `cache`, `install`,
* `uninstall` or `list`
*
* @type {string}
* @memberof PackageCommandType
*/
command: string; command: string;
/**
* Parameter object of each command
*
* @type {GenericObject<any>}
* @memberof PackageCommandType
*/
args: GenericObject<any>; args: GenericObject<any>;
} }
/**
*
* Interface for basic request result returned
* from the server-side. A valid server-side response should
* be in the following format
* ```json
* {
* "error": boolean or string_err,
* "result": JSON result object
* }
* ```
*
* @export
* @interface RequestResult
*/
export interface RequestResult { export interface RequestResult {
/**
* Indicate whether an the response is error
*
* @type {(boolean | string)}
* @memberof RequestResult
*/
error: boolean | string; error: boolean | string;
/**
* The response result, this value must be
* set when `error` is false
*
* @type {(string
* | boolean
* | GenericObject<any>
* | any[]
* | FileInfoType
* | FileInfoType[]
* | setting.UserSettingType)}
* @memberof RequestResult
*/
result: result:
| string | string
| boolean | boolean
| GenericObject<any> | GenericObject<any>
| any[] | any[]
| FileInfoType | FileInfoType
| FileInfoType[]; | FileInfoType[]
| setting.UserSettingType;
} }
let loc: any = { hostname: "localhost", port: "80", protocol: "http" }; let loc: any = { hostname: "localhost", port: "80", protocol: "http" };
if (Ant.location) loc = Ant.location; if (Ant.location) loc = Ant.location;
/**
* The host name of the server-side
*/
export var HOST: string = export var HOST: string =
loc.hostname + (loc.port ? `:${loc.port}` : ""); loc.hostname + (loc.port ? `:${loc.port}` : "");
/**
* The base REST URI of the server-side API
*/
export var REST: string = `${loc.protocol}//${HOST}`; export var REST: string = `${loc.protocol}//${HOST}`;
/**
* The namespace `handle` contains some low level API to
* communicate with the server side API. It is the only
* API layer that communicate directly with the server.
* To make AntOS compatible with any server side API,
* all exported variable unctions defined in the `handle`
* namespace should be re-implemented
*/
export namespace handle { export namespace handle {
// get file, require authentification /**
* Base URI for reading content of VFS file
*/
export var get: string = `${REST}/VFS/get`; export var get: string = `${REST}/VFS/get`;
// get shared file with publish /**
* Base URI for VFS file sharing
*/
export var shared: string = `${REST}/VFS/shared`; export var shared: string = `${REST}/VFS/shared`;
/**
* Send a request to the server-side API for a directory scanning
* operation
*
* @export
* @param {string} p a VFS file path e.g. home://test/
* @returns {Promise<RequestResult>} A promise on a [[RequestResult
* which contains an error or a list of FileInfoType
*/
export function scandir(p: string): Promise<RequestResult> { export function scandir(p: string): Promise<RequestResult> {
const path = `${REST}/VFS/scandir`; const path = `${REST}/VFS/scandir`;
return API.post(path, { path: p }); return API.post(path, { path: p });
} }
/**
*
* Send a request to the server-side API for directory creation
*
* @export
* @param {string} p VFS path of the directory to be created
* @returns {Promise<RequestResult>} A promise on a RequestResult
* which contains an error or true on success
*/
export function mkdir(p: string): Promise<RequestResult> { export function mkdir(p: string): Promise<RequestResult> {
const path = `${API.REST}/VFS/mkdir`; const path = `${API.REST}/VFS/mkdir`;
return API.post(path, { path: p }); return API.post(path, { path: p });
} }
/**
* Send a request to the server-side API for sharing/unsharing a VFS file,
* once shared a VFS file will be publicly visible by everyone
*
* @export
* @param {string} p VFS file path to be shared
* @param {boolean} pub flag: share (true) or unshare (false)
* @returns {Promise<RequestResult>} A promise on a RequestResult
* which contains an error or true on success
*/
export function sharefile( export function sharefile(
p: string, p: string,
pub: boolean pub: boolean
@ -73,31 +192,88 @@ namespace OS {
return API.post(path, { path: p, publish: pub }); return API.post(path, { path: p, publish: pub });
} }
/**
* Get VFS file meta-data
*
* @export
* @param {string} p VFS file path
* @returns {Promise<RequestResult>} A promise on a [[RequestResult]]
* which contains an error or an object of FileInfoType
*/
export function fileinfo(p: string): Promise<RequestResult> { export function fileinfo(p: string): Promise<RequestResult> {
const path = `${API.REST}/VFS/fileinfo`; const path = `${API.REST}/VFS/fileinfo`;
return API.post(path, { path: p }); return API.post(path, { path: p });
} }
/**
* Read a VFS file content. There are many ways a VFS file can be read:
* - Read as a raw text content
* - Read as a javascript file, in this case the content of the
* file will be executed
* - Read as JSON object
*
* @export
* @param {string} p path of the VFS file
* @param {string} t return data type:
* - jsonp: the response is an json object
* - script: the response is a javascript code
* - xm, html: the response is a XML/HTML object
* - text: plain text
*
* @returns {Promise<any>} A promise on a [[RequestResult]]
* which contains an error or an object of [[FileInfoType]]
*/
export function readfile(p: string, t: string): Promise<any> { export function readfile(p: string, t: string): Promise<any> {
const path = `${API.REST}/VFS/get/`; const path = `${API.REST}/VFS/get/`;
return API.get(path + p, t); return API.get(path + p, t);
} }
/**
* Move a file to another location on server-side
*
* @export
* @param {string} s VFS source file path
* @param {string} d VFS destination file path
* @returns {Promise<RequestResult>} A promise on a [[RequestResult]]
* which contains an error or a success response
*/
export function move(s: string, d: string): Promise<RequestResult> { export function move(s: string, d: string): Promise<RequestResult> {
const path = `${API.REST}/VFS/move`; const path = `${API.REST}/VFS/move`;
return API.post(path, { src: s, dest: d }); return API.post(path, { src: s, dest: d });
} }
/**
* Delete a VFS file on the server-side
*
* @export
* @param {string} p VFS file path
* @returns {Promise<RequestResult>} A promise on a [[RequestResult]]
* which contains an error or a success response
*/
export function remove(p: string): Promise<RequestResult> { export function remove(p: string): Promise<RequestResult> {
const path = `${API.REST}/VFS/delete`; const path = `${API.REST}/VFS/delete`;
return API.post(path, { path: p }); return API.post(path, { path: p });
} }
/**
* Read the file as binary data
*
* @export
* @param {string} p VFS file to be read
* @returns {Promise<ArrayBuffer>} a Promise on an array buffer
*/
export function fileblob(p: string): Promise<ArrayBuffer> { export function fileblob(p: string): Promise<ArrayBuffer> {
const path = `${API.REST}/VFS/get/`; const path = `${API.REST}/VFS/get/`;
return API.blob(path + p); return API.blob(path + p);
} }
/**
* Send a command to the serverside package manager
*
* @export
* @param {PackageCommandType} d a package command of type PackageCommandType
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function packages( export function packages(
d: PackageCommandType d: PackageCommandType
): Promise<RequestResult> { ): Promise<RequestResult> {
@ -105,11 +281,26 @@ namespace OS {
return API.post(path, d); return API.post(path, d);
} }
/**
* Upload file to the server via VFS interface
*
* @export
* @param {string} d VFS destination directory path
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function upload(d: string): Promise<RequestResult> { export function upload(d: string): Promise<RequestResult> {
const path = `${API.REST}/VFS/upload`; const path = `${API.REST}/VFS/upload`;
return API.upload(path, d); return API.upload(path, d);
} }
/**
* Write Base 64 encoded data to a VFS file
*
* @export
* @param {string} p path to the VFS file
* @param {string} d file data encoded in Base 64
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function write( export function write(
p: string, p: string,
d: string d: string
@ -117,6 +308,35 @@ namespace OS {
const path = `${API.REST}/VFS/write`; const path = `${API.REST}/VFS/write`;
return API.post(path, { path: p, data: d }); return API.post(path, { path: p, data: d });
} }
/**
* An apigateway allows client side to execute a custom server-side
* script and get back the result. This gateway is particularly
* useful in case of performing a task that is not provided by the core
* API
*
* @export
* @param {GenericObject<any>} d execution indication, provided only when ws is `false`
* otherwise, `d` should be written directly to the websocket stream as JSON object.
* Two possible formats of `d`:
* ```text
* execute an server-side script file:
*
* {
* path: [VFS path],
* parameters: [parameters of the server-side script]
* }
*
* or, execute directly a snippet of server-side script:
*
* { code: [server-side script code snippet as string] }
*
* ```
*
* @param {boolean} ws flag indicate whether to use websocket for the connection
* to the gateway API. In case of streaming data, the websocket is preferred
* @returns {Promise<any>} a promise on the result object (any)
*/
export function apigateway( export function apigateway(
d: GenericObject<any>, d: GenericObject<any>,
ws: boolean ws: boolean
@ -141,26 +361,98 @@ namespace OS {
} }
} }
/**
* Check if a user is logged in
*
* @export
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]] that
* contains an error or a [[UserSettingType]] object
*/
export function auth(): Promise<RequestResult> { export function auth(): Promise<RequestResult> {
const p = `${API.REST}/user/auth`; const p = `${API.REST}/user/auth`;
return API.post(p, {}); return API.post(p, {});
} }
/**
* Perform a login operation
*
* @export
* @param {UserLoginType} d user data [[UserLoginType]]
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]] that
* contains an error or a [[UserSettingType]] object
*/
export function login(d: UserLoginType): Promise<RequestResult> { export function login(d: UserLoginType): Promise<RequestResult> {
const p = `${API.REST}/user/login`; const p = `${API.REST}/user/login`;
return API.post(p, d); return API.post(p, d);
} }
/**
* Perform a logout operation
*
* @export
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function logout(): Promise<RequestResult> { export function logout(): Promise<RequestResult> {
const p = `${API.REST}/user/logout`; const p = `${API.REST}/user/logout`;
return API.post(p, {}); return API.post(p, {});
} }
/**
* Save the current user settings
*
* @export
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function setting(): Promise<RequestResult> { export function setting(): Promise<RequestResult> {
const p = `${API.REST}/system/settings`; const p = `${API.REST}/system/settings`;
return API.post(p, OS.setting); return API.post(p, OS.setting);
} }
/**
* This is the low level function of AntOS VDB API.
* It requests the server API to perform some simple
* SQL query.
*
* @export
* @param {string} cmd action to perform: save, delete, get, select
* @param {GenericObject<any>} d data object of the request based on each action:
* - save:
* ```
* { table: "table name", data: [record data object]}
* ```
* - get:
* ```
* { table: "table name", id: [record id]}
* ```
* - delete:
* ```
* { table: "table name", id: [record id]}
* or
* { table: "table name", cond: [conditional object]}
* ```
* - select:
* ```
* { table: "table name", cond: [conditional object]}
* ```
* @returns {Promise<RequestResult>} a promise of [[RequestResult]] on the
* query data
*
* A conditional object represents a SQL condition statement as an object,
* example: `pid = 10 AND cid = 2 ORDER BY date DESC`
* ```
* {
* exp: {
* "and": {
* pid: 10,
* cid: 2
* }
* },
* order: {
* date: "DESC"
* }
* }
* ```
*/
export function dbquery( export function dbquery(
cmd: string, cmd: string,
d: GenericObject<any> d: GenericObject<any>

View File

@ -1,35 +1,69 @@
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
/** /**
* *
* Interface for an application dock item
* *
* @export * @export
* @interface AppDockItemType * @interface AppDockItemType
*/ */
export interface AppDockItemType { export interface AppDockItemType {
/**
* Reference to the application process represented
* by the dock item
*
* @type {application.BaseApplication}
* @memberof AppDockItemType
*/
app: application.BaseApplication; app: application.BaseApplication;
/**
* Reference to the DOM element of
* the owner dock item
*
* @type {AFXTag}
* @memberof AppDockItemType
*/
domel?: AFXTag; domel?: AFXTag;
[propName: string]: any; [propName: string]: any;
} }
export namespace tag { export namespace tag {
/** /**
* * This class define the AntOS system application dock tag
* *
* @export * @export
* @class AppDockTag * @class AppDockTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class AppDockTag extends AFXTag { export class AppDockTag extends AFXTag {
/**
* variable holds the application select event
* callback handle
*
* @private
* @type {TagEventCallback<any>}
* @memberof AppDockTag
*/
private _onappselect: TagEventCallback<any>; private _onappselect: TagEventCallback<any>;
/**
* Items data of the dock
*
* @private
* @type {AppDockItemType[]}
* @memberof AppDockTag
*/
private _items: AppDockItemType[]; private _items: AppDockItemType[];
/**
* Reference to the currently select application
* process in the dock
*
* @private
* @type {application.BaseApplication}
* @memberof AppDockTag
*/
private _selectedApp: application.BaseApplication; private _selectedApp: application.BaseApplication;
/** /**
@ -42,17 +76,17 @@ namespace OS {
} }
/** /**
* * Implementation of the abstract function: Update the current tag.
* It do nothing for this tag
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d]
* @memberof AppDockTag * @memberof AppDockTag
*/ */
protected reload(d?: any): void { protected reload(d?: any): void {}
}
/** /**
* * Init the tag before mounting
* *
* @protected * @protected
* @memberof AppDockTag * @memberof AppDockTag
@ -62,7 +96,8 @@ namespace OS {
} }
/** /**
* * The tag layout, it is empty on creation but elements will
* be added automatically to it in operation
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}
@ -73,16 +108,7 @@ namespace OS {
} }
/** /**
* * getter to get the dock items
*
* @protected
* @param {*} [d]
* @memberof AppDockTag
*/
protected refresh(d?: any): void {}
/**
*
* *
* @readonly * @readonly
* @type {AppDockItemType[]} * @type {AppDockItemType[]}
@ -93,7 +119,10 @@ namespace OS {
} }
/** /**
* * Setter to set the selected application in the dock
* this will trigger two event:
* - `focus`: on the selected application
* - `blur`: on all other applications on the dock
* *
* @memberof AppDockTag * @memberof AppDockTag
*/ */
@ -115,7 +144,8 @@ namespace OS {
} }
/** /**
* * getter to get the current selected application
* on the dock
* *
* @type {BaseApplication} * @type {BaseApplication}
* @memberof AppDockTag * @memberof AppDockTag
@ -125,9 +155,12 @@ namespace OS {
} }
/** /**
* When a new application process is created, this function
* will be called to add new application entry to the dock.
* The added application will becomes the current selected
* application
* *
* * @param {AppDockItemType} item an application dock item entry
* @param {AppDockItemType} item
* @memberof AppDockTag * @memberof AppDockTag
*/ */
newapp(item: AppDockItemType): void { newapp(item: AppDockItemType): void {
@ -150,9 +183,11 @@ namespace OS {
} }
/** /**
* Delete and application entry from the dock.
* This function will be called when an application
* is exit
* *
* * @param {BaseApplication} a the application to be removed from the dock
* @param {BaseApplication} a
* @memberof AppDockTag * @memberof AppDockTag
*/ */
removeapp(a: application.BaseApplication): void { removeapp(a: application.BaseApplication): void {
@ -174,7 +209,7 @@ namespace OS {
} }
/** /**
* * Mount the current dock tag
* *
* @protected * @protected
* @memberof AppDockTag * @memberof AppDockTag
@ -184,7 +219,9 @@ namespace OS {
if (e.target === this) { if (e.target === this) {
return; return;
} }
const bt = $(e.target).closest("afx-button")[0] as any as ButtonTag; const bt = ($(e.target).closest(
"afx-button"
)[0] as any) as ButtonTag;
const app = bt.data; const app = bt.data;
m.items = [ m.items = [
{ text: "__(Show)", dataid: "show" }, { text: "__(Show)", dataid: "show" },

View File

@ -1,46 +1,113 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/**
* This tag define a basic button and its behavior
*
* @export
* @class ButtonTag
* @extends {AFXTag}
*/
export class ButtonTag extends AFXTag { export class ButtonTag extends AFXTag {
private _selected: boolean; /**
* Variable hold the button click callback handle
*
* @private
* @type {TagEventCallback<JQuery.MouseEventBase>}
* @memberof ButtonTag
*/
private _onbtclick: TagEventCallback<JQuery.MouseEventBase>; private _onbtclick: TagEventCallback<JQuery.MouseEventBase>;
/**
* Custom user data
*
* @type {GenericObject<any>}
* @memberof ButtonTag
*/
data: GenericObject<any>; data: GenericObject<any>;
/**
*Creates an instance of ButtonTag.
* @memberof ButtonTag
*/
constructor() { constructor() {
super(); super();
} }
set onbtclick(v: TagEventCallback<JQuery.MouseEventBase>)
{ /**
* Set the click callback handle for the target button
*
* @memberof ButtonTag
*/
set onbtclick(v: TagEventCallback<JQuery.MouseEventBase>) {
this._onbtclick = v; this._onbtclick = v;
} }
/**
* Set the path to the button icon, the path should be
* a VFS file path
*
* @memberof ButtonTag
*/
set icon(v: string) { set icon(v: string) {
$(this).attr("icon", v); $(this).attr("icon", v);
(this.refs.label as LabelTag).icon = v; (this.refs.label as LabelTag).icon = v;
} }
/**
* Set the icon class to the button, this property
* allows to style the button icon using CSS
*
* @memberof ButtonTag
*/
set iconclass(v: string) { set iconclass(v: string) {
$(this).attr("iconclass", v); $(this).attr("iconclass", v);
(this.refs.label as LabelTag).iconclass = v; (this.refs.label as LabelTag).iconclass = v;
} }
set text(v: string | FormatedString) { /**
* Set the text of the button
*
* @memberof ButtonTag
*/
set text(v: string | FormattedString) {
(this.refs.label as LabelTag).text = v; (this.refs.label as LabelTag).text = v;
} }
get text(): string| FormatedString {
/**
* Get the current button test
*
* @type {(string| FormattedString)}
* @memberof ButtonTag
*/
get text(): string | FormattedString {
return (this.refs.label as LabelTag).text; return (this.refs.label as LabelTag).text;
} }
/**
* Enable or disable the button
*
* @memberof ButtonTag
*/
set enable(v: boolean) { set enable(v: boolean) {
$(this.refs.button).prop("disabled", !v); $(this.refs.button).prop("disabled", !v);
} }
/**
* Get the `enable` property of the button
*
* @type {boolean}
* @memberof ButtonTag
*/
get enable(): boolean { get enable(): boolean {
return !$(this.refs.button).prop("disabled"); return !$(this.refs.button).prop("disabled");
} }
/**
* set or remove the attribute `selected` of the button
*
* @memberof ButtonTag
*/
set selected(v: boolean) { set selected(v: boolean) {
$(this.refs.button).removeClass(); $(this.refs.button).removeClass();
this.attsw(v, "selected"); this.attsw(v, "selected");
@ -48,18 +115,42 @@ namespace OS {
$(this.refs.button).addClass("selected"); $(this.refs.button).addClass("selected");
} }
} }
/**
* check whether the attribute `selected` of the button is set
*
* @type {boolean}
* @memberof ButtonTag
*/
get selected(): boolean { get selected(): boolean {
return this.hasattr("selected"); return this.hasattr("selected");
} }
/**
* activate or deactivate the toggle mode of the button
*
* @memberof ButtonTag
*/
set toggle(v: boolean) { set toggle(v: boolean) {
this.attsw(v, "toggle"); this.attsw(v, "toggle");
} }
/**
* Check whether the button is in toggle mode
*
* @type {boolean}
* @memberof ButtonTag
*/
get toggle(): boolean { get toggle(): boolean {
return this.hasattr("toggle"); return this.hasattr("toggle");
} }
/**
* Mount the tag
*
* @protected
* @memberof ButtonTag
*/
protected mount() { protected mount() {
$(this.refs.button).click((e) => { $(this.refs.button).click((e) => {
const evt: TagEventType<JQuery.MouseEventBase> = { const evt: TagEventType<JQuery.MouseEventBase> = {
@ -73,13 +164,42 @@ namespace OS {
} }
}); });
} }
/**
* Init the tag before mounting
*
* @protected
* @memberof ButtonTag
*/
protected init(): void { protected init(): void {
this.enable = true; this.enable = true;
this.toggle = false; this.toggle = false;
this._onbtclick = (e) => {}; this._onbtclick = (e) => {};
} }
/**
* Re-calibrate the button, do nothing in this tag
*
* @protected
* @memberof ButtonTag
*/
protected calibrate(): void {} protected calibrate(): void {}
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof ButtonTag
*/
reload(d?: any): void {} reload(d?: any): void {}
/**
* Button layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof ButtonTag
*/
protected layout(): TagLayoutType[] { protected layout(): TagLayoutType[] {
return [ return [
{ {
@ -90,6 +210,7 @@ namespace OS {
]; ];
} }
} }
define("afx-button", ButtonTag); define("afx-button", ButtonTag);
} }
} }

View File

@ -1,25 +1,57 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS202: Simplify dynamic range loops
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/** /**
* * Tag that define system calendar widget
* *
* @export * @export
* @class CalendarTag * @class CalendarTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class CalendarTag extends AFXTag { export class CalendarTag extends AFXTag {
/**
* The current selected day
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _day: number; private _day: number;
/**
* The current selected month
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _month: number; private _month: number;
/**
* The current selected year
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _year: number; private _year: number;
/**
* The current selected date object
*
* @private
* @type {Date}
* @memberof CalendarTag
*/
private _selectedDate: Date; private _selectedDate: Date;
/**
* holder for date select event callback
*
* @private
* @type {TagEventCallback<Date>}
* @memberof CalendarTag
*/
private _ondateselect: TagEventCallback<Date>; private _ondateselect: TagEventCallback<Date>;
/** /**
@ -35,7 +67,7 @@ namespace OS {
} }
/** /**
* * Init the tag before mounting
* *
* @protected * @protected
* @memberof CalendarTag * @memberof CalendarTag
@ -46,17 +78,16 @@ namespace OS {
} }
/** /**
* * Update the current tag, doing nothing in this tag
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d] any data object
* @memberof CalendarTag * @memberof CalendarTag
*/ */
protected reload(d?: any): void { protected reload(d?: any): void {}
}
/** /**
* * Get the current selected date in the widget
* *
* @readonly * @readonly
* @type {Date} * @type {Date}
@ -67,7 +98,7 @@ namespace OS {
} }
/** /**
* * Set the date select event callback handle for the widget
* *
* @memberof CalendarTag * @memberof CalendarTag
*/ */
@ -76,7 +107,7 @@ namespace OS {
} }
/** /**
* * Mount the current widget to the DOM tree
* *
* @protected * @protected
* @memberof CalendarTag * @memberof CalendarTag
@ -104,14 +135,16 @@ namespace OS {
} }
/** /**
* * This function triggers the date select event
* *
* @private * @private
* @param {TagEventType} e * @param {TagEventType} e AFX tag event data [[TagEventType]]
* @returns {void} * @returns {void}
* @memberof CalendarTag * @memberof CalendarTag
*/ */
private dateselect(e: TagEventType<TagEventDataType<tag.GridCellPrototype>>): void { private dateselect(
e: TagEventType<TagEventDataType<tag.GridCellPrototype>>
): void {
if (!e.data.item) { if (!e.data.item) {
return; return;
} }
@ -121,7 +154,11 @@ namespace OS {
} }
const evt = { const evt = {
id: this.aid, id: this.aid,
data: new Date(this._year, this._month, parseInt(value)), data: new Date(
this._year,
this._month,
parseInt(value)
),
}; };
this._ondateselect(evt); this._ondateselect(evt);
this._selectedDate = evt.data; this._selectedDate = evt.data;
@ -129,7 +166,7 @@ namespace OS {
} }
/** /**
* * Calibrate the layout of the tag
* *
* @protected * @protected
* @memberof CalendarTag * @memberof CalendarTag
@ -142,7 +179,7 @@ namespace OS {
} }
/** /**
* * Display the previous month of the current month
* *
* @private * @private
* @memberof CalendarTag * @memberof CalendarTag
@ -157,9 +194,8 @@ namespace OS {
this.calendar(new Date(this._year, this._month, 1)); this.calendar(new Date(this._year, this._month, 1));
} }
/** /**
* * Display the next month of the current month
* *
* @private * @private
* @returns * @returns
@ -176,7 +212,7 @@ namespace OS {
} }
/** /**
* * Visualize the calendar base on input date
* *
* @private * @private
* @param {Date} date * @param {Date} date
@ -265,11 +301,13 @@ namespace OS {
rows.push(row); rows.push(row);
const grid = this.refs.grid as GridViewTag; const grid = this.refs.grid as GridViewTag;
grid.rows = rows; grid.rows = rows;
(this.refs.mlbl as LabelTag).text = `${months[this._month]} ${this._year}`; (this.refs.mlbl as LabelTag).text = `${
months[this._month]
} ${this._year}`;
} }
/** /**
* * Layout definition of the widget
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -1,38 +1,89 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
/** /**
* * Color type used by AFX API
* *
* @export * @export
* @interface ColorType * @interface ColorType
*/ */
export interface ColorType { export interface ColorType {
/**
* Red chanel
*
* @type {number}
* @memberof ColorType
*/
r: number; r: number;
/**
* Green chanel
*
* @type {number}
* @memberof ColorType
*/
g: number; g: number;
/**
* Blue chanel
*
* @type {number}
* @memberof ColorType
*/
b: number; b: number;
/**
* Alpha chanel
*
* @type {number}
* @memberof ColorType
*/
a?: number; a?: number;
/**
* color text in CSS format
*
* @type {string}
* @memberof ColorType
*/
text?: string; text?: string;
/**
* Color in hex format
*
* @type {string}
* @memberof ColorType
*/
hex?: string; hex?: string;
} }
export namespace tag { export namespace tag {
/** /**
* * Class definition of Color picker widget
* *
* @export * @export
* @class ColorPickerTag * @class ColorPickerTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class ColorPickerTag extends AFXTag { export class ColorPickerTag extends AFXTag {
/**
* The current selected color object
*
* @private
* @type {ColorType}
* @memberof ColorPickerTag
*/
private _selectedColor: ColorType; private _selectedColor: ColorType;
/**
* Holder for the color select event callback
*
* @private
* @type {TagEventCallback<ColorType>}
* @memberof ColorPickerTag
*/
private _oncolorselect: TagEventCallback<ColorType>; private _oncolorselect: TagEventCallback<ColorType>;
/** /**
*Creates an instance of ColorPickerTag. * Creates an instance of ColorPickerTag.
* @memberof ColorPickerTag * @memberof ColorPickerTag
*/ */
constructor() { constructor() {
@ -41,7 +92,7 @@ namespace OS {
} }
/** /**
* * Init tag before mounting, do nothing
* *
* @protected * @protected
* @memberof ColorPickerTag * @memberof ColorPickerTag
@ -49,7 +100,7 @@ namespace OS {
protected init(): void {} protected init(): void {}
/** /**
* * Reload tag, do nothing
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d]
@ -58,7 +109,7 @@ namespace OS {
protected reload(d?: any): void {} protected reload(d?: any): void {}
/** /**
* * Get selected color value
* *
* @readonly * @readonly
* @type {ColorType} * @type {ColorType}
@ -69,7 +120,7 @@ namespace OS {
} }
/** /**
* * Set the color select event handle
* *
* @memberof ColorPickerTag * @memberof ColorPickerTag
*/ */
@ -78,7 +129,7 @@ namespace OS {
} }
/** /**
* * Mount the widget to DOM tree
* *
* @protected * @protected
* @memberof ColorPickerTag * @memberof ColorPickerTag
@ -112,7 +163,7 @@ namespace OS {
} }
/** /**
* * Build the color palette
* *
* @private * @private
* @memberof ColorPickerTag * @memberof ColorPickerTag
@ -237,7 +288,7 @@ namespace OS {
} }
/** /**
* * layout definition of the widget
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -1,25 +1,74 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/** /**
* * Definition of system file view widget
* *
* @export * @export
* @class FileViewTag * @class FileViewTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class FileViewTag extends AFXTag { export class FileViewTag extends AFXTag {
/**
* Holder for file select event callback
*
* @private
* @type {TagEventCallback<API.FileInfoType>}
* @memberof FileViewTag
*/
private _onfileselect: TagEventCallback<API.FileInfoType>; private _onfileselect: TagEventCallback<API.FileInfoType>;
/**
* Holder for file open event callback
*
* @private
* @type {TagEventCallback<API.FileInfoType>}
* @memberof FileViewTag
*/
private _onfileopen: TagEventCallback<API.FileInfoType>; private _onfileopen: TagEventCallback<API.FileInfoType>;
/**
* Reference to the currently selected file meta-data
*
* @private
* @type {API.FileInfoType}
* @memberof FileViewTag
*/
private _selectedFile: API.FileInfoType; private _selectedFile: API.FileInfoType;
/**
* Data holder of the current working directory
*
* @private
* @type {API.FileInfoType[]}
* @memberof FileViewTag
*/
private _data: API.FileInfoType[]; private _data: API.FileInfoType[];
/**
* The path of the current working directory
*
* @private
* @type {string}
* @memberof FileViewTag
*/
private _path: string; private _path: string;
/**
* Header definition of the widget grid view
*
* @private
* @type {(GenericObject<string | number>[])}
* @memberof FileViewTag
*/
private _header: GenericObject<string | number>[]; private _header: GenericObject<string | number>[];
/**
* Holder for the user-specified meta-data fetch function
*
* @private
* @memberof FileViewTag
*/
private _fetch: (p: string) => Promise<API.FileInfoType[]>; private _fetch: (p: string) => Promise<API.FileInfoType[]>;
/** /**
@ -31,7 +80,7 @@ namespace OS {
} }
/** /**
* * Init the widget before mounting
* *
* @protected * @protected
* @memberof FileViewTag * @memberof FileViewTag
@ -51,15 +100,18 @@ namespace OS {
} }
/** /**
* * Update the current widget, do nothing
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d]
* @memberof FileViewTag * @memberof FileViewTag
*/ */
protected reload(d?: any): void {} protected reload(d?: any): void {}
/** /**
* * set the function that allows to fetch file entries.
* This handle function should return a promise on
* an arry of [[API.FileInfoType]]
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -68,7 +120,9 @@ namespace OS {
} }
/** /**
* * set the callback handle for the file select event.
* The parameter of the callback should be an object
* of type [[TagEventType]]<T> with the data type `T` is [[API.FileInfoType]]
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -77,7 +131,9 @@ namespace OS {
} }
/** /**
* set the callback handle for the file open event.
* The parameter of the callback should be an object
* of type [[TagEventType]]<T> with the data type `T` is [[API.FileInfoType]]
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -86,7 +142,10 @@ namespace OS {
} }
/** /**
* * chang the view of the widget, there are three different views
* - `icon`
* - `list`
* - `tree`
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -96,7 +155,7 @@ namespace OS {
} }
/** /**
* * Get the current view setting of the widget
* *
* @type {string} * @type {string}
* @memberof FileViewTag * @memberof FileViewTag
@ -106,7 +165,10 @@ namespace OS {
} }
/** /**
* * Turn on/off the changing current working directory feature
* of the widget when a directory is double clicked. If enabled,
* the widget will use the configured [[fetch]] function to query
* the content of the selected directory
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -115,7 +177,8 @@ namespace OS {
} }
/** /**
* * check whether changing current working directory feature
* is enabled
* *
* @type {boolean} * @type {boolean}
* @memberof FileViewTag * @memberof FileViewTag
@ -125,7 +188,7 @@ namespace OS {
} }
/** /**
* * Enable or disable the status bar of the widget
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -139,7 +202,7 @@ namespace OS {
} }
/** /**
* * Check whether the status bar is enabled
* *
* @type {boolean} * @type {boolean}
* @memberof FileViewTag * @memberof FileViewTag
@ -149,7 +212,7 @@ namespace OS {
} }
/** /**
* * Allow the widget to show or hide hidden file
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -162,7 +225,8 @@ namespace OS {
} }
/** /**
* * Check whether the hidden file should be shown in
* the widget
* *
* @type {boolean} * @type {boolean}
* @memberof FileViewTag * @memberof FileViewTag
@ -172,7 +236,7 @@ namespace OS {
} }
/** /**
* * Get the current selected file
* *
* @readonly * @readonly
* @type {API.FileInfoType} * @type {API.FileInfoType}
@ -183,7 +247,10 @@ namespace OS {
} }
/** /**
* * Set the path of the current working directory.
* When called the widget will refresh the current
* working directory using the configured [[fetch]]
* function
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -211,7 +278,7 @@ namespace OS {
} }
/** /**
* * Get the path of the current working directory
* *
* @type {string} * @type {string}
* @memberof FileViewTag * @memberof FileViewTag
@ -221,7 +288,7 @@ namespace OS {
} }
/** /**
* * Set the data of the current working directory
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -234,7 +301,7 @@ namespace OS {
} }
/** /**
* * Get the data of the current working directory
* *
* @type {API.FileInfoType[]} * @type {API.FileInfoType[]}
* @memberof FileViewTag * @memberof FileViewTag
@ -244,21 +311,26 @@ namespace OS {
} }
/** /**
* * Set the file drag and drop event handle. This allows application
* to define custom behavior of the event
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
set ondragndrop(v: TagEventCallback<DnDEventDataType<TreeViewTag| ListViewItemTag>>) { set ondragndrop(
v: TagEventCallback<
DnDEventDataType<TreeViewTag | ListViewItemTag>
>
) {
(this.refs.treeview as TreeViewTag).ondragndrop = v; (this.refs.treeview as TreeViewTag).ondragndrop = v;
(this.refs.listview as ListViewTag).ondragndrop = v; (this.refs.listview as ListViewTag).ondragndrop = v;
} }
/** /**
* * sort file by it type
* *
* @private * @private
* @param {API.FileInfoType} a * @param {API.FileInfoType} a first file meta-data
* @param {API.FileInfoType} b * @param {API.FileInfoType} b second file meta-data
* @returns {(0|-1|1)} * @returns {(0|-1|1)}
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -276,7 +348,7 @@ namespace OS {
} }
/** /**
* * calibrate the widget layout
* *
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -295,7 +367,8 @@ namespace OS {
} }
/** /**
* * Refresh the list view of the widget. This function
* is called when the view of the widget changed to `icon`
* *
* @private * @private
* @memberof FileViewTag * @memberof FileViewTag
@ -318,7 +391,8 @@ namespace OS {
} }
/** /**
* * Refresh the grid view of the widget, this function is called
* when the view of the widget set to `list`
* *
* @private * @private
* @memberof FileViewTag * @memberof FileViewTag
@ -348,7 +422,8 @@ namespace OS {
} }
/** /**
* * Refresh the Treeview of the widget, this function is called
* when the view of the widget set to `tree`
* *
* @private * @private
* @memberof FileViewTag * @memberof FileViewTag
@ -359,17 +434,18 @@ namespace OS {
text: this.path, text: this.path,
path: this.path, path: this.path,
open: true, open: true,
nodes: this.getTreeData(this.data) nodes: this.getTreeData(this.data),
}; };
(this.refs.treeview as TreeViewTag).data = tdata; (this.refs.treeview as TreeViewTag).data = tdata;
// (this.refs.treeview as TreeViewTag).expandAll(); // (this.refs.treeview as TreeViewTag).expandAll();
} }
/** /**
* * Create the tree data from the list of input
* file meta-data
* *
* @private * @private
* @param {API.FileInfoType[]} data * @param {API.FileInfoType[]} data list of file meta-data
* @returns {TreeViewDataType[]} * @returns {TreeViewDataType[]}
* @memberof FileViewTag * @memberof FileViewTag
*/ */
@ -395,7 +471,7 @@ namespace OS {
} }
/** /**
* * Refresh data of the current widget view
* *
* @private * @private
* @returns {void} * @returns {void}
@ -417,7 +493,7 @@ namespace OS {
} }
/** /**
* * Switch between three view options
* *
* @private * @private
* @memberof FileViewTag * @memberof FileViewTag
@ -445,10 +521,10 @@ namespace OS {
} }
/** /**
* * This function triggers the file select event
* *
* @private * @private
* @param {API.FileInfoType} e * @param {API.FileInfoType} e selected file meta-data
* @memberof FileViewTag * @memberof FileViewTag
*/ */
private fileselect(e: API.FileInfoType): void { private fileselect(e: API.FileInfoType): void {
@ -470,10 +546,10 @@ namespace OS {
} }
/** /**
* * This function triggers the file open event
* *
* @private * @private
* @param {API.FileInfoType} e * @param {API.FileInfoType} e selected file meta-data
* @memberof FileViewTag * @memberof FileViewTag
*/ */
private filedbclick(e: API.FileInfoType): void { private filedbclick(e: API.FileInfoType): void {
@ -491,7 +567,7 @@ namespace OS {
} }
/** /**
* * Mount the widget in the DOM tree
* *
* @protected * @protected
* @memberof FileViewTag * @memberof FileViewTag
@ -529,27 +605,28 @@ namespace OS {
}; };
grid.onrowselect = (e) => { grid.onrowselect = (e) => {
this.fileselect( this.fileselect(
$(e.data.item).children()[0].data as API.FileInfoType $(e.data.item).children()[0]
.data as API.FileInfoType
); );
}; };
tree.ontreeselect = (e) => { tree.ontreeselect = (e) => {
this.fileselect(e.data.item.data as API.FileInfoType); this.fileselect(e.data.item.data as API.FileInfoType);
}; };
// dblclick // dblclick
list.onlistdbclick = (e) => { list.onlistdbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType); this.filedbclick(e.data.item.data as API.FileInfoType);
}; };
grid.oncelldbclick = (e) => { grid.oncelldbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType); this.filedbclick(e.data.item.data as API.FileInfoType);
}; };
tree.ontreedbclick = (e) => { tree.ontreedbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType); this.filedbclick(e.data.item.data as API.FileInfoType);
}; };
this.switchView(); this.switchView();
} }
/** /**
* * Layout definition of the widget
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -1,21 +1,32 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/** /**
* * A float list is a list of items in which each
* item can be moved (drag and drop) freely
* *
* @export * @export
* @class FloatListTag * @class FloatListTag
* @extends {ListViewTag} * @extends {ListViewTag}
*/ */
export class FloatListTag extends ListViewTag { export class FloatListTag extends ListViewTag {
protected reload(d?: any): void { /**
} * Update the current tag, do nothing
*
* @protected
* @param {*} [d]
* @memberof FloatListTag
*/
protected reload(d?: any): void {}
/**
* Variable that hold the onready callback of
* the tag. This callback will be called after
* the tag is mounted
*
* @private
* @memberof FloatListTag
*/
private _onready: (e: FloatListTag) => void; private _onready: (e: FloatListTag) => void;
/** /**
@ -27,7 +38,9 @@ namespace OS {
} }
/** /**
* * set the onready callback function to the tag.
* This callback will be called after
* the tag is mounted
* *
* @memberof FloatListTag * @memberof FloatListTag
*/ */
@ -36,7 +49,12 @@ namespace OS {
} }
/** /**
* Set the direction of the list item layout.
* Two directions are available:
* - `vertical`
* - `horizontal`
* *
* This setter acts as a DOM attribute
* *
* @memberof FloatListTag * @memberof FloatListTag
*/ */
@ -46,7 +64,8 @@ namespace OS {
} }
/** /**
* * Get the currently set direction of list
* item layout
* *
* @type {string} * @type {string}
* @memberof FloatListTag * @memberof FloatListTag
@ -54,24 +73,24 @@ namespace OS {
get dir(): string { get dir(): string {
return $(this).attr("dir"); return $(this).attr("dir");
} }
// disable some uneccessary functions
/** /**
* * Disable the dropdown option in this list
* *
* @memberof FloatListTag * @memberof FloatListTag
*/ */
set dropdown(v: boolean) {} set dropdown(v: boolean) {}
/** /**
* * Disable the list buttons configuration in this
* list
* *
* @memberof FloatListTag * @memberof FloatListTag
*/ */
set buttons(v: GenericObject<any>[]) {} set buttons(v: GenericObject<any>[]) {}
/** /**
* * Disable the `showlist` behavior in this list
* *
* @protected * @protected
* @param {*} e * @param {*} e
@ -80,7 +99,7 @@ namespace OS {
protected showlist(e: any) {} protected showlist(e: any) {}
/** /**
* * Disable the `dropoff` behavior in this list
* *
* @protected * @protected
* @param {*} e * @param {*} e
@ -89,7 +108,8 @@ namespace OS {
protected dropoff(e: any) {} protected dropoff(e: any) {}
/** /**
* * Function called when the data of the list
* is changed
* *
* @protected * @protected
* @memberof FloatListTag * @memberof FloatListTag
@ -99,7 +119,7 @@ namespace OS {
} }
/** /**
* * Mount the list to the DOM tree
* *
* @protected * @protected
* @returns {void} * @returns {void}
@ -120,9 +140,9 @@ namespace OS {
} }
/** /**
* Push an element to the list
* *
* * @param {GenericObject<any>} v an element data
* @param {GenericObject<any>} v
* @returns * @returns
* @memberof FloatListTag * @memberof FloatListTag
*/ */
@ -133,10 +153,10 @@ namespace OS {
} }
/** /**
* * Enable drag and drop on the list
* *
* @private * @private
* @param {ListViewItemTag} el * @param {ListViewItemTag} el the list item DOM element
* @memberof FloatListTag * @memberof FloatListTag
*/ */
private enable_drag(el: ListViewItemTag): void { private enable_drag(el: ListViewItemTag): void {
@ -174,7 +194,7 @@ namespace OS {
} }
/** /**
* * Calibrate the view of the list
* *
* @memberof FloatListTag * @memberof FloatListTag
*/ */

View File

@ -1,24 +1,39 @@
/* /**
* decaffeinate suggestions: * Extend the Array interface with some
* DS101: Remove unnecessary use of Array.from * property needed by AFX API
* DS102: Remove unnecessary code created because of implicit returns *
* DS205: Consider reworking code to avoid use of IIFEs * @interface Array
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md * @template T
*/ */
interface Array<T> { interface Array<T> {
domel: GenericObject<any>; /**
* Reference to a DOM element created by AFX API,
* this property is used by some AFX tags to refer
* to its child element in it data object
*
* @type {GenericObject<any>}
* @memberof Array
*/
domel?: GenericObject<any>;
} }
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/** /**
* * A grid Row is a simple element that
* contains a group of grid cell
* *
* @export * @export
* @class GridRowTag * @class GridRowTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class GridRowTag extends AFXTag { export class GridRowTag extends AFXTag {
/**
* Data holder for a collection of cell data
*
* @type {GenericObject<any>[]}
* @memberof GridRowTag
*/
data: GenericObject<any>[]; data: GenericObject<any>[];
/** /**
@ -32,7 +47,7 @@ namespace OS {
} }
/** /**
* * Mount the tag, do nothing
* *
* @protected * @protected
* @memberof GridRowTag * @memberof GridRowTag
@ -40,7 +55,7 @@ namespace OS {
protected mount(): void {} protected mount(): void {}
/** /**
* * Init the tag before mounting: reset the data holder
* *
* @protected * @protected
* @memberof GridRowTag * @memberof GridRowTag
@ -50,7 +65,7 @@ namespace OS {
} }
/** /**
* * Empty layout
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}
@ -61,7 +76,7 @@ namespace OS {
} }
/** /**
* * This function does nothing in this tag
* *
* @protected * @protected
* @memberof GridRowTag * @memberof GridRowTag
@ -69,7 +84,7 @@ namespace OS {
protected calibrate(): void {} protected calibrate(): void {}
/** /**
* * This function does nothing in this tag
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d]
@ -78,10 +93,15 @@ namespace OS {
protected reload(d?: any): void {} protected reload(d?: any): void {}
} }
/**
* Event data used by grid cell
*/
export type CellEventData = TagEventDataType<GridCellPrototype>; export type CellEventData = TagEventDataType<GridCellPrototype>;
/** /**
* * Prototype of any grid cell, custom grid cell
* definition should extend and implement this
* abstract prototype
* *
* @export * @export
* @abstract * @abstract
@ -89,8 +109,31 @@ namespace OS {
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export abstract class GridCellPrototype extends AFXTag { export abstract class GridCellPrototype extends AFXTag {
/**
* Holder for cell selected event callback
*
* @private
* @type {TagEventCallback<CellEventData>}
* @memberof GridCellPrototype
*/
private _oncellselect: TagEventCallback<CellEventData>; private _oncellselect: TagEventCallback<CellEventData>;
/**
* Holder for cell double click event callback
*
* @private
* @type {TagEventCallback<CellEventData>}
* @memberof GridCellPrototype
*/
private _oncelldbclick: TagEventCallback<CellEventData>; private _oncelldbclick: TagEventCallback<CellEventData>;
/**
* Data holder of the current cell
*
* @private
* @type {GenericObject<any>}
* @memberof GridCellPrototype
*/
private _data: GenericObject<any>; private _data: GenericObject<any>;
/** /**
@ -102,7 +145,7 @@ namespace OS {
} }
/** /**
* * Set the cell selected event callback
* *
* @memberof GridCellPrototype * @memberof GridCellPrototype
*/ */
@ -111,7 +154,7 @@ namespace OS {
} }
/** /**
* * Set the cell double click event callback
* *
* @memberof GridCellPrototype * @memberof GridCellPrototype
*/ */
@ -120,7 +163,8 @@ namespace OS {
} }
/** /**
* * Set the data of the cell, this will trigger
* the [[ondatachange]] function
* *
* @memberof GridCellPrototype * @memberof GridCellPrototype
*/ */
@ -135,7 +179,7 @@ namespace OS {
} }
/** /**
* * Get the current cell data holder
* *
* @type {GenericObject<any>} * @type {GenericObject<any>}
* @memberof GridCellPrototype * @memberof GridCellPrototype
@ -145,7 +189,9 @@ namespace OS {
} }
/** /**
* * Set/unset the current cell as selected.
* This will trigger the [[cellselect]]
* event
* *
* @memberof GridCellPrototype * @memberof GridCellPrototype
*/ */
@ -159,7 +205,7 @@ namespace OS {
} }
/** /**
* * Check whether the current cell is selected
* *
* @type {boolean} * @type {boolean}
* @memberof GridCellPrototype * @memberof GridCellPrototype
@ -169,7 +215,8 @@ namespace OS {
} }
/** /**
* * Update the current cell. This will
* reset the cell data
* *
* @protected * @protected
* @param {*} d * @param {*} d
@ -180,7 +227,7 @@ namespace OS {
} }
/** /**
* * Mount the current cell to the grid
* *
* @protected * @protected
* @memberof GridCellPrototype * @memberof GridCellPrototype
@ -203,7 +250,8 @@ namespace OS {
} }
/** /**
* * This function triggers the cell select
* event
* *
* @private * @private
* @param {TagEventType<GridCellPrototype>} e * @param {TagEventType<GridCellPrototype>} e
@ -223,7 +271,8 @@ namespace OS {
} }
/** /**
* * Abstract function called when the cell data changed.
* This should be implemented by subclasses
* *
* @protected * @protected
* @abstract * @abstract
@ -233,7 +282,8 @@ namespace OS {
} }
/** /**
* * Simple grid cell defines a grid cell with
* an [[LabelTag]] as it cell layout
* *
* @export * @export
* @class SimpleGridCellTag * @class SimpleGridCellTag
@ -249,7 +299,7 @@ namespace OS {
} }
/** /**
* * Reset the label of the cell with its data
* *
* @protected * @protected
* @memberof SimpleGridCellTag * @memberof SimpleGridCellTag
@ -259,7 +309,7 @@ namespace OS {
} }
/** /**
* * This function do nothing in this tag
* *
* @protected * @protected
* @memberof SimpleGridCellTag * @memberof SimpleGridCellTag
@ -267,7 +317,7 @@ namespace OS {
protected init(): void {} protected init(): void {}
/** /**
* * This function do nothing in this tag
* *
* @protected * @protected
* @memberof SimpleGridCellTag * @memberof SimpleGridCellTag
@ -275,7 +325,7 @@ namespace OS {
protected calibrate(): void {} protected calibrate(): void {}
/** /**
* * The layout of the cell with a simple [[LabelTag]]
* *
* @returns * @returns
* @memberof SimpleGridCellTag * @memberof SimpleGridCellTag
@ -291,24 +341,89 @@ namespace OS {
} }
/** /**
* * A Grid contains a header and a collection grid rows
* which has the same number of cells as the number of
* the header elements
* *
* @export * @export
* @class GridViewTag * @class GridViewTag
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class GridViewTag extends AFXTag { export class GridViewTag extends AFXTag {
/**
* Grid header definition
*
* @private
* @type {GenericObject<any>[]}
* @memberof GridViewTag
*/
private _header: GenericObject<any>[]; private _header: GenericObject<any>[];
/**
* Grid rows data holder
*
* @private
* @type {GenericObject<any>[][]}
* @memberof GridViewTag
*/
private _rows: GenericObject<any>[][]; private _rows: GenericObject<any>[][];
/**
* Reference to the current selected row DOM element
*
* @private
* @type {GridRowTag}
* @memberof GridViewTag
*/
private _selectedRow: GridRowTag; private _selectedRow: GridRowTag;
/**
* A collection of selected grid rows DOM element
*
* @private
* @type {GridRowTag[]}
* @memberof GridViewTag
*/
private _selectedRows: GridRowTag[]; private _selectedRows: GridRowTag[];
/**
* Reference to the current selected cell
*
* @private
* @type {GridCellPrototype}
* @memberof GridViewTag
*/
private _selectedCell: GridCellPrototype; private _selectedCell: GridCellPrototype;
/**
* Cell select event callback holder
*
* @private
* @type {TagEventCallback<CellEventData>}
* @memberof GridViewTag
*/
private _oncellselect: TagEventCallback<CellEventData>; private _oncellselect: TagEventCallback<CellEventData>;
/**
* Row select event callback holder
*
* @private
* @type {TagEventCallback<CellEventData>}
* @memberof GridViewTag
*/
private _onrowselect: TagEventCallback<CellEventData>; private _onrowselect: TagEventCallback<CellEventData>;
/**
* Cell double click event callback holder
*
* @private
* @type {TagEventCallback<CellEventData>}
* @memberof GridViewTag
*/
private _oncelldbclick: TagEventCallback<CellEventData>; private _oncelldbclick: TagEventCallback<CellEventData>;
/** /**
*Creates an instance of GridViewTag. * Creates an instance of GridViewTag.
* @memberof GridViewTag * @memberof GridViewTag
*/ */
constructor() { constructor() {
@ -316,7 +431,8 @@ namespace OS {
} }
/** /**
* * Init the grid view before mounting.
* Reset all the holders to default values
* *
* @protected * @protected
* @memberof GridViewTag * @memberof GridViewTag
@ -335,7 +451,7 @@ namespace OS {
} }
/** /**
* * This function does nothing
* *
* @protected * @protected
* @param {*} [d] * @param {*} [d]
@ -344,7 +460,7 @@ namespace OS {
protected reload(d?: any): void {} protected reload(d?: any): void {}
/** /**
* * set the cell select event callback
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -353,7 +469,7 @@ namespace OS {
} }
/** /**
* * set the row select event callback
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -362,7 +478,7 @@ namespace OS {
} }
/** /**
* * set the cell double click event callback
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -371,7 +487,7 @@ namespace OS {
} }
/** /**
* * set the tag name of the header cells
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -380,7 +496,7 @@ namespace OS {
} }
/** /**
* * get the grid header tag name
* *
* @type {string} * @type {string}
* @memberof GridViewTag * @memberof GridViewTag
@ -390,7 +506,7 @@ namespace OS {
} }
/** /**
* * set the tag name of the grid cell
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -399,7 +515,7 @@ namespace OS {
} }
/** /**
* * get the tag name of the grid cell
* *
* @type {string} * @type {string}
* @memberof GridViewTag * @memberof GridViewTag
@ -409,7 +525,7 @@ namespace OS {
} }
/** /**
* * get the header data holder
* *
* @type {GenericObject<any>[]} * @type {GenericObject<any>[]}
* @memberof GridViewTag * @memberof GridViewTag
@ -419,7 +535,7 @@ namespace OS {
} }
/** /**
* * the set the header data
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -443,7 +559,7 @@ namespace OS {
} }
/** /**
* * Get all the selected rows
* *
* @readonly * @readonly
* @type {GridRowTag[]} * @type {GridRowTag[]}
@ -454,7 +570,7 @@ namespace OS {
} }
/** /**
* * Get the latest selected row
* *
* @readonly * @readonly
* @type {GridRowTag} * @type {GridRowTag}
@ -465,7 +581,7 @@ namespace OS {
} }
/** /**
* * Get the current selected cell
* *
* @readonly * @readonly
* @type {GridCellPrototype} * @type {GridCellPrototype}
@ -476,7 +592,7 @@ namespace OS {
} }
/** /**
* * set the rows data
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -487,7 +603,7 @@ namespace OS {
} }
/** /**
* * get the rows data
* *
* @type {GenericObject<any>[][]} * @type {GenericObject<any>[][]}
* @memberof GridViewTag * @memberof GridViewTag
@ -497,7 +613,7 @@ namespace OS {
} }
/** /**
* * activate deactivate multi-select
* *
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -506,8 +622,7 @@ namespace OS {
} }
/** /**
* * check whether the `multiselect` option is activated
*
* @type {boolean} * @type {boolean}
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -516,9 +631,9 @@ namespace OS {
} }
/** /**
* Delete a grid rows
* *
* * @param {GridRowTag} row row DOM element
* @param {GridRowTag} row
* @returns {void} * @returns {void}
* @memberof GridViewTag * @memberof GridViewTag
*/ */
@ -546,11 +661,12 @@ namespace OS {
} }
/** /**
* Push a row to the grid
* *
* * @param {GenericObject<any>[]} row list of cell data
* @param {GenericObject<any>[]} row * @param {boolean} flag indicates where the row is add to beginning or end
* @param {boolean} flag * of the row
* @memberof GridViewTag * @memberof GridViewTags
*/ */
push(row: GenericObject<any>[], flag: boolean): void { push(row: GenericObject<any>[], flag: boolean): void {
const rowel = $("<afx-grid-row>").css( const rowel = $("<afx-grid-row>").css(
@ -590,9 +706,9 @@ namespace OS {
} }
/** /**
* Unshift a row to the grid
* *
* * @param {GenericObject<any>[]} row list of cell data in the row
* @param {GenericObject<any>[]} row
* @memberof GridViewTag * @memberof GridViewTag
*/ */
unshift(row: GenericObject<any>[]): void { unshift(row: GenericObject<any>[]): void {
@ -600,14 +716,15 @@ namespace OS {
} }
/** /**
* This function triggers the cell select event
* *
* * @private
* @param {TagEventType<CellEventData>} e * @param {TagEventType<CellEventData>} e event contains cell event data
* @param {boolean} flag * @param {boolean} flag indicates whether the event is double clicked
* @returns {void} * @returns {void}
* @memberof GridViewTag * @memberof GridViewTag
*/ */
cellselect( private cellselect(
e: TagEventType<CellEventData>, e: TagEventType<CellEventData>,
flag: boolean flag: boolean
): void { ): void {
@ -629,13 +746,14 @@ namespace OS {
} }
/** /**
* * This function triggers the row selected event, a cell select
* event will also trigger this event
* *
* @param {TagEventType<CellEventData>} e * @param {TagEventType<CellEventData>} e
* @returns {void} * @returns {void}
* @memberof GridViewTag * @memberof GridViewTag
*/ */
rowselect(e: TagEventType<CellEventData>): void { private rowselect(e: TagEventType<CellEventData>): void {
if (!e.data.item) { if (!e.data.item) {
return; return;
} }
@ -680,7 +798,7 @@ namespace OS {
} }
/** /**
* * Check whether the grid has header
* *
* @private * @private
* @returns {boolean} * @returns {boolean}
@ -692,7 +810,7 @@ namespace OS {
} }
/** /**
* * Calibrate the grid
* *
* @protected * @protected
* @memberof GridViewTag * @memberof GridViewTag
@ -715,7 +833,9 @@ namespace OS {
} }
/** /**
* * Recalculate the size of each header cell, changing
* in header cell size will also resize the entire
* related column
* *
* @private * @private
* @returns {void} * @returns {void}
@ -756,7 +876,7 @@ namespace OS {
} }
/** /**
* * Mount the grid view tag
* *
* @protected * @protected
* @returns {void} * @returns {void}
@ -776,7 +896,7 @@ namespace OS {
} }
/** /**
* * Layout definition of the grid view
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -7,7 +7,7 @@ namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
export class LabelTag extends AFXTag { export class LabelTag extends AFXTag {
private _text: string | FormatedString; private _text: string | FormattedString;
constructor() { constructor() {
super(); super();
} }
@ -53,7 +53,7 @@ namespace OS {
} }
} }
set text(v: string | FormatedString) { set text(v: string | FormattedString) {
this._text = v; this._text = v;
if (v && v !== "") { if (v && v !== "") {
$(this.refs.text).show(); $(this.refs.text).show();
@ -63,7 +63,7 @@ namespace OS {
} }
} }
get text(): string| FormatedString { get text(): string| FormattedString {
return this._text; return this._text;
} }

View File

@ -1,16 +1,16 @@
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
export namespace tag { export namespace tag {
/**
* List item event data type
*/
export type ListItemEventData = TagEventDataType<ListViewItemTag> export type ListItemEventData = TagEventDataType<ListViewItemTag>
/** /**
* * A list item represent the individual view of an item in the [[ListView]].
* This class is an abstract prototype class, implementation of any
* list view item should extend it
*
* *
* @export * @export
* @abstract * @abstract
@ -18,11 +18,59 @@ namespace OS {
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export abstract class ListViewItemTag extends AFXTag { export abstract class ListViewItemTag extends AFXTag {
/**
* Data holder for the list item
*
* @private
* @type {GenericObject<any>}
* @memberof ListViewItemTag
*/
private _data: GenericObject<any>; private _data: GenericObject<any>;
/**
* Holder for the item select event callback
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onselect: TagEventCallback<ListItemEventData>; private _onselect: TagEventCallback<ListItemEventData>;
/**
* Context menu event callback handle
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onctxmenu: TagEventCallback<ListItemEventData>; private _onctxmenu: TagEventCallback<ListItemEventData>;
/**
* Click event callback holder
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onclick: TagEventCallback<ListItemEventData>; private _onclick: TagEventCallback<ListItemEventData>;
/**
* Double click event callback handle
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _ondbclick: TagEventCallback<ListItemEventData>; private _ondbclick: TagEventCallback<ListItemEventData>;
/**
* Item close event callback holder
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onclose: TagEventCallback<ListItemEventData>; private _onclose: TagEventCallback<ListItemEventData>;
/** /**

View File

@ -15,7 +15,7 @@ namespace OS {
* @extends {AFXTag} * @extends {AFXTag}
*/ */
export class SystemPanelTag extends AFXTag { export class SystemPanelTag extends AFXTag {
private _osmenu: GenericObject<string | FormatedString>; private _osmenu: GenericObject<string | FormattedString>;
private _view: boolean; private _view: boolean;
private _cb: (e: JQuery.MouseEventBase) => void; private _cb: (e: JQuery.MouseEventBase) => void;

View File

@ -81,13 +81,13 @@ namespace OS {
get resizable(): boolean { get resizable(): boolean {
return this.hasattr("resizable"); return this.hasattr("resizable");
} }
set apptitle(v: string| FormatedString) { set apptitle(v: string| FormattedString) {
$(this).attr("apptitle", v.__()); $(this).attr("apptitle", v.__());
if (v) { if (v) {
(this.refs["txtTitle"] as LabelTag).text = v; (this.refs["txtTitle"] as LabelTag).text = v;
} }
} }
get apptitle(): string| FormatedString { get apptitle(): string| FormattedString {
return $(this).attr("apptitle"); return $(this).attr("apptitle");
} }

View File

@ -1,20 +1,95 @@
/* /**
* decaffeinate suggestions: *
* DS101: Remove unnecessary use of Array.from * Extend the HTMLElement interface with some utility function need
* DS102: Remove unnecessary code created because of implicit returns * by AFX API
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md *
* @interface HTMLElement
*/ */
interface HTMLElement { interface HTMLElement {
/**
* Recursively update a tag and all its children
*
* @param {*} [d] data to send to all element in the DOM subtree
* @memberof HTMLElement
*/
update(d?: any): void; update(d?: any): void;
/**
*
* AFX will automatically bind the context menu on an HTMLElement
* if this function is defined on that element. The function should
* define the content of the context menu and its action
*
* Once the context menu is bound to the element, all context menu handle
* defined on any child of this element will be ignored.
*
* @param {JQuery.MouseEventBase} e a mouse event
* @param {OS.GUI.tag.MenuTag} m The context menu element [[MenuTag]]
* @memberof HTMLElement
*/
contextmenuHandle(e: JQuery.MouseEventBase, m: OS.GUI.tag.MenuTag): void; contextmenuHandle(e: JQuery.MouseEventBase, m: OS.GUI.tag.MenuTag): void;
/**
* Mount the element and all the children on its DOM subtree. This action
* is performed in a top-down manner
*
* @memberof HTMLElement
*/
sync(): void; sync(): void;
/**
*
* This action allows to generated all the DOM nodes defined by all AFX tags
* in its hierarchy.
* It performs two operations, one top-down operation to generate all the
* necessary DOM nodes, another bottom-up operation to init all the AFX tag
* in the current element DOM hierarchy
*
* @param {OS.API.Announcer} o an AntOS observable object
* @memberof HTMLElement
*/
afxml(o: OS.API.Announcer): void; afxml(o: OS.API.Announcer): void;
/**
* Perform DOM generation ([[afxml]]) then mount ([[sync]]) all the
* elements.
*
* @param {OS.API.Announcer} o an AntOS observable object
* @param {boolean} [flag] indicates whether this is the top-most call of the operation
* @memberof HTMLElement
*/
uify(o: OS.API.Announcer, flag?: boolean): void; uify(o: OS.API.Announcer, flag?: boolean): void;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
mozRequestFullScreen: any; mozRequestFullScreen: any;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
webkitRequestFullscreen: any; webkitRequestFullscreen: any;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
msRequestFullscreen: any; msRequestFullscreen: any;
} }
/**
*
*
* @interface Document
*/
interface Document { interface Document {
mozCancelFullScreen: any; mozCancelFullScreen: any;
webkitExitFullscreen: any; webkitExitFullscreen: any;
@ -22,37 +97,205 @@ interface Document {
} }
namespace OS { namespace OS {
export namespace GUI { export namespace GUI {
/**
* [[TagLayoutType]] interface using by AFX tags to defined
* its internal DOM hierarchy
*
* @export
* @interface TagLayoutType
*/
export interface TagLayoutType { export interface TagLayoutType {
/**
* Element tag name
*
* @type {string}
* @memberof TagLayoutType
*/
el: string; el: string;
/**
* Children layout of the current element
*
* @type {TagLayoutType[]}
* @memberof TagLayoutType
*/
children?: TagLayoutType[]; children?: TagLayoutType[];
/**
* Reference name of the element used by AFX Tag
*
* @type {string}
* @memberof TagLayoutType
*/
ref?: string; ref?: string;
/**
* CSS class of the element
*
* @type {string}
* @memberof TagLayoutType
*/
class?: string; class?: string;
/**
* this is the `data-id` attribute of the element,
* can be query by the [[aid]] Tag API function.
* Not to be confused with the DOM `id` attribute
*
* @type {(string | number)}
* @memberof TagLayoutType
*/
id?: string | number; id?: string | number;
tooltip?: string | FormatedString;
/**
* Tooltip text of the element
*
* @type {(string | FormattedString)}
* @memberof TagLayoutType
*/
tooltip?: string | FormattedString;
/**
* `data-width` of the element, not to be confused with
* the `width` attribute of the DOM element
*
* @type {number}
* @memberof TagLayoutType
*/
width?: number; width?: number;
/**
** `data-height` of the element, not to be confused with
* the `height` attribute of the DOM element
*
* @type {number}
* @memberof TagLayoutType
*/
height?: number; height?: number;
} }
/**
* Data type for event issued by AFX tags
*
* @export
* @interface TagEventDataType
* @template T item template
*/
export interface TagEventDataType<T> { export interface TagEventDataType<T> {
item?: T, /**
[propName:string]: any; * Reference to the item involved in the event
*
* @type {T}
* @memberof TagEventDataType
*/
item?: T;
[propName: string]: any;
} }
export interface TagEventType<T>{
/**
* Format of the event issued by AFX tags
*
* @export
* @interface TagEventType
* @template T data type
*/
export interface TagEventType<T> {
/**
* `data-id` of the tag that trigger the
* event
*
* @type {(number | string)}
* @memberof TagEventType
*/
id: number | string; id: number | string;
/**
* Data object of the event
*
* @type {T}
* @memberof TagEventType
*/
data: T; data: T;
} }
/**
* Drag and Drop data type sent between mouse events
*
* @export
* @interface DnDEventDataType
* @template T
*/
export interface DnDEventDataType<T> { export interface DnDEventDataType<T> {
/**
* Reference to the source DOM element
*
* @type {T}
* @memberof DnDEventDataType
*/
from: T; from: T;
/**
* Reference to the target DOM element
*
* @type {T}
* @memberof DnDEventDataType
*/
to: T; to: T;
} }
/**
* Tag event callback type
*/
export type TagEventCallback<T> = (e: TagEventType<T>) => void; export type TagEventCallback<T> = (e: TagEventType<T>) => void;
/**
* Top most element z index value, start by 10
*/
export var zindex: number = 10; export var zindex: number = 10;
/**
* Base abstract class for tag implementation, any AFX tag should be
* subclass of this class
*
* @export
* @abstract
* @class AFXTag
* @extends {HTMLElement}
*/
export abstract class AFXTag extends HTMLElement { export abstract class AFXTag extends HTMLElement {
/**
* The announcer object of the tag
*
* @type {API.Announcer}
* @memberof AFXTag
*/
observable: API.Announcer; observable: API.Announcer;
/**
* Reference to some of the tag's children
* element. This reference object is built
* based on the `ref` property found in the
* tag layout [[TagLayoutType]]
*
* @protected
* @type {GenericObject<HTMLElement>}
* @memberof AFXTag
*/
protected refs: GenericObject<HTMLElement>; protected refs: GenericObject<HTMLElement>;
/**
* boolean value indicated whether the tag
* is already mounted in the DOM tree
*
* @protected
* @type {boolean}
* @memberof AFXTag
*/
protected _mounted: boolean; protected _mounted: boolean;
/**
*Creates an instance of AFXTag.
* @memberof AFXTag
*/
constructor() { constructor() {
super(); super();
@ -63,23 +306,51 @@ namespace OS {
this.refs = {}; this.refs = {};
} }
/**
* This function verifies if a property name of the input object
* corresponds to a setter of the current tag. If this is the
* case, it sets the value of that property to the setter
*
* @param {GenericObject<any>} v input object
* @memberof AFXTag
*/
set(v: GenericObject<any>) { set(v: GenericObject<any>) {
for (let k in v) { for (let k in v) {
let descriptor = this.descriptor_of(k); let descriptor = this.descriptor_of(k);
if (descriptor && descriptor.set) if (descriptor && descriptor.set) {
{
this[k] = v[k]; this[k] = v[k];
} }
} }
} }
/**
* Setter to set the tooltip text to the current tag.
* The text should be in the following format:
* ```text
* cr|cl|ct|cb: tooltip text
* ```
*
* @memberof AFXTag
*/
set tooltip(v: string) { set tooltip(v: string) {
if (!v) { if (!v) {
return; return;
} }
$(this).attr("tooltip", v); $(this).attr("tooltip", v);
} }
private descriptor_of(k: string) {
/**
*
* This function looking for a property name of the tag
* in its prototype chain. The descriptor of the property
* will be returned if it exists
*
* @private
* @param {string} k the property name to be queried
* @returns {PropertyDescriptor} the property descriptor or undefined
* @memberof AFXTag
*/
private descriptor_of(k: string): PropertyDescriptor {
let desc: PropertyDescriptor; let desc: PropertyDescriptor;
let obj = this; let obj = this;
do { do {
@ -87,28 +358,55 @@ namespace OS {
} while (!desc && (obj = Object.getPrototypeOf(obj))); } while (!desc && (obj = Object.getPrototypeOf(obj)));
return desc; return desc;
} }
set aid(v: string| number) {
/**
* Setter to set the id of the tag in string or number
*
* @memberof AFXTag
*/
set aid(v: string | number) {
$(this).attr("data-id", v); $(this).attr("data-id", v);
} }
/**
* Getter to get the id of the current tag
*
* @type {(string | number)}
* @memberof AFXTag
*/
get aid(): string | number { get aid(): string | number {
return $(this).attr("data-id"); return $(this).attr("data-id");
} }
/**
* Implementation from HTMLElement interface,
* this function mount the current tag hierarchy
*
* @returns {void}
* @memberof AFXTag
*/
sync(): void { sync(): void {
if(this._mounted) if (this._mounted) {
{
return; return;
} }
this._mounted = true; this._mounted = true;
this.mount(); this.mount();
super.sync(); super.sync();
} }
/**
* Generate the DOM hierarchy of the current tag
*
* @param {API.Announcer} o observable object
* @memberof AFXTag
*/
afxml(o: API.Announcer): void { afxml(o: API.Announcer): void {
if(o) if (o) this.observable = o;
this.observable = o; if (!this.aid)
if(!this.aid) this.aid = (
this.aid = (Math.floor(Math.random() * 100000) + 1).toString(); Math.floor(Math.random() * 100000) + 1
const children = $(this).children(); ).toString();
const children = $(this).children();
for (let obj of this.layout()) { for (let obj of this.layout()) {
const dom = this.mkui(obj); const dom = this.mkui(obj);
if (dom) { if (dom) {
@ -120,7 +418,7 @@ namespace OS {
$(v).detach().appendTo(this.refs.yield); $(v).detach().appendTo(this.refs.yield);
} }
} }
const attrs = {}; const attrs = {};
for (let i = 0; i < this.attributes.length; i++) { for (let i = 0; i < this.attributes.length; i++) {
const element = this.attributes[i]; const element = this.attributes[i];
let descriptor = this.descriptor_of(element.nodeName); let descriptor = this.descriptor_of(element.nodeName);
@ -136,26 +434,82 @@ namespace OS {
} }
super.afxml(this.observable); super.afxml(this.observable);
this.init(); this.init();
for(let k in attrs) for (let k in attrs) {
{
this[k] = attrs[k]; this[k] = attrs[k];
} }
} }
/**
* Update the current tag hierarchy
*
* @param {*} d any data object
* @memberof AFXTag
*/
update(d: any): void { update(d: any): void {
this.reload(d); this.reload(d);
super.update(d); super.update(d);
} }
/**
* Init the current tag, this function
* is called before the [[mount]] function
*
* @protected
* @abstract
* @memberof AFXTag
*/
protected abstract init(): void; protected abstract init(): void;
/**
* Mount only the current tag
*
* @protected
* @abstract
* @memberof AFXTag
*/
protected abstract mount(): void; protected abstract mount(): void;
/**
* Layout definition of a tag
*
* @protected
* @abstract
* @returns {TagLayoutType[]} tag layout object
* @memberof AFXTag
*/
protected abstract layout(): TagLayoutType[]; protected abstract layout(): TagLayoutType[];
/**
* Update only the current tag, this function is
* called by [[update]] before chaining the
* update process to its children
*
* @protected
* @abstract
* @param {*} [d]
* @memberof AFXTag
*/
protected abstract reload(d?: any): void; protected abstract reload(d?: any): void;
// should be defined by subclasses
/**
* This function is used to re-render the current
* tag
*
* @protected
* @memberof AFXTag
*/
protected calibrate(): void {} protected calibrate(): void {}
/**
* This function parses the input layout object
* and generates all the elements defined by
* the tag
*
* @private
* @param {TagLayoutType} tag tag layout object
* @returns {Element} the DOM element specified by the tag layout
* @memberof AFXTag
*/
private mkui(tag: TagLayoutType): Element { private mkui(tag: TagLayoutType): Element {
if (!tag) { if (!tag) {
return undefined; return undefined;
@ -188,27 +542,63 @@ namespace OS {
return dom[0]; //.uify(@observable) return dom[0]; //.uify(@observable)
} }
/**
* This function inserts or removes an attribute name
* to/from the target element based on the input `flag`.
*
* @protected
* @param {boolean} flag indicates whether the attribute name should be inserted o removed
* @param {string} v the attribute name
* @param {HTMLElement} [el] the target element
* @memberof AFXTag
*/
protected attsw(flag: boolean, v: string, el?: HTMLElement): void { protected attsw(flag: boolean, v: string, el?: HTMLElement): void {
if (flag) this.atton(v, el); if (flag) this.atton(v, el);
else this.attoff(v, el); else this.attoff(v, el);
} }
/**
* Insert the attribute name to the target element
*
* @protected
* @param {string} v the attribute name
* @param {HTMLElement} [el] the target element
* @memberof AFXTag
*/
protected atton(v: string, el?: HTMLElement): void { protected atton(v: string, el?: HTMLElement): void {
const element = el ? el : this; const element = el ? el : this;
$(element).attr(v, ""); $(element).attr(v, "");
} }
/**
* Remove the attribute name from the target element
*
* @protected
* @param {string} v attribute name
* @param {HTMLElement} [el] the target element
* @memberof AFXTag
*/
protected attoff(v: string, el?: HTMLElement): void { protected attoff(v: string, el?: HTMLElement): void {
const element = el ? el : this; const element = el ? el : this;
element.removeAttribute(v); element.removeAttribute(v);
} }
/**
* Verify if the target element has an attribute name
*
* @protected
* @param {string} v attribute name
* @param {HTMLElement} [el] target element
* @returns {boolean}
* @memberof AFXTag
*/
protected hasattr(v: string, el?: HTMLElement): boolean { protected hasattr(v: string, el?: HTMLElement): boolean {
const element = el ? el : this; const element = el ? el : this;
return element.hasAttribute(v); return element.hasAttribute(v);
} }
} }
HTMLElement.prototype.update = function (d):void { HTMLElement.prototype.update = function (d): void {
$(this) $(this)
.children() .children()
.each(function () { .each(function () {
@ -222,21 +612,39 @@ namespace OS {
return this.sync(); return this.sync();
}); });
}; };
HTMLElement.prototype.afxml = function(o: API.Announcer): void { HTMLElement.prototype.afxml = function (o: API.Announcer): void {
$(this) $(this)
.children() .children()
.each(function () { .each(function () {
return this.afxml(o); return this.afxml(o);
}); });
} };
HTMLElement.prototype.uify = function(o: API.Announcer, toplevel?: boolean): void { HTMLElement.prototype.uify = function (
o: API.Announcer,
toplevel?: boolean
): void {
this.afxml(o); this.afxml(o);
this.sync(); this.sync();
if(o && toplevel) if (o && toplevel) o.trigger("mounted", this.aid);
o.trigger("mounted", this.aid); };
} /**
* All the AFX tags are defined in this namespace,
* these tags are are defined as custom DOM elements and will be
* stored in the `customElements` registry of the browser
*/
export namespace tag { export namespace tag {
/**
* Define an AFX tag as a custom element and add it to the
* global `customElements` registry. If the tag is redefined, i.e.
* the tag already exist, its behavior will be updated with the
* new definition
*
* @export
* @template T all classes that extends [[AFXTag]]
* @param {string} name name of the tag
* @param {{ new (): T }} cls the class that defines the tag
* @returns {void}
*/
export function define<T extends AFXTag>( export function define<T extends AFXTag>(
name: string, name: string,
cls: { new (): T } cls: { new (): T }
@ -245,18 +653,15 @@ namespace OS {
customElements.define(name, cls); customElements.define(name, cls);
} catch (error) { } catch (error) {
const proto = customElements.get(name); const proto = customElements.get(name);
if(cls) if (cls) {
{
const props = Object.getOwnPropertyNames(cls.prototype); const props = Object.getOwnPropertyNames(cls.prototype);
// redefine the class // redefine the class
for(let prop of props) for (let prop of props) {
{
proto.prototype[prop] = cls.prototype[prop]; proto.prototype[prop] = cls.prototype[prop];
} }
return; return;
} }
throw error; throw error;
} }
} }
} }

View File

@ -58,11 +58,11 @@ namespace OS {
* *
* *
* @protected * @protected
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @returns {void} * @returns {void}
* @memberof BaseExtension * @memberof BaseExtension
*/ */
protected notify(m: string | FormatedString): void { protected notify(m: string | FormattedString): void {
return this.app.notify(m); return this.app.notify(m);
} }
@ -70,12 +70,12 @@ namespace OS {
* *
* *
* @protected * @protected
* @param {(string | FormatedString)} m * @param {(string | FormattedString)} m
* @param {Error} e * @param {Error} e
* @returns {void} * @returns {void}
* @memberof BaseExtension * @memberof BaseExtension
*/ */
protected error(m: string | FormatedString, e: Error): void { protected error(m: string | FormattedString, e: Error): void {
return this.app.error(m, e); return this.app.error(m, e);
} }

View File

@ -978,7 +978,7 @@ namespace OS {
* @class CMDMenu * @class CMDMenu
*/ */
class CMDMenu { class CMDMenu {
text: string | FormatedString; text: string | FormattedString;
private shortcut: string; private shortcut: string;
nodes: GenericObject<any>[]; nodes: GenericObject<any>[];
parent: CMDMenu; parent: CMDMenu;
@ -990,11 +990,11 @@ namespace OS {
/** /**
*Creates an instance of CMDMenu. *Creates an instance of CMDMenu.
* @param {(string | FormatedString)} text * @param {(string | FormattedString)} text
* @param {string} [shortcut] * @param {string} [shortcut]
* @memberof CMDMenu * @memberof CMDMenu
*/ */
constructor(text: string | FormatedString, shortcut?: string) { constructor(text: string | FormattedString, shortcut?: string) {
this.text = text; this.text = text;
this.shortcut = shortcut; this.shortcut = shortcut;
this.nodes = []; this.nodes = [];