forked from extern/egroupware
Use jQuery's Deferred to solve the deferred loading problem instead of load events.
This commit is contained in:
parent
f10fc199a0
commit
4002907c05
@ -730,26 +730,68 @@ var et2_widget = Class.extend(
|
||||
* function is called, the DOM-Tree is created. loadingFinished is
|
||||
* recursively called for all child elements. Do not directly override this
|
||||
* function but the doLoadingFinished function which is executed before
|
||||
* descending deeper into the DOM-Tree
|
||||
* descending deeper into the DOM-Tree.
|
||||
*
|
||||
* Some widgets (template) do not load immediately because they request
|
||||
* additional resources via AJAX. They will return a Deferred Promise object.
|
||||
* If you call loadingFinished(promises) after creating such a widget
|
||||
* programmatically, you might need to wait for it to fully complete its
|
||||
* loading before proceeding. In that case use:
|
||||
* <code>
|
||||
* var promises = [];
|
||||
* widget.loadingFinished(promises);
|
||||
* jQuery.when.apply(null, promises).done( doneCallback );
|
||||
* </code>
|
||||
* @see {@link http://api.jquery.com/category/deferred-object/|jQuery Deferred}
|
||||
*
|
||||
* @param {Promise[]} promises List of promises from widgets that are not done. Pass an empty array, it will be filled if needed.
|
||||
*/
|
||||
loadingFinished: function() {
|
||||
loadingFinished: function(promises) {
|
||||
// Call all availble setters
|
||||
this.initAttributes(this.options);
|
||||
|
||||
// Make sure promises is defined to avoid errors.
|
||||
// We'll warn (below) if programmer should have passed it.
|
||||
if(typeof promises == "undefined")
|
||||
{
|
||||
promises = [];
|
||||
var warn_if_deferred = true;
|
||||
}
|
||||
|
||||
if (this.doLoadingFinished())
|
||||
var loadChildren = function()
|
||||
{
|
||||
// Descend recursively into the tree
|
||||
for (var i = 0; i < this._children.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
this._children[i].loadingFinished();
|
||||
this._children[i].loadingFinished(promises);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
egw.debug("error", "There was an error with a widget:\nError:%o\nProblem widget:%o",e.valueOf(),this._children[i],e.stack);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = this.doLoadingFinished();
|
||||
if(typeof result == "boolean" && result)
|
||||
{
|
||||
// Simple widget finishes nicely
|
||||
loadChildren.apply(this, arguments);
|
||||
}
|
||||
else if (typeof result == "object" && result.done)
|
||||
{
|
||||
// Warn if list was not provided
|
||||
if(warn_if_deferred)
|
||||
{
|
||||
// Might not be a problem, but if you need the widget to be really loaded, it could be
|
||||
egw.debug("warning", "Loading was deferred for widget %o, but creator is not checking. Pass a list to loadingFinished().");
|
||||
}
|
||||
// Widget is waiting. Add to the list
|
||||
promises.push(result);
|
||||
// Fihish loading when it's finished
|
||||
result.done(jQuery.proxy(loadChildren, this));
|
||||
}
|
||||
},
|
||||
|
||||
@ -779,6 +821,15 @@ var et2_widget = Class.extend(
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Does specific post-processing after the widget is loaded. Most widgets should not
|
||||
* need to do anything here, it should all be done before.
|
||||
*
|
||||
* @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}
|
||||
*/
|
||||
doLoadingFinished: function() {
|
||||
return true;
|
||||
},
|
||||
|
@ -1205,7 +1205,7 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
{
|
||||
// Keep the name of the template, as we'll free up the widget after parsing
|
||||
this.template = _value;
|
||||
template.loadingFinished();
|
||||
|
||||
// Fetch the grid element and parse it
|
||||
var definitionGrid = template.getChildren()[0];
|
||||
if (definitionGrid && definitionGrid instanceof et2_grid)
|
||||
@ -1242,7 +1242,11 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
};
|
||||
|
||||
// Template might not be loaded yet, defer parsing
|
||||
$j(template.getDOMNode()).on("load",
|
||||
var promise = []
|
||||
template.loadingFinished(promise);
|
||||
|
||||
// Wait until template (& children) are done
|
||||
jQuery.when.apply(null, promise).done(
|
||||
jQuery.proxy(function() {
|
||||
parse.call(this, template);
|
||||
this.dynheight.initialized = false;
|
||||
@ -1656,7 +1660,7 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader,
|
||||
_build_left_right: function(left_or_right, template_name)
|
||||
{
|
||||
var existing = this.headers[left_or_right == "left" ? 0 : 1];
|
||||
if(existing)
|
||||
if(existing && existing._type)
|
||||
{
|
||||
if(existing.id == template_name) return;
|
||||
existing.free();
|
||||
@ -1666,11 +1670,12 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader,
|
||||
// Load the template
|
||||
var header = et2_createWidget("template", {"id": template_name}, this);
|
||||
jQuery(header.getDOMNode()).addClass(left_or_right == "left" ? "et2_hbox_left":"et2_hbox_right").addClass("nm_header");
|
||||
this.headers.push(header);
|
||||
this.headers[left_or_right == "left" ? 0 : 1] = header;
|
||||
$j(header.getDOMNode()).on("load", jQuery.proxy(function() {
|
||||
header.loadingFinished();
|
||||
//header.loadingFinished();
|
||||
this._bindHeaderInput(header);
|
||||
},this));
|
||||
header.loadingFinished();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1873,9 +1878,12 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader,
|
||||
return this.filters[0];
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < this.headers.length; i++)
|
||||
if(_sender && _sender._type == "template")
|
||||
{
|
||||
if(_sender.id == this.headers[i].id && _sender._parent == this) return this.header_div[0];
|
||||
for(var i = 0; i < this.headers.length; i++)
|
||||
{
|
||||
if(_sender.id == this.headers[i].id && _sender._parent == this) return this.header_div[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
@ -77,8 +77,8 @@ var et2_template = et2_DOMWidget.extend(
|
||||
|
||||
this.div = document.createElement("div");
|
||||
|
||||
// Flag to indicate that loading is finished
|
||||
this.loading = false;
|
||||
// Deferred object so we can load via AJAX
|
||||
this.loading = jQuery.Deferred();
|
||||
|
||||
if (this.id != "" || this.options.template)
|
||||
{
|
||||
@ -108,8 +108,6 @@ var et2_template = et2_DOMWidget.extend(
|
||||
|
||||
if(splitted.length)
|
||||
{
|
||||
// Still loading, don't fire loading finished
|
||||
this.loading = true;
|
||||
et2_loadXMLFromURL(path, function(_xmldoc) {
|
||||
var templates = this.getInstanceManager().templates || {};
|
||||
// Scan for templates and store them
|
||||
@ -123,13 +121,7 @@ var et2_template = et2_DOMWidget.extend(
|
||||
this.loadFromXML(templates[template_name]);
|
||||
|
||||
// Update flag
|
||||
this.loading = false;
|
||||
|
||||
// Fire the load event (after)
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
$j(self.getDOMNode()).trigger('load');
|
||||
},0);
|
||||
this.loading.resolve();
|
||||
|
||||
}, this);
|
||||
}
|
||||
@ -140,17 +132,16 @@ var et2_template = et2_DOMWidget.extend(
|
||||
{
|
||||
this.egw().debug("log", "Loading template from XML: ", template_name);
|
||||
this.loadFromXML(xml);
|
||||
// Don't call this here - premature
|
||||
// Don't call this here - done by caller, or on whole widget tree
|
||||
//this.loadingFinished();
|
||||
// Fire the load event (after)
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
$j(self.getDOMNode()).trigger('load');
|
||||
},0);
|
||||
|
||||
// But resolve the promise
|
||||
this.loading.resolve();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.egw().debug("warn", "Unable to find XML for ", template_name);
|
||||
this.loading.reject();
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -175,13 +166,17 @@ var et2_template = et2_DOMWidget.extend(
|
||||
},
|
||||
|
||||
/**
|
||||
* Override to trigger a load event, to facilitate processing when the xml file
|
||||
* is loaded asyncronously
|
||||
* Override to return the promise for deferred loading
|
||||
*/
|
||||
doLoadingFinished: function() {
|
||||
if(this.loading) return false;
|
||||
// Apply parent now, which actually puts into the DOM
|
||||
this._super.apply(this, arguments);
|
||||
return true;
|
||||
|
||||
// Fire load event when done loading
|
||||
this.loading.done(jQuery.proxy(function() {$j(this).trigger("load");},this.div));
|
||||
|
||||
// Not done yet, but widget will let you know
|
||||
return this.loading.promise();
|
||||
}
|
||||
});
|
||||
et2_register_widget(et2_template, ["template"]);
|
||||
|
@ -245,8 +245,11 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
|
||||
// Read the XML structure of the requested template
|
||||
this.widgetContainer.loadFromXML(this.templates[_name || missing_name]);
|
||||
|
||||
// List of Promises from widgets that are not quite fully loaded
|
||||
var deferred = [];
|
||||
|
||||
// Inform the widget tree that it has been successfully loaded.
|
||||
this.widgetContainer.loadingFinished();
|
||||
this.widgetContainer.loadingFinished(deferred);
|
||||
|
||||
// Insert the document fragment to the DOM Container
|
||||
this.DOMContainer.appendChild(frag);
|
||||
@ -257,20 +260,24 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
|
||||
etemplate2._byTemplate[_name] = [];
|
||||
}
|
||||
etemplate2._byTemplate[_name].push(this);
|
||||
|
||||
// Trigger the "resize" event
|
||||
this.resize();
|
||||
|
||||
if(typeof _callback == "function")
|
||||
{
|
||||
_callback.call(window,this);
|
||||
}
|
||||
if(_callback != app_callback)
|
||||
{
|
||||
app_callback.call(window,this);
|
||||
}
|
||||
|
||||
$j(this.DOMContainer).trigger('load', this);
|
||||
|
||||
// Wait for everything to be loaded, then finish it up
|
||||
jQuery.when.apply(null, deferred).done(jQuery.proxy(function() {
|
||||
// Trigger the "resize" event
|
||||
this.resize();
|
||||
|
||||
// Tell others about it
|
||||
if(typeof _callback == "function")
|
||||
{
|
||||
_callback.call(window,this);
|
||||
}
|
||||
if(_callback != app_callback)
|
||||
{
|
||||
app_callback.call(window,this);
|
||||
}
|
||||
|
||||
$j(this.DOMContainer).trigger('load', this);
|
||||
},this));
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user