mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 08:38:54 +01:00
Swap Promise for jQuery.Promise in loadingFinished() & doLoadingFinished()
This lets us add LitElement's updateComplete Promise into the list of things to wait for, and solves the problem of app init code being run before widgets are complete. https://lit.dev/docs/components/lifecycle/#reactive-update-cycle-completing
This commit is contained in:
parent
1b74f1f1a7
commit
f7f4053d1a
@ -394,6 +394,17 @@ const Et2WidgetMixin = (superClass) =>
|
||||
return this.classList.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the widget class
|
||||
*
|
||||
* @deprecated Use this.class or this.classList instead
|
||||
* @param {string} new_class
|
||||
*/
|
||||
set_class(new_class : string)
|
||||
{
|
||||
this.class = new_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handlers
|
||||
*/
|
||||
@ -771,8 +782,9 @@ const Et2WidgetMixin = (superClass) =>
|
||||
child.loadingFinished(promises);
|
||||
}
|
||||
};
|
||||
|
||||
doLoadingFinished();
|
||||
|
||||
promises.push(this.getUpdateComplete());
|
||||
}
|
||||
|
||||
getWidgetById(_id)
|
||||
|
@ -18,14 +18,8 @@ import {ClassWithAttributes} from './et2_core_inheritance';
|
||||
import {et2_IDOMNode} from "./et2_core_interfaces";
|
||||
import {et2_hasChild, et2_no_init} from "./et2_core_common";
|
||||
import {et2_widget, WidgetConfig} from "./et2_core_widget";
|
||||
import {
|
||||
egw_getActionManager,
|
||||
egwActionObject,
|
||||
egwActionObjectInterface,
|
||||
egw_getAppObjectManager,
|
||||
egw_getObjectManager
|
||||
} from '../egw_action/egw_action.js';
|
||||
import {EGW_AI_DRAG_OVER, EGW_AI_DRAG_OUT} from '../egw_action/egw_action_constants.js';
|
||||
import {egw_getActionManager, egw_getAppObjectManager, egw_getObjectManager} from '../egw_action/egw_action.js';
|
||||
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER} from '../egw_action/egw_action_constants.js';
|
||||
import {egw} from "../jsapi/egw_global";
|
||||
// fixing circular dependencies by only importing type
|
||||
import type {et2_tabbox} from "./et2_widget_tabs";
|
||||
@ -170,7 +164,7 @@ export abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode
|
||||
/**
|
||||
* Attaches the container node of this widget to the DOM-Tree
|
||||
*/
|
||||
doLoadingFinished() : boolean | JQueryPromise<unknown>
|
||||
doLoadingFinished() : boolean | Promise<any>
|
||||
{
|
||||
// Check whether the parent implements the et2_IDOMNode interface. If
|
||||
// yes, grab the DOM node and create our own.
|
||||
|
@ -18,7 +18,7 @@ import {et2_no_init} from "./et2_core_common";
|
||||
import {ClassWithAttributes} from "./et2_core_inheritance";
|
||||
import {et2_widget, WidgetConfig} from "./et2_core_widget";
|
||||
import {et2_valueWidget} from './et2_core_valueWidget'
|
||||
import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "./et2_core_interfaces";
|
||||
import {et2_IInput, et2_ISubmitListener} from "./et2_core_interfaces";
|
||||
import {et2_compileLegacyJS} from "./et2_core_legacyJSFunctions";
|
||||
// fixing circular dependencies by only importing the type (not in compiled .js)
|
||||
import type {et2_tabbox} from "./et2_widget_tabs";
|
||||
@ -107,7 +107,7 @@ export class et2_inputWidget extends et2_valueWidget implements et2_IInput, et2_
|
||||
/**
|
||||
* Make sure dirty flag is properly set
|
||||
*/
|
||||
doLoadingFinished(): boolean | JQueryPromise<unknown>
|
||||
doLoadingFinished() : boolean | Promise<unknown>
|
||||
{
|
||||
let result = super.doLoadingFinished();
|
||||
|
||||
|
@ -900,12 +900,12 @@ export class et2_widget extends ClassWithAttributes
|
||||
};
|
||||
|
||||
var result = this.doLoadingFinished();
|
||||
if (typeof result == "boolean" && result)
|
||||
if(typeof result == "boolean" && result)
|
||||
{
|
||||
// Simple widget finishes nicely
|
||||
loadChildren.apply(this, arguments);
|
||||
}
|
||||
else if (typeof result == "object" && result.done)
|
||||
else if(typeof result == "object" && result.then)
|
||||
{
|
||||
// Warn if list was not provided
|
||||
if (warn_if_deferred)
|
||||
@ -916,7 +916,7 @@ export class et2_widget extends ClassWithAttributes
|
||||
// Widget is waiting. Add to the list
|
||||
promises.push(result);
|
||||
// Fihish loading when it's finished
|
||||
result.done(jQuery.proxy(loadChildren, this));
|
||||
result.then(loadChildren.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
@ -956,9 +956,9 @@ export class et2_widget extends ClassWithAttributes
|
||||
* @return {boolean|Promise} True if the widget is fully loaded, false to avoid procesing children,
|
||||
* or a Promise if loading is not actually finished (eg. waiting for AJAX)
|
||||
*
|
||||
* @see {@link http://api.jquery.com/deferred.promise/|jQuery Promise}
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Promise}
|
||||
*/
|
||||
doLoadingFinished(): JQueryPromise<any> | boolean
|
||||
doLoadingFinished() : Promise<any> | boolean
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -41,7 +41,13 @@
|
||||
*/
|
||||
|
||||
import {et2_csvSplit, et2_no_init} from "./et2_core_common";
|
||||
import {et2_IInput, et2_IPrint, et2_IResizeable, implements_methods, et2_implements_registry} from "./et2_core_interfaces";
|
||||
import {
|
||||
et2_IInput,
|
||||
et2_implements_registry,
|
||||
et2_IPrint,
|
||||
et2_IResizeable,
|
||||
implements_methods
|
||||
} from "./et2_core_interfaces";
|
||||
import {ClassWithAttributes} from "./et2_core_inheritance";
|
||||
import {et2_createWidget, et2_register_widget, et2_widget, WidgetConfig} from "./et2_core_widget";
|
||||
import {et2_DOMWidget} from "./et2_core_DOMWidget";
|
||||
@ -292,6 +298,12 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
||||
row_selector: '',
|
||||
orientation_style: null
|
||||
};
|
||||
/**
|
||||
* When loading the row template, we have to wait for the template before we try to process it.
|
||||
* During the legacy load process, we need to return this from doLoadingFinished() so it can be waited on so we
|
||||
* have to store it.
|
||||
*/
|
||||
private template_promise : Promise<void>;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -497,8 +509,7 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
||||
this.controller._grid.doInvalidate = true;
|
||||
}
|
||||
}, this));
|
||||
|
||||
return true;
|
||||
return this.template_promise ? this.template_promise : true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2521,8 +2532,8 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
||||
template.loadingFinished(promise);
|
||||
|
||||
// Wait until template (& children) are done
|
||||
jQuery.when.apply(null, promise).done(
|
||||
jQuery.proxy(function()
|
||||
// Keep promise so we can return it from doLoadingFinished
|
||||
this.template_promise = Promise.all(promise).then(() =>
|
||||
{
|
||||
parse.call(this, template);
|
||||
if(!this.dynheight)
|
||||
@ -2531,9 +2542,10 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
||||
}
|
||||
this.dynheight.initialized = false;
|
||||
this.resize();
|
||||
}, this)
|
||||
);
|
||||
return promise;
|
||||
}
|
||||
).finally(() => this.template_promise = null);
|
||||
|
||||
return this.template_promise;
|
||||
}
|
||||
|
||||
// Some accessors to match conventions
|
||||
|
@ -112,7 +112,7 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
||||
this.options.status_id = _new_id;
|
||||
}
|
||||
|
||||
doLoadingFinished( ) : boolean | JQueryPromise<unknown>
|
||||
doLoadingFinished() : boolean | Promise<unknown>
|
||||
{
|
||||
super.doLoadingFinished();
|
||||
|
||||
@ -121,7 +121,8 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
||||
if(tab)
|
||||
{
|
||||
// Bind the action to when the tab is selected
|
||||
const handler = function (e) {
|
||||
const handler = function(e)
|
||||
{
|
||||
e.data.div.unbind("click.history");
|
||||
// Bind on click tap, because we need to update history size
|
||||
// after a rezise happend and history log was not the active tab
|
||||
|
@ -14,10 +14,9 @@
|
||||
et2_core_valueWidget;
|
||||
*/
|
||||
|
||||
import { ClassWithAttributes } from "./et2_core_inheritance";
|
||||
import { et2_widget, et2_createWidget, et2_register_widget, WidgetConfig } from "./et2_core_widget";
|
||||
import { et2_DOMWidget } from './et2_core_DOMWidget'
|
||||
import { et2_valueWidget } from './et2_core_valueWidget'
|
||||
import {ClassWithAttributes} from "./et2_core_inheritance";
|
||||
import {et2_createWidget, et2_register_widget, et2_widget, WidgetConfig} from "./et2_core_widget";
|
||||
import {et2_valueWidget} from './et2_core_valueWidget'
|
||||
import {et2_nextmatch} from "./et2_extension_nextmatch";
|
||||
import {et2_no_init} from "./et2_core_common";
|
||||
import {et2_IInput, et2_IPrint, et2_IResizeable} from "./et2_core_interfaces";
|
||||
@ -26,7 +25,7 @@ import {et2_directChildrenByTagName, et2_filteredNodeIterator, et2_readAttrWithD
|
||||
/**
|
||||
* Class which implements the tabbox-tag
|
||||
*/
|
||||
export class et2_tabbox extends et2_valueWidget implements et2_IInput,et2_IResizeable,et2_IPrint
|
||||
export class et2_tabbox extends et2_valueWidget implements et2_IInput, et2_IResizeable, et2_IPrint
|
||||
{
|
||||
static readonly _attributes : any = {
|
||||
'tabs': {
|
||||
@ -252,15 +251,17 @@ export class et2_tabbox extends et2_valueWidget implements et2_IInput,et2_IResiz
|
||||
*/
|
||||
doLoadingFinished()
|
||||
{
|
||||
var tab_deferred = jQuery.Deferred();
|
||||
var promises = [];
|
||||
var tabs = this;
|
||||
|
||||
// Specially process the selected index so it shows up right away
|
||||
this._loadTab(this.selected_index,promises);
|
||||
this._loadTab(this.selected_index, promises);
|
||||
|
||||
// Avoid reloading if tabs were modified by data
|
||||
if(this.isInTree() && this.isAttached()) return;
|
||||
if(this.isInTree() && this.isAttached())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply parent now, which actually puts into the DOM
|
||||
// This has to be before loading the child, so the dom sub-tree is not
|
||||
@ -271,20 +272,27 @@ export class et2_tabbox extends et2_valueWidget implements et2_IInput,et2_IResiz
|
||||
// which has special handling
|
||||
this._children[0].loadingFinished(promises);
|
||||
|
||||
// Defer parsing & loading of other tabs until later
|
||||
window.setTimeout(function() {
|
||||
for (var i = 0; i < tabs.tabData.length; i++)
|
||||
let tab_deferred = new Promise<any>((resolve, reject) =>
|
||||
{
|
||||
// Defer parsing & loading of other tabs until later
|
||||
window.setTimeout(function()
|
||||
{
|
||||
if (i == tabs.selected_index) continue;
|
||||
tabs._loadTab(i,promises);
|
||||
}
|
||||
jQuery.when.apply(jQuery,promises).then(function() {
|
||||
tab_deferred.resolve();
|
||||
tabs.resetDirty();
|
||||
});
|
||||
},0);
|
||||
|
||||
return tab_deferred.promise();
|
||||
for(var i = 0; i < tabs.tabData.length; i++)
|
||||
{
|
||||
if(i == tabs.selected_index)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tabs._loadTab(i, promises);
|
||||
}
|
||||
Promise.all(promises).then(function()
|
||||
{
|
||||
resolve();
|
||||
tabs.resetDirty();
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
return tab_deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,9 +72,9 @@ export class et2_template extends et2_DOMWidget
|
||||
}
|
||||
};
|
||||
|
||||
content: string;
|
||||
div: HTMLDivElement;
|
||||
loading: JQueryDeferred<unknown>;
|
||||
content : string;
|
||||
div : HTMLDivElement;
|
||||
loading : Promise<any>;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -94,66 +94,78 @@ export class et2_template extends et2_DOMWidget
|
||||
this.div = document.createElement("div");
|
||||
|
||||
// Deferred object so we can load via AJAX
|
||||
this.loading = jQuery.Deferred();
|
||||
|
||||
// run transformAttributes now, to get server-side modifications (url!)
|
||||
if (_attrs.template)
|
||||
this.loading = new Promise<any>((resolve, reject) =>
|
||||
{
|
||||
this.id = _attrs.template;
|
||||
this.transformAttributes(_attrs);
|
||||
this.options = et2_cloneObject(_attrs);
|
||||
_attrs = {};
|
||||
}
|
||||
if (this.id != "" || this.options.template)
|
||||
{
|
||||
var parts = (this.options.template || this.id).split('?');
|
||||
var cache_buster = parts.length > 1 ? parts.pop() : null;
|
||||
var template_name = parts.pop();
|
||||
|
||||
// Check to see if XML is known
|
||||
var xml = null;
|
||||
var templates = etemplate2.templates; // use global eTemplate cache
|
||||
if(!(xml = templates[template_name]))
|
||||
// run transformAttributes now, to get server-side modifications (url!)
|
||||
if(_attrs.template)
|
||||
{
|
||||
// Check to see if ID is short form --> prepend parent/top-level name
|
||||
if(template_name.indexOf('.') < 0)
|
||||
this.id = _attrs.template;
|
||||
this.transformAttributes(_attrs);
|
||||
this.options = et2_cloneObject(_attrs);
|
||||
_attrs = {};
|
||||
}
|
||||
if(this.id != "" || this.options.template)
|
||||
{
|
||||
var parts = (this.options.template || this.id).split('?');
|
||||
var cache_buster = parts.length > 1 ? parts.pop() : null;
|
||||
var template_name = parts.pop();
|
||||
|
||||
// Check to see if XML is known
|
||||
var xml = null;
|
||||
var templates = etemplate2.templates; // use global eTemplate cache
|
||||
if(!(xml = templates[template_name]))
|
||||
{
|
||||
var root = _parent ? _parent.getRoot() : null;
|
||||
var top_name = root && root._inst ? root._inst.name : null;
|
||||
if (top_name && template_name.indexOf('.') < 0) template_name = top_name+'.'+template_name;
|
||||
}
|
||||
xml = templates[template_name];
|
||||
if(!xml)
|
||||
{
|
||||
// Ask server
|
||||
var url = this.options.url;
|
||||
if (!this.options.url)
|
||||
// Check to see if ID is short form --> prepend parent/top-level name
|
||||
if(template_name.indexOf('.') < 0)
|
||||
{
|
||||
var splitted = template_name.split('.');
|
||||
var app = splitted.shift();
|
||||
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
||||
url = this.getRoot()._inst.template_base_url + app + "/templates/default/" +
|
||||
splitted.join('.')+ ".xet" + (cache_buster ? '?download='+cache_buster : '');
|
||||
var root = _parent ? _parent.getRoot() : null;
|
||||
var top_name = root && root._inst ? root._inst.name : null;
|
||||
if(top_name && template_name.indexOf('.') < 0)
|
||||
{
|
||||
template_name = top_name + '.' + template_name;
|
||||
}
|
||||
}
|
||||
// if server did not give a cache-buster, fall back to current time
|
||||
xml = templates[template_name];
|
||||
if(!xml)
|
||||
{
|
||||
// Ask server
|
||||
var url = this.options.url;
|
||||
if(!this.options.url)
|
||||
{
|
||||
var splitted = template_name.split('.');
|
||||
var app = splitted.shift();
|
||||
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
||||
url = this.getRoot()._inst.template_base_url + app + "/templates/default/" +
|
||||
splitted.join('.') + ".xet" + (cache_buster ? '?download=' + cache_buster : '');
|
||||
}
|
||||
// if server did not give a cache-buster, fall back to current time
|
||||
if (url.indexOf('?') == -1) url += '?download='+(new Date).valueOf();
|
||||
|
||||
if(this.options.url || splitted.length)
|
||||
{
|
||||
var fetch_url_callback = function(_xmldoc) {
|
||||
var fetch_url_callback = function(_xmldoc)
|
||||
{
|
||||
// Scan for templates and store them
|
||||
for(var i = 0; i < _xmldoc.childNodes.length; i++) {
|
||||
for(var i = 0; i < _xmldoc.childNodes.length; i++)
|
||||
{
|
||||
var template = _xmldoc.childNodes[i];
|
||||
if(template.nodeName.toLowerCase() != "template") continue;
|
||||
if(template.nodeName.toLowerCase() != "template")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
templates[template.getAttribute("id")] = template;
|
||||
}
|
||||
|
||||
// Read the XML structure of the requested template
|
||||
if (typeof templates[template_name] != 'undefined') this.loadFromXML(templates[template_name]);
|
||||
if(typeof templates[template_name] != 'undefined')
|
||||
{
|
||||
this.loadFromXML(templates[template_name]);
|
||||
}
|
||||
|
||||
// Update flag
|
||||
this.loading.resolve();
|
||||
};
|
||||
resolve();
|
||||
}.bind(this);
|
||||
|
||||
et2_loadXMLFromURL(url, fetch_url_callback, this, function( error) {
|
||||
url = egw.link('/'+ app + "/templates/default/" +
|
||||
@ -173,19 +185,20 @@ export class et2_template extends et2_DOMWidget
|
||||
//this.loadingFinished();
|
||||
|
||||
// But resolve the promise
|
||||
this.loading.resolve();
|
||||
resolve();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.egw().debug("warn", "Unable to find XML for ", template_name);
|
||||
this.loading.reject();
|
||||
reject()
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No actual template
|
||||
this.loading.resolve();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No actual template
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,10 +265,10 @@ export class et2_template extends et2_DOMWidget
|
||||
super.doLoadingFinished();
|
||||
|
||||
// Fire load event when done loading
|
||||
this.loading.done(jQuery.proxy(function() {jQuery(this).trigger("load");},this.div));
|
||||
this.loading.then(function() {jQuery(this).trigger("load");}.bind(this.div));
|
||||
|
||||
// Not done yet, but widget will let you know
|
||||
return this.loading.promise();
|
||||
return this.loading;
|
||||
}
|
||||
}
|
||||
et2_register_widget(et2_template, ["template"]);
|
||||
|
@ -638,24 +638,9 @@ export class etemplate2
|
||||
{
|
||||
egw.window.console.groupEnd();
|
||||
}
|
||||
if(deferred.length > 0)
|
||||
{
|
||||
let still_deferred = 0;
|
||||
jQuery(deferred).each(function()
|
||||
{
|
||||
if(this.state() == "pending")
|
||||
{
|
||||
still_deferred++;
|
||||
}
|
||||
});
|
||||
if(still_deferred > 0)
|
||||
{
|
||||
egw.debug("log", "Template loaded, waiting for %d/%d deferred to finish...", still_deferred, deferred.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for everything to be loaded, then finish it up
|
||||
jQuery.when.apply(jQuery, deferred).done(jQuery.proxy(function()
|
||||
Promise.all(deferred).then(() =>
|
||||
{
|
||||
egw.debug("log", "Finished loading %s, triggering load event", _name);
|
||||
|
||||
@ -736,7 +721,7 @@ export class etemplate2
|
||||
gen_time_div.find('.et2RenderTime').remove();
|
||||
gen_time_div.append('<span class="et2RenderTime">' + egw.lang('eT2 rendering took %1s', '' + ((end_time - start_time) / 1000)) + '</span>');
|
||||
}
|
||||
}, this));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user