mirror of
https://github.com/lxsang/antos-frontend.git
synced 2024-12-26 01:18:21 +01:00
feat: Introduce API.Task API that allow to track promise object via AntOS announcement system
This commit is contained in:
parent
0ac886f644
commit
4d59b104b9
81
d.ts/antos.d.ts
vendored
81
d.ts/antos.d.ts
vendored
@ -2034,13 +2034,21 @@ declare namespace OS {
|
||||
*/
|
||||
var lang: GenericObject<string>;
|
||||
/**
|
||||
* Re-export the system announcement {@link OS.announcer.getMID} function to the
|
||||
* core API
|
||||
* A task is a Promise object that is tracked by AntOS via the
|
||||
* Announcerment system
|
||||
*
|
||||
* Task manager implementation can subscribe to the following global events
|
||||
* - ANTOS-TASK-PENDING : a new task/promise is created and executing
|
||||
* - ANTOS-TASK-FULFILLED: a fullfilled task is a resolved promise
|
||||
* - ANTOS-TASK-REJECTED: a rejected task is a rejected or error promise
|
||||
*
|
||||
* Whenever a task is created by this API, it states will be automatically announced
|
||||
* to any subscribers of these events
|
||||
*
|
||||
* @export
|
||||
* @returns {number}
|
||||
* @param {Promise} a Promise object
|
||||
*/
|
||||
function mid(): number;
|
||||
function Task(fn: (resolve: (any: any) => void, reject: (any: any) => void) => void): Promise<any>;
|
||||
/**
|
||||
* REST-based API.
|
||||
*
|
||||
@ -2086,28 +2094,6 @@ declare namespace OS {
|
||||
* @param {*} b file content
|
||||
*/
|
||||
function saveblob(name: string, b: any): void;
|
||||
/**
|
||||
* Helper function to trigger the global `loading`
|
||||
* event. This event should be triggered in the
|
||||
* beginning of a heavy task
|
||||
*
|
||||
* @export
|
||||
* @param {number} q message id, see {@link mid}
|
||||
* @param {string} p message string
|
||||
*/
|
||||
function loading(q: number, p: string): void;
|
||||
/**
|
||||
* Helper function to trigger the global `loaded`
|
||||
* event: This event should be triggered in the
|
||||
* end of a heavy task that has previously triggered
|
||||
* the `loading` event
|
||||
*
|
||||
* @export
|
||||
* @param {number} q the message id of the corresponding `loading` event
|
||||
* @param {string} p the message string
|
||||
* @param {string} m message status (`OK` of `FAIL`)
|
||||
*/
|
||||
function loaded(q: number, p: string, m: string): void;
|
||||
/**
|
||||
* Perform an REST GET request
|
||||
*
|
||||
@ -2348,21 +2334,6 @@ declare namespace OS {
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
sysdock: GUI.tag.AppDockTag;
|
||||
/**
|
||||
* Loading animation check timeout
|
||||
*
|
||||
* @private
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private _loading_toh;
|
||||
/**
|
||||
* Store pending loading task
|
||||
*
|
||||
* @private
|
||||
* @type {number[]}
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private _pending_task;
|
||||
/**
|
||||
*Creates an instance of BaseApplication.
|
||||
* @param {string} name application name
|
||||
@ -2393,9 +2364,8 @@ declare namespace OS {
|
||||
protected loadScheme(): void;
|
||||
/**
|
||||
* API function to perform an heavy task.
|
||||
* This function will trigger the global `loading`
|
||||
* event at the beginning of the task, and the `loaded`
|
||||
* event after finishing the task
|
||||
* This function will create a Task that is tracked by any
|
||||
* task manager implementation
|
||||
*
|
||||
* @protected
|
||||
* @param {Promise<any>} promise the promise on a task to be performed
|
||||
@ -2569,14 +2539,6 @@ declare namespace OS {
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
protected cleanup(e: BaseEvent): void;
|
||||
/**
|
||||
* Check if the loading tasks ended,
|
||||
* if it the case, stop the animation
|
||||
*
|
||||
* @private
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private animation_check;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6452,7 +6414,7 @@ declare namespace OS {
|
||||
* Store pending loading task
|
||||
*
|
||||
* @private
|
||||
* @type {number[]}
|
||||
* @type {Promise<any>[]}
|
||||
* @memberof SystemPanelTag
|
||||
*/
|
||||
private _pending_task;
|
||||
@ -10681,12 +10643,6 @@ declare namespace OS {
|
||||
* and callbacks
|
||||
*/
|
||||
var observable: API.Announcer;
|
||||
/**
|
||||
* This variable is used to allocate the `id` of all messages
|
||||
* passing between publishers and subscribers in the
|
||||
* system announcement
|
||||
*/
|
||||
var quota: 0;
|
||||
/**
|
||||
* Placeholder of all global events listeners
|
||||
*/
|
||||
@ -10759,13 +10715,6 @@ declare namespace OS {
|
||||
* @returns {void}
|
||||
*/
|
||||
function unregister(app: BaseModel): void;
|
||||
/**
|
||||
* Allocate message id
|
||||
*
|
||||
* @export
|
||||
* @returns {number}
|
||||
*/
|
||||
function getMID(): number;
|
||||
}
|
||||
}
|
||||
declare namespace OS {
|
||||
|
@ -290,12 +290,6 @@ namespace OS {
|
||||
* and callbacks
|
||||
*/
|
||||
export var observable: API.Announcer = new API.Announcer();
|
||||
/**
|
||||
* This variable is used to allocate the `id` of all messages
|
||||
* passing between publishers and subscribers in the
|
||||
* system announcement
|
||||
*/
|
||||
export var quota: 0;
|
||||
/**
|
||||
* Placeholder of all global events listeners
|
||||
*/
|
||||
@ -412,16 +406,5 @@ namespace OS {
|
||||
}
|
||||
announcer.listeners.delete(app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate message id
|
||||
*
|
||||
* @export
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getMID(): number {
|
||||
quota += 1;
|
||||
return quota;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,22 +61,6 @@ namespace OS {
|
||||
*/
|
||||
sysdock: GUI.tag.AppDockTag;
|
||||
|
||||
/**
|
||||
* Loading animation check timeout
|
||||
*
|
||||
* @private
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private _loading_toh: any;
|
||||
/**
|
||||
* Store pending loading task
|
||||
*
|
||||
* @private
|
||||
* @type {number[]}
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private _pending_task: number[];
|
||||
|
||||
/**
|
||||
*Creates an instance of BaseApplication.
|
||||
* @param {string} name application name
|
||||
@ -90,8 +74,6 @@ namespace OS {
|
||||
}
|
||||
this.setting = setting.applications[this.name];
|
||||
this.keycomb = {};
|
||||
this._loading_toh = undefined;
|
||||
this._pending_task = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,25 +121,7 @@ namespace OS {
|
||||
this.applySetting(m.message as string);
|
||||
}
|
||||
});
|
||||
this.subscribe("loading", (o: API.AnnouncementDataType<number>) => {
|
||||
if(o.u_data != this.pid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this._pending_task.push(o.id);
|
||||
this.trigger("loading", undefined);
|
||||
});
|
||||
this.subscribe("loaded", (o: API.AnnouncementDataType<number>) => {
|
||||
const i = this._pending_task.indexOf(o.id);
|
||||
if (i >= 0) {
|
||||
this._pending_task.splice(i, 1);
|
||||
}
|
||||
if (this._pending_task.length === 0) {
|
||||
// set time out
|
||||
if(!this._loading_toh)
|
||||
this._loading_toh = setTimeout(() => this.animation_check(),1000);
|
||||
}
|
||||
});
|
||||
|
||||
this.updateLocale(this.systemsetting.system.locale);
|
||||
return this.loadScheme();
|
||||
}
|
||||
@ -178,9 +142,8 @@ namespace OS {
|
||||
|
||||
/**
|
||||
* API function to perform an heavy task.
|
||||
* This function will trigger the global `loading`
|
||||
* event at the beginning of the task, and the `loaded`
|
||||
* event after finishing the task
|
||||
* This function will create a Task that is tracked by any
|
||||
* task manager implementation
|
||||
*
|
||||
* @protected
|
||||
* @param {Promise<any>} promise the promise on a task to be performed
|
||||
@ -188,15 +151,11 @@ namespace OS {
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
protected load(promise: Promise<any>): Promise<void> {
|
||||
const q = this._api.mid();
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this._api.loading(q, this.name);
|
||||
return this._api.Task(async (resolve, reject) => {
|
||||
try {
|
||||
await promise;
|
||||
this._api.loaded(q, this.name, "OK");
|
||||
return resolve();
|
||||
return resolve(undefined);
|
||||
} catch (e) {
|
||||
this._api.loaded(q, this.name, "FAIL");
|
||||
return reject(__e(e));
|
||||
}
|
||||
});
|
||||
@ -505,23 +464,6 @@ namespace OS {
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
protected cleanup(e: BaseEvent): void {}
|
||||
|
||||
/**
|
||||
* Check if the loading tasks ended,
|
||||
* if it the case, stop the animation
|
||||
*
|
||||
* @private
|
||||
* @memberof BaseApplication
|
||||
*/
|
||||
private animation_check(): void {
|
||||
if(this._pending_task.length === 0)
|
||||
{
|
||||
this.trigger("loaded", undefined);
|
||||
}
|
||||
if(this._loading_toh)
|
||||
clearTimeout(this._loading_toh);
|
||||
this._loading_toh = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
BaseApplication.type = ModelType.Application;
|
||||
|
107
src/core/core.ts
107
src/core/core.ts
@ -878,7 +878,6 @@ namespace OS {
|
||||
$("#wrapper").empty();
|
||||
GUI.clearTheme();
|
||||
announcer.observable = new API.Announcer();
|
||||
announcer.quota = 0;
|
||||
resetSetting();
|
||||
PM.processes = {};
|
||||
PM.pidalloc = 0;
|
||||
@ -1183,14 +1182,44 @@ namespace OS {
|
||||
export var lang: GenericObject<string> = {};
|
||||
|
||||
/**
|
||||
* Re-export the system announcement {@link OS.announcer.getMID} function to the
|
||||
* core API
|
||||
*
|
||||
* A task is a Promise object that is tracked by AntOS via the
|
||||
* Announcerment system
|
||||
*
|
||||
* Task manager implementation can subscribe to the following global events
|
||||
* - ANTOS-TASK-PENDING : a new task/promise is created and executing
|
||||
* - ANTOS-TASK-FULFILLED: a fullfilled task is a resolved promise
|
||||
* - ANTOS-TASK-REJECTED: a rejected task is a rejected or error promise
|
||||
*
|
||||
* Whenever a task is created by this API, it states will be automatically announced
|
||||
* to any subscribers of these events
|
||||
*
|
||||
* @export
|
||||
* @returns {number}
|
||||
* @param {Promise} a Promise object
|
||||
*/
|
||||
export function mid(): number {
|
||||
return announcer.getMID();
|
||||
export function Task(fn: ( resolve: (any)=>void,reject:(any)=>void) => void ): Promise<any>
|
||||
{
|
||||
return new Promise(async (ok,nok) =>{
|
||||
const promise = new Promise(fn);
|
||||
const ann:API.AnnouncementDataType<Promise<any>> = {} as API.AnnouncementDataType<Promise<any>>;
|
||||
ann.name = "OS";
|
||||
ann.u_data = promise;
|
||||
ann.id = Math.floor(Math.random() * 1e6);
|
||||
try
|
||||
{
|
||||
ann.message = "ANTOS-TASK-PENDING";
|
||||
announcer.trigger(ann.message, ann);
|
||||
const data = await promise;
|
||||
ok(data);
|
||||
ann.message = "ANTOS-TASK-FULFILLED";
|
||||
announcer.trigger(ann.message, ann);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
ann.message = "ANTOS-TASK-REJECTED";
|
||||
announcer.trigger(ann.message, ann);
|
||||
nok(__e(e));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1205,9 +1234,7 @@ namespace OS {
|
||||
* @returns {Promise<any>} a promise on the result data
|
||||
*/
|
||||
export function post(p: string, d: any): Promise<any> {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const q = announcer.getMID();
|
||||
API.loading(q, p);
|
||||
return API.Task(function (resolve, reject) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: p,
|
||||
@ -1226,11 +1253,9 @@ namespace OS {
|
||||
success: null,
|
||||
})
|
||||
.done(function (data) {
|
||||
API.loaded(q, p, "OK");
|
||||
return resolve(data);
|
||||
})
|
||||
.fail(function (j, s, e) {
|
||||
API.loaded(q, p, "FAIL");
|
||||
return reject(API.throwe(s));
|
||||
});
|
||||
});
|
||||
@ -1248,21 +1273,17 @@ namespace OS {
|
||||
* @returns {Promise<ArrayBuffer>} a promise on the returned binary data
|
||||
*/
|
||||
export function blob(p: string): Promise<ArrayBuffer> {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const q = announcer.getMID();
|
||||
return API.Task(function (resolve, reject) {
|
||||
const r = new XMLHttpRequest();
|
||||
r.open("GET", p, true);
|
||||
r.responseType = "arraybuffer";
|
||||
r.onload = function (e) {
|
||||
if (this.status === 200 && this.readyState === 4) {
|
||||
API.loaded(q, p, "OK");
|
||||
resolve(this.response);
|
||||
} else {
|
||||
API.loaded(q, p, "FAIL");
|
||||
reject(API.throwe(__("Unable to get blob: {0}", p)));
|
||||
}
|
||||
};
|
||||
API.loading(q, p);
|
||||
r.send();
|
||||
});
|
||||
}
|
||||
@ -1278,8 +1299,7 @@ namespace OS {
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function upload(p: string, d: string): Promise<any> {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const q = announcer.getMID();
|
||||
return API.Task(function (resolve, reject) {
|
||||
//insert a temporal file selector
|
||||
const o =
|
||||
$("<input>")
|
||||
@ -1287,9 +1307,6 @@ namespace OS {
|
||||
.attr("multiple", "true");
|
||||
o.on("change", function () {
|
||||
const files = (o[0] as HTMLInputElement).files;
|
||||
const n_files = files.length;
|
||||
if (n_files > 0)
|
||||
API.loading(q, p);
|
||||
const formd = new FormData();
|
||||
formd.append("path", d);
|
||||
jQuery.each(files, (i, file) => {
|
||||
@ -1303,11 +1320,9 @@ namespace OS {
|
||||
processData: false,
|
||||
})
|
||||
.done(function (data) {
|
||||
API.loaded(q, p, "OK");
|
||||
resolve(data);
|
||||
})
|
||||
.fail(function (j, s, e) {
|
||||
API.loaded(q, p, "FAIL");
|
||||
o.remove();
|
||||
reject(API.throwe(s));
|
||||
});
|
||||
@ -1337,44 +1352,6 @@ namespace OS {
|
||||
o.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to trigger the global `loading`
|
||||
* event. This event should be triggered in the
|
||||
* beginning of a heavy task
|
||||
*
|
||||
* @export
|
||||
* @param {number} q message id, see {@link mid}
|
||||
* @param {string} p message string
|
||||
*/
|
||||
export function loading(q: number, p: string): void {
|
||||
const data: API.AnnouncementDataType<number> = {} as API.AnnouncementDataType<number>;
|
||||
data.id = q;
|
||||
data.message = p;
|
||||
data.name = p;
|
||||
data.u_data = 0; //PM.pidactive;
|
||||
announcer.trigger("loading", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to trigger the global `loaded`
|
||||
* event: This event should be triggered in the
|
||||
* end of a heavy task that has previously triggered
|
||||
* the `loading` event
|
||||
*
|
||||
* @export
|
||||
* @param {number} q the message id of the corresponding `loading` event
|
||||
* @param {string} p the message string
|
||||
* @param {string} m message status (`OK` of `FAIL`)
|
||||
*/
|
||||
export function loaded(q: number, p: string, m: string): void {
|
||||
const data: API.AnnouncementDataType<boolean> = {} as API.AnnouncementDataType<boolean>;
|
||||
data.id = q;
|
||||
data.message = p;
|
||||
data.name = "OS";
|
||||
data.u_data = false;
|
||||
announcer.trigger("loaded", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an REST GET request
|
||||
*
|
||||
@ -1388,7 +1365,7 @@ namespace OS {
|
||||
* @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) {
|
||||
return API.Task(function (resolve, reject) {
|
||||
const conf: any = {
|
||||
type: "GET",
|
||||
url: p,
|
||||
@ -1396,15 +1373,11 @@ namespace OS {
|
||||
if (t) {
|
||||
conf.dataType = t;
|
||||
}
|
||||
const q = announcer.getMID();
|
||||
API.loading(q, p);
|
||||
return $.ajax(conf)
|
||||
.done(function (data) {
|
||||
API.loaded(q, p, "OK");
|
||||
return resolve(data);
|
||||
})
|
||||
.fail(function (j, s, e) {
|
||||
API.loaded(q, p, "FAIL");
|
||||
return reject(API.throwe(s));
|
||||
});
|
||||
});
|
||||
|
@ -34,10 +34,10 @@ namespace OS {
|
||||
* Store pending loading task
|
||||
*
|
||||
* @private
|
||||
* @type {number[]}
|
||||
* @type {Promise<any>[]}
|
||||
* @memberof SystemPanelTag
|
||||
*/
|
||||
private _pending_task: number[];
|
||||
private _pending_task: Promise<any>[];
|
||||
|
||||
/**
|
||||
* Flag indicate where the selected application shall be openned
|
||||
@ -519,17 +519,13 @@ namespace OS {
|
||||
this.refs.osmenu.contextmenuHandle = (e, m) => { };
|
||||
systray.contextmenuHandle = (e, m) => { };
|
||||
this.refs.panel.contextmenuHandle = (e, m) => { };
|
||||
announcer.on("loading", (o: API.AnnouncementDataType<number>) => {
|
||||
if(o.u_data != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
announcer.on("ANTOS-TASK-PENDING", (o: API.AnnouncementDataType<Promise<any>>) => {
|
||||
if(this._pending_task.length == 0)
|
||||
{
|
||||
$(this.refs.panel).addClass("loading");
|
||||
systray.iconclass = "fa-spin fa fa-cog";
|
||||
}
|
||||
this._pending_task.push(o.id);
|
||||
this._pending_task.push(o.u_data);
|
||||
|
||||
$(GUI.workspace).css("cursor", "wait");
|
||||
});
|
||||
@ -538,8 +534,8 @@ namespace OS {
|
||||
e.data.stopPropagation();
|
||||
this.show_systray();
|
||||
};
|
||||
announcer.on("loaded", (o: API.AnnouncementDataType<number>) => {
|
||||
const i = this._pending_task.indexOf(o.id);
|
||||
const remove_task = (o: Promise<any>) => {
|
||||
const i = this._pending_task.indexOf(o);
|
||||
if (i >= 0) {
|
||||
this._pending_task.splice(i, 1);
|
||||
}
|
||||
@ -549,7 +545,15 @@ namespace OS {
|
||||
if(!this._loading_toh)
|
||||
this._loading_toh = setTimeout(() => this.animation_check(),1000);
|
||||
}
|
||||
};
|
||||
announcer.on("ANTOS-TASK-FULFILLED", (o: API.AnnouncementDataType<Promise<any>>) => {
|
||||
remove_task(o.u_data);
|
||||
});
|
||||
|
||||
announcer.on("ANTOS-TASK-REJECTED", (o: API.AnnouncementDataType<Promise<any>>) => {
|
||||
remove_task(o.u_data);
|
||||
});
|
||||
|
||||
announcer.on("desktopresize", (e) => {
|
||||
this.calibrate();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user