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
NC=\033[0m
@ -156,6 +157,9 @@ uglify:
release: main uglify
doc:
typedoc --mode file --excludeNotExported --hideGenerator --out $(DOCDIR)
clean:
rm -rf $(BUILDDIR)/resources
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)
[![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
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
[https://github.com/lxsang/antosdk-apps](https://github.com/lxsang/antosdk-apps)
## Dependencies
## Documentation
- npm install @types/jquery
- 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.
- API documentation: [https://doc.iohuv.dev/antos/api/](https://doc.iohuv.dev/antos/api/)
## 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

View File

@ -219,10 +219,10 @@ namespace OS {
*
*
* @export
* @param {(string | FormatedString)} m
* @param {(string | FormattedString)} m
* @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 });
}
@ -230,10 +230,10 @@ namespace OS {
*
*
* @export
* @param {(string | FormatedString)} m
* @param {(string | FormattedString)} m
* @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 });
}
@ -241,9 +241,9 @@ namespace OS {
*
*
* @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 });
}

View File

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

View File

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

View File

@ -1,13 +1,4 @@
/*
* 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>
// Copyright 2017-2020 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information
@ -40,7 +31,7 @@ interface String {
unescape(): string;
asUint8Array(): Uint8Array;
format(...args: any[]): string;
f(...args: any[]): OS.FormatedString;
f(...args: any[]): OS.FormattedString;
__(): string;
l(): string;
trimLeft(arg: string): string;
@ -71,9 +62,9 @@ interface GenericObject<T> {
*
*
* @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;
}
Ant.__ = function (...args: any[]): FormatedString | string {
Ant.__ = function (...args: any[]): FormattedString | string {
if (!(args.length > 0)) {
return "Undefined";
}
const d = args[0];
d.l();
return new FormatedString(
return new FormattedString(
d,
__range__(1, args.length - 1, true).map((i) => args[i])
);
@ -134,9 +125,9 @@ namespace OS {
*
*
* @export
* @class FormatedString
* @class FormattedString
*/
export class FormatedString {
export class FormattedString {
fs: string;
values: any[];
constructor(fs: string, args: any[]) {
@ -158,7 +149,7 @@ namespace OS {
*
*
* @returns {string}
* @memberof FormatedString
* @memberof FormattedString
*/
toString(): string {
return this.__();
@ -168,7 +159,7 @@ namespace OS {
*
*
* @returns {string}
* @memberof FormatedString
* @memberof FormattedString
*/
__(): string {
return this.fs
@ -186,7 +177,7 @@ namespace OS {
*
*
* @returns {number}
* @memberof FormatedString
* @memberof FormattedString
*/
hash(): number {
return this.__().hash();
@ -197,7 +188,7 @@ namespace OS {
*
* @param {(string | RegExp)} t
* @returns {RegExpMatchArray}
* @memberof FormatedString
* @memberof FormattedString
*/
match(t: string | RegExp): RegExpMatchArray {
return this.__().match(t);
@ -207,7 +198,7 @@ namespace OS {
*
*
* @returns {string}
* @memberof FormatedString
* @memberof FormattedString
*/
asBase64(): string {
return this.__().asBase64();
@ -217,7 +208,7 @@ namespace OS {
*
*
* @returns {string}
* @memberof FormatedString
* @memberof FormattedString
*/
unescape(): string {
return this.__().unescape();
@ -227,7 +218,7 @@ namespace OS {
*
*
* @returns {Uint8Array}
* @memberof FormatedString
* @memberof FormattedString
*/
asUint8Array(): Uint8Array {
return this.__().asUint8Array();
@ -237,7 +228,7 @@ namespace OS {
*
*
* @param {...any[]} args
* @memberof FormatedString
* @memberof FormattedString
*/
format(...args: any[]): void {
__range__(0, args.length - 1, true).map(
@ -444,8 +435,8 @@ namespace OS {
};
}
String.prototype.f = function (...args: any[]): FormatedString {
return new FormatedString(this, args);
String.prototype.f = function (...args: any[]): FormattedString {
return new FormattedString(this, args);
};
String.prototype.__ = function (): string {
@ -810,12 +801,16 @@ namespace OS {
}
/**
*
* Perform an REST GET request
*
* @export
* @param {string} p
* @param {string} [t=undefined]
* @returns {Promise<any>}
* @param {string} p the URI of the request
* @param {string} [t=undefined] the response data type:
* - 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> {
return new Promise(function (resolve, reject) {
@ -1083,10 +1078,10 @@ namespace OS {
*
*
* @export
* @param {(string | FormatedString)} n
* @param {(string | FormattedString)} n
* @returns {Error}
*/
export function throwe(n: string | FormatedString): Error {
export function throwe(n: string | FormattedString): Error {
let err = undefined;
try {
throw new Error(n.__());

View File

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

View File

@ -1,9 +1,4 @@
/*
* 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>
// Copyright 2017-2020 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information
@ -23,48 +18,172 @@
namespace OS {
export namespace API {
/**
* Interface for user login data
*
* @export
* @interface UserLoginType
*/
export interface UserLoginType {
/**
* The user credential
*
* @type {string}
* @memberof UserLoginType
*/
username: string;
/**
* The user password
*
* @type {string}
* @memberof UserLoginType
*/
password: string;
}
/**
* Interface for a command sent to
* server side package manage, it contains two field:
*
* @export
* @interface PackageCommandType
*/
export interface PackageCommandType {
/**
* Command name, should be: `init`, `cache`, `install`,
* `uninstall` or `list`
*
* @type {string}
* @memberof PackageCommandType
*/
command: string;
/**
* Parameter object of each command
*
* @type {GenericObject<any>}
* @memberof PackageCommandType
*/
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 {
/**
* Indicate whether an the response is error
*
* @type {(boolean | string)}
* @memberof RequestResult
*/
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:
| string
| boolean
| GenericObject<any>
| any[]
| FileInfoType
| FileInfoType[];
| FileInfoType[]
| setting.UserSettingType;
}
let loc: any = { hostname: "localhost", port: "80", protocol: "http" };
if (Ant.location) loc = Ant.location;
/**
* The host name of the server-side
*/
export var HOST: string =
loc.hostname + (loc.port ? `:${loc.port}` : "");
/**
* The base REST URI of the server-side API
*/
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 {
// get file, require authentification
/**
* Base URI for reading content of VFS file
*/
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`;
/**
* 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> {
const path = `${REST}/VFS/scandir`;
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> {
const path = `${API.REST}/VFS/mkdir`;
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(
p: string,
pub: boolean
@ -73,31 +192,88 @@ namespace OS {
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> {
const path = `${API.REST}/VFS/fileinfo`;
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> {
const path = `${API.REST}/VFS/get/`;
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> {
const path = `${API.REST}/VFS/move`;
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> {
const path = `${API.REST}/VFS/delete`;
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> {
const path = `${API.REST}/VFS/get/`;
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(
d: PackageCommandType
): Promise<RequestResult> {
@ -105,11 +281,26 @@ namespace OS {
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> {
const path = `${API.REST}/VFS/upload`;
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(
p: string,
d: string
@ -117,6 +308,35 @@ namespace OS {
const path = `${API.REST}/VFS/write`;
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(
d: GenericObject<any>,
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> {
const p = `${API.REST}/user/auth`;
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> {
const p = `${API.REST}/user/login`;
return API.post(p, d);
}
/**
* Perform a logout operation
*
* @export
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function logout(): Promise<RequestResult> {
const p = `${API.REST}/user/logout`;
return API.post(p, {});
}
/**
* Save the current user settings
*
* @export
* @returns {Promise<RequestResult>} a promise on a [[RequestResult]]
*/
export function setting(): Promise<RequestResult> {
const p = `${API.REST}/system/settings`;
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(
cmd: string,
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 {
export namespace GUI {
/**
*
* Interface for an application dock item
*
* @export
* @interface AppDockItemType
*/
export interface AppDockItemType {
/**
* Reference to the application process represented
* by the dock item
*
* @type {application.BaseApplication}
* @memberof AppDockItemType
*/
app: application.BaseApplication;
/**
* Reference to the DOM element of
* the owner dock item
*
* @type {AFXTag}
* @memberof AppDockItemType
*/
domel?: AFXTag;
[propName: string]: any;
}
export namespace tag {
/**
*
* This class define the AntOS system application dock tag
*
* @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>;
/**
* Items data of the dock
*
* @private
* @type {AppDockItemType[]}
* @memberof AppDockTag
*/
private _items: AppDockItemType[];
/**
* Reference to the currently select application
* process in the dock
*
* @private
* @type {application.BaseApplication}
* @memberof AppDockTag
*/
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
* @param {*} [d]
* @memberof AppDockTag
*/
protected reload(d?: any): void {
}
protected reload(d?: any): void {}
/**
*
* Init the tag before mounting
*
* @protected
* @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
* @returns {TagLayoutType[]}
@ -73,16 +108,7 @@ namespace OS {
}
/**
*
*
* @protected
* @param {*} [d]
* @memberof AppDockTag
*/
protected refresh(d?: any): void {}
/**
*
* getter to get the dock items
*
* @readonly
* @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
*/
@ -115,7 +144,8 @@ namespace OS {
}
/**
*
* getter to get the current selected application
* on the dock
*
* @type {BaseApplication}
* @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
* @param {AppDockItemType} item an application dock item entry
* @memberof AppDockTag
*/
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
* @param {BaseApplication} a the application to be removed from the dock
* @memberof AppDockTag
*/
removeapp(a: application.BaseApplication): void {
@ -174,7 +209,7 @@ namespace OS {
}
/**
*
* Mount the current dock tag
*
* @protected
* @memberof AppDockTag
@ -184,7 +219,9 @@ namespace OS {
if (e.target === this) {
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;
m.items = [
{ 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 {
export namespace GUI {
export namespace tag {
/**
* This tag define a basic button and its behavior
*
* @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>;
/**
* Custom user data
*
* @type {GenericObject<any>}
* @memberof ButtonTag
*/
data: GenericObject<any>;
/**
*Creates an instance of ButtonTag.
* @memberof ButtonTag
*/
constructor() {
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;
}
/**
* Set the path to the button icon, the path should be
* a VFS file path
*
* @memberof ButtonTag
*/
set icon(v: string) {
$(this).attr("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) {
$(this).attr("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;
}
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;
}
/**
* Enable or disable the button
*
* @memberof ButtonTag
*/
set enable(v: boolean) {
$(this.refs.button).prop("disabled", !v);
}
/**
* Get the `enable` property of the button
*
* @type {boolean}
* @memberof ButtonTag
*/
get enable(): boolean {
return !$(this.refs.button).prop("disabled");
}
/**
* set or remove the attribute `selected` of the button
*
* @memberof ButtonTag
*/
set selected(v: boolean) {
$(this.refs.button).removeClass();
this.attsw(v, "selected");
@ -48,18 +115,42 @@ namespace OS {
$(this.refs.button).addClass("selected");
}
}
/**
* check whether the attribute `selected` of the button is set
*
* @type {boolean}
* @memberof ButtonTag
*/
get selected(): boolean {
return this.hasattr("selected");
}
/**
* activate or deactivate the toggle mode of the button
*
* @memberof ButtonTag
*/
set toggle(v: boolean) {
this.attsw(v, "toggle");
}
/**
* Check whether the button is in toggle mode
*
* @type {boolean}
* @memberof ButtonTag
*/
get toggle(): boolean {
return this.hasattr("toggle");
}
/**
* Mount the tag
*
* @protected
* @memberof ButtonTag
*/
protected mount() {
$(this.refs.button).click((e) => {
const evt: TagEventType<JQuery.MouseEventBase> = {
@ -73,13 +164,42 @@ namespace OS {
}
});
}
/**
* Init the tag before mounting
*
* @protected
* @memberof ButtonTag
*/
protected init(): void {
this.enable = true;
this.toggle = false;
this._onbtclick = (e) => {};
}
/**
* Re-calibrate the button, do nothing in this tag
*
* @protected
* @memberof ButtonTag
*/
protected calibrate(): void {}
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof ButtonTag
*/
reload(d?: any): void {}
/**
* Button layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof ButtonTag
*/
protected layout(): TagLayoutType[] {
return [
{
@ -90,6 +210,7 @@ namespace OS {
];
}
}
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 {
export namespace GUI {
export namespace tag {
/**
*
* Tag that define system calendar widget
*
* @export
* @class CalendarTag
* @extends {AFXTag}
*/
export class CalendarTag extends AFXTag {
/**
* The current selected day
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _day: number;
/**
* The current selected month
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _month: number;
/**
* The current selected year
*
* @private
* @type {number}
* @memberof CalendarTag
*/
private _year: number;
/**
* The current selected date object
*
* @private
* @type {Date}
* @memberof CalendarTag
*/
private _selectedDate: Date;
/**
* holder for date select event callback
*
* @private
* @type {TagEventCallback<Date>}
* @memberof CalendarTag
*/
private _ondateselect: TagEventCallback<Date>;
/**
@ -35,7 +67,7 @@ namespace OS {
}
/**
*
* Init the tag before mounting
*
* @protected
* @memberof CalendarTag
@ -46,17 +78,16 @@ namespace OS {
}
/**
*
* Update the current tag, doing nothing in this tag
*
* @protected
* @param {*} [d]
* @param {*} [d] any data object
* @memberof CalendarTag
*/
protected reload(d?: any): void {
}
protected reload(d?: any): void {}
/**
*
* Get the current selected date in the widget
*
* @readonly
* @type {Date}
@ -67,7 +98,7 @@ namespace OS {
}
/**
*
* Set the date select event callback handle for the widget
*
* @memberof CalendarTag
*/
@ -76,7 +107,7 @@ namespace OS {
}
/**
*
* Mount the current widget to the DOM tree
*
* @protected
* @memberof CalendarTag
@ -104,14 +135,16 @@ namespace OS {
}
/**
*
* This function triggers the date select event
*
* @private
* @param {TagEventType} e
* @param {TagEventType} e AFX tag event data [[TagEventType]]
* @returns {void}
* @memberof CalendarTag
*/
private dateselect(e: TagEventType<TagEventDataType<tag.GridCellPrototype>>): void {
private dateselect(
e: TagEventType<TagEventDataType<tag.GridCellPrototype>>
): void {
if (!e.data.item) {
return;
}
@ -121,7 +154,11 @@ namespace OS {
}
const evt = {
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._selectedDate = evt.data;
@ -129,7 +166,7 @@ namespace OS {
}
/**
*
* Calibrate the layout of the tag
*
* @protected
* @memberof CalendarTag
@ -142,7 +179,7 @@ namespace OS {
}
/**
*
* Display the previous month of the current month
*
* @private
* @memberof CalendarTag
@ -157,9 +194,8 @@ namespace OS {
this.calendar(new Date(this._year, this._month, 1));
}
/**
*
* Display the next month of the current month
*
* @private
* @returns
@ -176,7 +212,7 @@ namespace OS {
}
/**
*
* Visualize the calendar base on input date
*
* @private
* @param {Date} date
@ -265,11 +301,13 @@ namespace OS {
rows.push(row);
const grid = this.refs.grid as GridViewTag;
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
* @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 {
export namespace GUI {
/**
*
* Color type used by AFX API
*
* @export
* @interface ColorType
*/
export interface ColorType {
/**
* Red chanel
*
* @type {number}
* @memberof ColorType
*/
r: number;
/**
* Green chanel
*
* @type {number}
* @memberof ColorType
*/
g: number;
/**
* Blue chanel
*
* @type {number}
* @memberof ColorType
*/
b: number;
/**
* Alpha chanel
*
* @type {number}
* @memberof ColorType
*/
a?: number;
/**
* color text in CSS format
*
* @type {string}
* @memberof ColorType
*/
text?: string;
/**
* Color in hex format
*
* @type {string}
* @memberof ColorType
*/
hex?: string;
}
export namespace tag {
/**
*
* Class definition of Color picker widget
*
* @export
* @class ColorPickerTag
* @extends {AFXTag}
*/
export class ColorPickerTag extends AFXTag {
/**
* The current selected color object
*
* @private
* @type {ColorType}
* @memberof ColorPickerTag
*/
private _selectedColor: ColorType;
/**
* Holder for the color select event callback
*
* @private
* @type {TagEventCallback<ColorType>}
* @memberof ColorPickerTag
*/
private _oncolorselect: TagEventCallback<ColorType>;
/**
*Creates an instance of ColorPickerTag.
* Creates an instance of ColorPickerTag.
* @memberof ColorPickerTag
*/
constructor() {
@ -41,7 +92,7 @@ namespace OS {
}
/**
*
* Init tag before mounting, do nothing
*
* @protected
* @memberof ColorPickerTag
@ -49,7 +100,7 @@ namespace OS {
protected init(): void {}
/**
*
* Reload tag, do nothing
*
* @protected
* @param {*} [d]
@ -58,7 +109,7 @@ namespace OS {
protected reload(d?: any): void {}
/**
*
* Get selected color value
*
* @readonly
* @type {ColorType}
@ -69,7 +120,7 @@ namespace OS {
}
/**
*
* Set the color select event handle
*
* @memberof ColorPickerTag
*/
@ -78,7 +129,7 @@ namespace OS {
}
/**
*
* Mount the widget to DOM tree
*
* @protected
* @memberof ColorPickerTag
@ -112,7 +163,7 @@ namespace OS {
}
/**
*
* Build the color palette
*
* @private
* @memberof ColorPickerTag
@ -237,7 +288,7 @@ namespace OS {
}
/**
*
* layout definition of the widget
*
* @protected
* @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 {
export namespace GUI {
export namespace tag {
/**
*
* Definition of system file view widget
*
* @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>;
/**
* Holder for file open event callback
*
* @private
* @type {TagEventCallback<API.FileInfoType>}
* @memberof FileViewTag
*/
private _onfileopen: TagEventCallback<API.FileInfoType>;
/**
* Reference to the currently selected file meta-data
*
* @private
* @type {API.FileInfoType}
* @memberof FileViewTag
*/
private _selectedFile: API.FileInfoType;
/**
* Data holder of the current working directory
*
* @private
* @type {API.FileInfoType[]}
* @memberof FileViewTag
*/
private _data: API.FileInfoType[];
/**
* The path of the current working directory
*
* @private
* @type {string}
* @memberof FileViewTag
*/
private _path: string;
/**
* Header definition of the widget grid view
*
* @private
* @type {(GenericObject<string | number>[])}
* @memberof FileViewTag
*/
private _header: GenericObject<string | number>[];
/**
* Holder for the user-specified meta-data fetch function
*
* @private
* @memberof FileViewTag
*/
private _fetch: (p: string) => Promise<API.FileInfoType[]>;
/**
@ -31,7 +80,7 @@ namespace OS {
}
/**
*
* Init the widget before mounting
*
* @protected
* @memberof FileViewTag
@ -51,15 +100,18 @@ namespace OS {
}
/**
*
* Update the current widget, do nothing
*
* @protected
* @param {*} [d]
* @memberof FileViewTag
*/
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
*/
@ -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
*/
@ -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
*/
@ -86,7 +142,10 @@ namespace OS {
}
/**
*
* chang the view of the widget, there are three different views
* - `icon`
* - `list`
* - `tree`
*
* @memberof FileViewTag
*/
@ -96,7 +155,7 @@ namespace OS {
}
/**
*
* Get the current view setting of the widget
*
* @type {string}
* @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
*/
@ -115,7 +177,8 @@ namespace OS {
}
/**
*
* check whether changing current working directory feature
* is enabled
*
* @type {boolean}
* @memberof FileViewTag
@ -125,7 +188,7 @@ namespace OS {
}
/**
*
* Enable or disable the status bar of the widget
*
* @memberof FileViewTag
*/
@ -139,7 +202,7 @@ namespace OS {
}
/**
*
* Check whether the status bar is enabled
*
* @type {boolean}
* @memberof FileViewTag
@ -149,7 +212,7 @@ namespace OS {
}
/**
*
* Allow the widget to show or hide hidden file
*
* @memberof FileViewTag
*/
@ -162,7 +225,8 @@ namespace OS {
}
/**
*
* Check whether the hidden file should be shown in
* the widget
*
* @type {boolean}
* @memberof FileViewTag
@ -172,7 +236,7 @@ namespace OS {
}
/**
*
* Get the current selected file
*
* @readonly
* @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
*/
@ -211,7 +278,7 @@ namespace OS {
}
/**
*
* Get the path of the current working directory
*
* @type {string}
* @memberof FileViewTag
@ -221,7 +288,7 @@ namespace OS {
}
/**
*
* Set the data of the current working directory
*
* @memberof FileViewTag
*/
@ -234,7 +301,7 @@ namespace OS {
}
/**
*
* Get the data of the current working directory
*
* @type {API.FileInfoType[]}
* @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
*/
set ondragndrop(v: TagEventCallback<DnDEventDataType<TreeViewTag| ListViewItemTag>>) {
set ondragndrop(
v: TagEventCallback<
DnDEventDataType<TreeViewTag | ListViewItemTag>
>
) {
(this.refs.treeview as TreeViewTag).ondragndrop = v;
(this.refs.listview as ListViewTag).ondragndrop = v;
}
/**
*
* sort file by it type
*
* @private
* @param {API.FileInfoType} a
* @param {API.FileInfoType} b
* @param {API.FileInfoType} a first file meta-data
* @param {API.FileInfoType} b second file meta-data
* @returns {(0|-1|1)}
* @memberof FileViewTag
*/
@ -276,7 +348,7 @@ namespace OS {
}
/**
*
* calibrate the widget layout
*
* @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
* @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
* @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
* @memberof FileViewTag
@ -359,17 +434,18 @@ namespace OS {
text: this.path,
path: this.path,
open: true,
nodes: this.getTreeData(this.data)
nodes: this.getTreeData(this.data),
};
(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
* @param {API.FileInfoType[]} data
* @param {API.FileInfoType[]} data list of file meta-data
* @returns {TreeViewDataType[]}
* @memberof FileViewTag
*/
@ -395,7 +471,7 @@ namespace OS {
}
/**
*
* Refresh data of the current widget view
*
* @private
* @returns {void}
@ -417,7 +493,7 @@ namespace OS {
}
/**
*
* Switch between three view options
*
* @private
* @memberof FileViewTag
@ -445,10 +521,10 @@ namespace OS {
}
/**
*
* This function triggers the file select event
*
* @private
* @param {API.FileInfoType} e
* @param {API.FileInfoType} e selected file meta-data
* @memberof FileViewTag
*/
private fileselect(e: API.FileInfoType): void {
@ -470,10 +546,10 @@ namespace OS {
}
/**
*
* This function triggers the file open event
*
* @private
* @param {API.FileInfoType} e
* @param {API.FileInfoType} e selected file meta-data
* @memberof FileViewTag
*/
private filedbclick(e: API.FileInfoType): void {
@ -491,7 +567,7 @@ namespace OS {
}
/**
*
* Mount the widget in the DOM tree
*
* @protected
* @memberof FileViewTag
@ -529,27 +605,28 @@ namespace OS {
};
grid.onrowselect = (e) => {
this.fileselect(
$(e.data.item).children()[0].data as API.FileInfoType
$(e.data.item).children()[0]
.data as API.FileInfoType
);
};
tree.ontreeselect = (e) => {
this.fileselect(e.data.item.data as API.FileInfoType);
this.fileselect(e.data.item.data as API.FileInfoType);
};
// dblclick
list.onlistdbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType);
this.filedbclick(e.data.item.data as API.FileInfoType);
};
grid.oncelldbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType);
};
tree.ontreedbclick = (e) => {
this.filedbclick(e.data.item.data as API.FileInfoType);
this.filedbclick(e.data.item.data as API.FileInfoType);
};
this.switchView();
}
/**
*
* Layout definition of the widget
*
* @protected
* @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 {
export namespace GUI {
export namespace tag {
/**
*
* A float list is a list of items in which each
* item can be moved (drag and drop) freely
*
* @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;
/**
@ -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
*/
@ -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
*/
@ -46,7 +64,8 @@ namespace OS {
}
/**
*
* Get the currently set direction of list
* item layout
*
* @type {string}
* @memberof FloatListTag
@ -54,24 +73,24 @@ namespace OS {
get dir(): string {
return $(this).attr("dir");
}
// disable some uneccessary functions
/**
*
* Disable the dropdown option in this list
*
* @memberof FloatListTag
*/
set dropdown(v: boolean) {}
/**
*
* Disable the list buttons configuration in this
* list
*
* @memberof FloatListTag
*/
set buttons(v: GenericObject<any>[]) {}
/**
*
* Disable the `showlist` behavior in this list
*
* @protected
* @param {*} e
@ -80,7 +99,7 @@ namespace OS {
protected showlist(e: any) {}
/**
*
* Disable the `dropoff` behavior in this list
*
* @protected
* @param {*} e
@ -89,7 +108,8 @@ namespace OS {
protected dropoff(e: any) {}
/**
*
* Function called when the data of the list
* is changed
*
* @protected
* @memberof FloatListTag
@ -99,7 +119,7 @@ namespace OS {
}
/**
*
* Mount the list to the DOM tree
*
* @protected
* @returns {void}
@ -120,9 +140,9 @@ namespace OS {
}
/**
* Push an element to the list
*
*
* @param {GenericObject<any>} v
* @param {GenericObject<any>} v an element data
* @returns
* @memberof FloatListTag
*/
@ -133,10 +153,10 @@ namespace OS {
}
/**
*
* Enable drag and drop on the list
*
* @private
* @param {ListViewItemTag} el
* @param {ListViewItemTag} el the list item DOM element
* @memberof FloatListTag
*/
private enable_drag(el: ListViewItemTag): void {
@ -174,7 +194,7 @@ namespace OS {
}
/**
*
* Calibrate the view of the list
*
* @memberof FloatListTag
*/

View File

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

View File

@ -7,7 +7,7 @@ namespace OS {
export namespace GUI {
export namespace tag {
export class LabelTag extends AFXTag {
private _text: string | FormatedString;
private _text: string | FormattedString;
constructor() {
super();
}
@ -53,7 +53,7 @@ namespace OS {
}
}
set text(v: string | FormatedString) {
set text(v: string | FormattedString) {
this._text = v;
if (v && v !== "") {
$(this.refs.text).show();
@ -63,7 +63,7 @@ namespace OS {
}
}
get text(): string| FormatedString {
get text(): string| FormattedString {
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 {
export namespace GUI {
export namespace tag {
/**
* List item event data type
*/
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
* @abstract
@ -18,11 +18,59 @@ namespace OS {
* @extends {AFXTag}
*/
export abstract class ListViewItemTag extends AFXTag {
/**
* Data holder for the list item
*
* @private
* @type {GenericObject<any>}
* @memberof ListViewItemTag
*/
private _data: GenericObject<any>;
/**
* Holder for the item select event callback
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onselect: TagEventCallback<ListItemEventData>;
/**
* Context menu event callback handle
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onctxmenu: TagEventCallback<ListItemEventData>;
/**
* Click event callback holder
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onclick: TagEventCallback<ListItemEventData>;
/**
* Double click event callback handle
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _ondbclick: TagEventCallback<ListItemEventData>;
/**
* Item close event callback holder
*
* @private
* @type {TagEventCallback<ListItemEventData>}
* @memberof ListViewItemTag
*/
private _onclose: TagEventCallback<ListItemEventData>;
/**

View File

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

View File

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

View File

@ -1,20 +1,95 @@
/*
* 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
/**
*
* Extend the HTMLElement interface with some utility function need
* by AFX API
*
* @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;
/**
*
* 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;
/**
* Mount the element and all the children on its DOM subtree. This action
* is performed in a top-down manner
*
* @memberof HTMLElement
*/
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;
/**
* 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;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
mozRequestFullScreen: any;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
webkitRequestFullscreen: any;
/**
*
*
* @type {*}
* @memberof HTMLElement
*/
msRequestFullscreen: any;
}
/**
*
*
* @interface Document
*/
interface Document {
mozCancelFullScreen: any;
webkitExitFullscreen: any;
@ -22,37 +97,205 @@ interface Document {
}
namespace OS {
export namespace GUI {
/**
* [[TagLayoutType]] interface using by AFX tags to defined
* its internal DOM hierarchy
*
* @export
* @interface TagLayoutType
*/
export interface TagLayoutType {
/**
* Element tag name
*
* @type {string}
* @memberof TagLayoutType
*/
el: string;
/**
* Children layout of the current element
*
* @type {TagLayoutType[]}
* @memberof TagLayoutType
*/
children?: TagLayoutType[];
/**
* Reference name of the element used by AFX Tag
*
* @type {string}
* @memberof TagLayoutType
*/
ref?: string;
/**
* CSS class of the element
*
* @type {string}
* @memberof TagLayoutType
*/
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;
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;
/**
** `data-height` of the element, not to be confused with
* the `height` attribute of the DOM element
*
* @type {number}
* @memberof TagLayoutType
*/
height?: number;
}
/**
* Data type for event issued by AFX tags
*
* @export
* @interface TagEventDataType
* @template T item template
*/
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;
/**
* Data object of the event
*
* @type {T}
* @memberof TagEventType
*/
data: T;
}
/**
* Drag and Drop data type sent between mouse events
*
* @export
* @interface DnDEventDataType
* @template T
*/
export interface DnDEventDataType<T> {
/**
* Reference to the source DOM element
*
* @type {T}
* @memberof DnDEventDataType
*/
from: T;
/**
* Reference to the target DOM element
*
* @type {T}
* @memberof DnDEventDataType
*/
to: T;
}
/**
* Tag event callback type
*/
export type TagEventCallback<T> = (e: TagEventType<T>) => void;
/**
* Top most element z index value, start by 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 {
/**
* The announcer object of the tag
*
* @type {API.Announcer}
* @memberof AFXTag
*/
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>;
/**
* boolean value indicated whether the tag
* is already mounted in the DOM tree
*
* @protected
* @type {boolean}
* @memberof AFXTag
*/
protected _mounted: boolean;
/**
*Creates an instance of AFXTag.
* @memberof AFXTag
*/
constructor() {
super();
@ -63,23 +306,51 @@ namespace OS {
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>) {
for (let k in v) {
let descriptor = this.descriptor_of(k);
if (descriptor && descriptor.set)
{
if (descriptor && descriptor.set) {
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) {
if (!v) {
return;
}
$(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 obj = this;
do {
@ -87,28 +358,55 @@ namespace OS {
} while (!desc && (obj = Object.getPrototypeOf(obj)));
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);
}
/**
* Getter to get the id of the current tag
*
* @type {(string | number)}
* @memberof AFXTag
*/
get aid(): string | number {
return $(this).attr("data-id");
}
/**
* Implementation from HTMLElement interface,
* this function mount the current tag hierarchy
*
* @returns {void}
* @memberof AFXTag
*/
sync(): void {
if(this._mounted)
{
if (this._mounted) {
return;
}
this._mounted = true;
this.mount();
super.sync();
}
/**
* Generate the DOM hierarchy of the current tag
*
* @param {API.Announcer} o observable object
* @memberof AFXTag
*/
afxml(o: API.Announcer): void {
if(o)
this.observable = o;
if(!this.aid)
this.aid = (Math.floor(Math.random() * 100000) + 1).toString();
const children = $(this).children();
if (o) this.observable = o;
if (!this.aid)
this.aid = (
Math.floor(Math.random() * 100000) + 1
).toString();
const children = $(this).children();
for (let obj of this.layout()) {
const dom = this.mkui(obj);
if (dom) {
@ -120,7 +418,7 @@ namespace OS {
$(v).detach().appendTo(this.refs.yield);
}
}
const attrs = {};
const attrs = {};
for (let i = 0; i < this.attributes.length; i++) {
const element = this.attributes[i];
let descriptor = this.descriptor_of(element.nodeName);
@ -136,26 +434,82 @@ namespace OS {
}
super.afxml(this.observable);
this.init();
for(let k in attrs)
{
for (let k in attrs) {
this[k] = attrs[k];
}
}
/**
* Update the current tag hierarchy
*
* @param {*} d any data object
* @memberof AFXTag
*/
update(d: any): void {
this.reload(d);
super.update(d);
}
/**
* Init the current tag, this function
* is called before the [[mount]] function
*
* @protected
* @abstract
* @memberof AFXTag
*/
protected abstract init(): void;
/**
* Mount only the current tag
*
* @protected
* @abstract
* @memberof AFXTag
*/
protected abstract mount(): void;
/**
* Layout definition of a tag
*
* @protected
* @abstract
* @returns {TagLayoutType[]} tag layout object
* @memberof AFXTag
*/
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;
// should be defined by subclasses
/**
* This function is used to re-render the current
* tag
*
* @protected
* @memberof AFXTag
*/
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 {
if (!tag) {
return undefined;
@ -188,27 +542,63 @@ namespace OS {
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 {
if (flag) this.atton(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 {
const element = el ? el : this;
$(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 {
const element = el ? el : this;
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 {
const element = el ? el : this;
return element.hasAttribute(v);
}
}
HTMLElement.prototype.update = function (d):void {
HTMLElement.prototype.update = function (d): void {
$(this)
.children()
.each(function () {
@ -222,21 +612,39 @@ namespace OS {
return this.sync();
});
};
HTMLElement.prototype.afxml = function(o: API.Announcer): void {
HTMLElement.prototype.afxml = function (o: API.Announcer): void {
$(this)
.children()
.each(function () {
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.sync();
if(o && toplevel)
o.trigger("mounted", this.aid);
}
if (o && toplevel) 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 {
/**
* 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>(
name: string,
cls: { new (): T }
@ -245,18 +653,15 @@ namespace OS {
customElements.define(name, cls);
} catch (error) {
const proto = customElements.get(name);
if(cls)
{
if (cls) {
const props = Object.getOwnPropertyNames(cls.prototype);
// redefine the class
for(let prop of props)
{
for (let prop of props) {
proto.prototype[prop] = cls.prototype[prop];
}
return;
}
throw error;
}
}
}

View File

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

View File

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