Commit b088ba59 authored by Romain Courteaud's avatar Romain Courteaud Committed by Eteri

[erp5_xhtml_style/erp5_web_renderjs_ui] Update renderJS 0.16.1

parent 7f272bb9
...@@ -1179,6 +1179,7 @@ if (typeof document.contains !== 'function') { ...@@ -1179,6 +1179,7 @@ if (typeof document.contains !== 'function') {
} }
this.__service_list.push(function () { this.__service_list.push(function () {
var queue_loop = new RSVP.Queue(), var queue_loop = new RSVP.Queue(),
context = this,
wait = function () { wait = function () {
queue_loop queue_loop
.push(function () { .push(function () {
...@@ -1189,7 +1190,7 @@ if (typeof document.contains !== 'function') { ...@@ -1189,7 +1190,7 @@ if (typeof document.contains !== 'function') {
return promiseAnimationFrame(); return promiseAnimationFrame();
}) })
.push(function () { .push(function () {
return callback.apply(this, []); return callback.apply(context, []);
}) })
.push(function () { .push(function () {
wait(); wait();
......
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>960.64345.32079.62088</string> </value> <value> <string>961.58176.38662.18807</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1502093855.2</float> <float>1505981711.78</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -749,6 +749,19 @@ if (typeof document.contains !== 'function') { ...@@ -749,6 +749,19 @@ if (typeof document.contains !== 'function') {
return new RSVP.Promise(itsANonResolvableTrap, canceller); return new RSVP.Promise(itsANonResolvableTrap, canceller);
} }
function promiseAnimationFrame() {
var request_id;
function canceller() {
window.cancelAnimationFrame(request_id);
}
function resolver(resolve) {
request_id = window.requestAnimationFrame(resolve);
}
return new RSVP.Promise(resolver, canceller);
}
function ajax(url) { function ajax(url) {
var xhr; var xhr;
function resolver(resolve, reject) { function resolver(resolve, reject) {
...@@ -793,13 +806,13 @@ if (typeof document.contains !== 'function') { ...@@ -793,13 +806,13 @@ if (typeof document.contains !== 'function') {
javascript_registration_dict = {}, javascript_registration_dict = {},
stylesheet_registration_dict = {}, stylesheet_registration_dict = {},
gadget_loading_klass_list = [], gadget_loading_klass_list = [],
loading_klass_promise,
renderJS, renderJS,
Monitor, Monitor,
scope_increment = 0, scope_increment = 0,
isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'), isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
is_page_unloaded = false, is_page_unloaded = false,
error_list = []; error_list = [],
all_dependency_loaded_deferred;
window.addEventListener('error', function (error) { window.addEventListener('error', function (error) {
error_list.push(error); error_list.push(error);
...@@ -1160,6 +1173,35 @@ if (typeof document.contains !== 'function') { ...@@ -1160,6 +1173,35 @@ if (typeof document.contains !== 'function') {
return this; return this;
}; };
RenderJSGadget.onLoop = function (callback, delay) {
if (delay === undefined) {
delay = 0;
}
this.__service_list.push(function () {
var queue_loop = new RSVP.Queue(),
context = this,
wait = function () {
queue_loop
.push(function () {
return RSVP.delay(delay);
})
.push(function () {
// Only loop when the app has the focus
return promiseAnimationFrame();
})
.push(function () {
return callback.apply(context, []);
})
.push(function () {
wait();
});
};
wait();
return queue_loop;
});
return this;
};
function runJob(gadget, name, callback, argument_list) { function runJob(gadget, name, callback, argument_list) {
var job_promise = new RSVP.Queue() var job_promise = new RSVP.Queue()
.push(function () { .push(function () {
...@@ -1265,36 +1307,53 @@ if (typeof document.contains !== 'function') { ...@@ -1265,36 +1307,53 @@ if (typeof document.contains !== 'function') {
return this.element; return this.element;
}) })
.declareMethod('changeState', function (state_dict) { .declareMethod('changeState', function (state_dict) {
var key, var next_onStateChange = new RSVP.Queue(),
modified = false, previous_onStateCHange,
previous_cancelled = this.hasOwnProperty('__modification_dict'),
modification_dict,
context = this; context = this;
if (previous_cancelled) { if (context.hasOwnProperty('__previous_onStateChange')) {
modification_dict = this.__modification_dict; previous_onStateCHange = context.__previous_onStateChange;
modified = true; next_onStateChange
} else {
modification_dict = {};
this.__modification_dict = modification_dict;
}
for (key in state_dict) {
if (state_dict.hasOwnProperty(key) &&
(state_dict[key] !== this.state[key])) {
this.state[key] = state_dict[key];
modification_dict[key] = state_dict[key];
modified = true;
}
}
if (modified && this.__state_change_callback !== undefined) {
return new RSVP.Queue()
.push(function () { .push(function () {
return context.__state_change_callback(modification_dict); return previous_onStateCHange;
}) })
.push(function (result) { .push(undefined, function () {
delete context.__modification_dict; // Run callback even if previous failed
return result; return;
}); });
} }
context.__previous_onStateChange = next_onStateChange;
return next_onStateChange
.push(function () {
var key,
modified = false,
previous_cancelled = context.hasOwnProperty('__modification_dict'),
modification_dict;
if (previous_cancelled) {
modification_dict = context.__modification_dict;
modified = true;
} else {
modification_dict = {};
}
for (key in state_dict) {
if (state_dict.hasOwnProperty(key) &&
(state_dict[key] !== context.state[key])) {
context.state[key] = state_dict[key];
modification_dict[key] = state_dict[key];
modified = true;
}
}
if (modified && context.__state_change_callback !== undefined) {
context.__modification_dict = modification_dict;
return new RSVP.Queue()
.push(function () {
return context.__state_change_callback(modification_dict);
})
.push(function (result) {
delete context.__modification_dict;
return result;
});
}
});
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1393,6 +1452,8 @@ if (typeof document.contains !== 'function') { ...@@ -1393,6 +1452,8 @@ if (typeof document.contains !== 'function') {
RenderJSGadget.declareService; RenderJSGadget.declareService;
RenderJSEmbeddedGadget.onEvent = RenderJSEmbeddedGadget.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
RenderJSEmbeddedGadget.onLoop =
RenderJSGadget.onLoop;
RenderJSEmbeddedGadget.prototype = new RenderJSGadget(); RenderJSEmbeddedGadget.prototype = new RenderJSGadget();
RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget; RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget;
...@@ -1456,6 +1517,8 @@ if (typeof document.contains !== 'function') { ...@@ -1456,6 +1517,8 @@ if (typeof document.contains !== 'function') {
RenderJSGadget.declareService; RenderJSGadget.declareService;
RenderJSIframeGadget.onEvent = RenderJSIframeGadget.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
RenderJSIframeGadget.onLoop =
RenderJSGadget.onLoop;
RenderJSIframeGadget.prototype = new RenderJSGadget(); RenderJSIframeGadget.prototype = new RenderJSGadget();
RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget; RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget;
...@@ -1504,7 +1567,8 @@ if (typeof document.contains !== 'function') { ...@@ -1504,7 +1567,8 @@ if (typeof document.contains !== 'function') {
// Create the communication channel with the iframe // Create the communication channel with the iframe
gadget_instance.__chan = Channel.build({ gadget_instance.__chan = Channel.build({
window: iframe.contentWindow, window: iframe.contentWindow,
origin: "*", // origin: (new URL(url, window.location)).origin,
origin: '*',
scope: "renderJS" scope: "renderJS"
}); });
...@@ -1519,12 +1583,8 @@ if (typeof document.contains !== 'function') { ...@@ -1519,12 +1583,8 @@ if (typeof document.contains !== 'function') {
params: [ params: [
method_name, method_name,
Array.prototype.slice.call(argument_list, 0)], Array.prototype.slice.call(argument_list, 0)],
success: function (s) { success: resolve,
resolve(s); error: reject
},
error: function (e) {
reject(e);
}
}); });
}); });
return new RSVP.Queue() return new RSVP.Queue()
...@@ -1825,6 +1885,8 @@ if (typeof document.contains !== 'function') { ...@@ -1825,6 +1885,8 @@ if (typeof document.contains !== 'function') {
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.onEvent = tmp_constructor.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
tmp_constructor.onLoop =
RenderJSGadget.onLoop;
tmp_constructor.prototype = new RenderJSGadget(); tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
...@@ -1857,9 +1919,6 @@ if (typeof document.contains !== 'function') { ...@@ -1857,9 +1919,6 @@ if (typeof document.contains !== 'function') {
gadget_model_defer_dict[url] = defer; gadget_model_defer_dict[url] = defer;
// Change the global variable to update the loading queue
loading_klass_promise = defer.promise;
// Fetch the HTML page and parse it // Fetch the HTML page and parse it
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
...@@ -1972,379 +2031,385 @@ if (typeof document.contains !== 'function') { ...@@ -1972,379 +2031,385 @@ if (typeof document.contains !== 'function') {
// Bootstrap process. Register the self gadget. // Bootstrap process. Register the self gadget.
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
function bootstrap() { // Detect when all JS dependencies have been loaded
var url = removeHash(window.location.href), all_dependency_loaded_deferred = new RSVP.defer();
TmpConstructor, // Manually initializes the self gadget if the DOMContentLoaded event
// is triggered before everything was ready.
// (For instance, the HTML-tag for the self gadget gets inserted after
// page load)
renderJS.manualBootstrap = function () {
all_dependency_loaded_deferred.resolve();
};
document.addEventListener('DOMContentLoaded',
all_dependency_loaded_deferred.resolve, false);
function configureMutationObserver(TmpConstructor, url, root_gadget) {
// XXX HTML properties can only be set when the DOM is fully loaded
var settings = renderJS.parseGadgetHTMLDocument(document, url),
j,
key,
fragment = document.createDocumentFragment();
for (key in settings) {
if (settings.hasOwnProperty(key)) {
TmpConstructor.prototype['__' + key] = settings[key];
}
}
TmpConstructor.__template_element = document.createElement("div");
root_gadget.element = document.body;
root_gadget.state = {};
for (j = 0; j < root_gadget.element.childNodes.length; j += 1) {
fragment.appendChild(
root_gadget.element.childNodes[j].cloneNode(true)
);
}
TmpConstructor.__template_element.appendChild(fragment);
return RSVP.all([root_gadget.getRequiredJSList(),
root_gadget.getRequiredCSSList()])
.then(function (all_list) {
var i,
js_list = all_list[0],
css_list = all_list[1];
for (i = 0; i < js_list.length; i += 1) {
javascript_registration_dict[js_list[i]] = null;
}
for (i = 0; i < css_list.length; i += 1) {
stylesheet_registration_dict[css_list[i]] = null;
}
gadget_loading_klass_list.shift();
}).then(function () {
// select the target node
var target = document.querySelector('body'),
// create an observer instance
observer = new MutationObserver(function (mutations) {
var i, k, len, len2, node, added_list;
mutations.forEach(function (mutation) {
if (mutation.type === 'childList') {
len = mutation.removedNodes.length;
for (i = 0; i < len; i += 1) {
node = mutation.removedNodes[i];
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.hasAttribute("data-gadget-url") &&
(node._gadget !== undefined)) {
createMonitor(node._gadget);
}
added_list =
node.querySelectorAll("[data-gadget-url]");
len2 = added_list.length;
for (k = 0; k < len2; k += 1) {
node = added_list[k];
if (node._gadget !== undefined) {
createMonitor(node._gadget);
}
}
}
}
len = mutation.addedNodes.length;
for (i = 0; i < len; i += 1) {
node = mutation.addedNodes[i];
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.hasAttribute("data-gadget-url") &&
(node._gadget !== undefined)) {
if (document.contains(node)) {
startService(node._gadget);
}
}
added_list =
node.querySelectorAll("[data-gadget-url]");
len2 = added_list.length;
for (k = 0; k < len2; k += 1) {
node = added_list[k];
if (document.contains(node)) {
if (node._gadget !== undefined) {
startService(node._gadget);
}
}
}
}
}
}
});
}),
// configuration of the observer:
config = {
childList: true,
subtree: true,
attributes: false,
characterData: false
};
// pass in the target node, as well as the observer options
observer.observe(target, config);
return root_gadget;
});
}
function createLastAcquisitionGadget() {
var last_acquisition_gadget = new RenderJSGadget();
last_acquisition_gadget.__acquired_method_dict = {
reportServiceError: function (param_list) {
letsCrash(param_list[0]);
}
};
// Stop acquisition on the last acquisition gadget
// Do not put this on the klass, as their could be multiple instances
last_acquisition_gadget.__aq_parent = function (method_name) {
throw new renderJS.AcquisitionError(
"No gadget provides " + method_name
);
};
return last_acquisition_gadget;
}
/*
function notifyAllMethodToParent() {
;
}
*/
function createLoadingGadget(url) {
var TmpConstructor,
root_gadget, root_gadget,
loading_gadget_promise = new RSVP.Queue(),
declare_method_count = 0,
embedded_channel, embedded_channel,
notifyReady,
notifyDeclareMethod, notifyDeclareMethod,
gadget_ready = false, declare_method_list_waiting,
iframe_top_gadget, loading_result,
last_acquisition_gadget, channel_defer,
declare_method_list_waiting = [], real_result_list;
gadget_failed = false, // gadget_failed = false,
gadget_error, // connection_ready = false;
connection_ready = false;
// Create the gadget class for the current url // Create the gadget class for the current url
if (gadget_model_defer_dict.hasOwnProperty(url)) { if (gadget_model_defer_dict.hasOwnProperty(url)) {
throw new Error("bootstrap should not be called twice"); throw new Error("bootstrap should not be called twice");
} }
loading_klass_promise = new RSVP.Promise(function (resolve, reject) {
last_acquisition_gadget = new RenderJSGadget();
last_acquisition_gadget.__acquired_method_dict = {
reportServiceError: function (param_list) {
letsCrash(param_list[0]);
}
};
// Stop acquisition on the last acquisition gadget
// Do not put this on the klass, as their could be multiple instances
last_acquisition_gadget.__aq_parent = function (method_name) {
throw new renderJS.AcquisitionError(
"No gadget provides " + method_name
);
};
//we need to determine tmp_constructor's value before exit bootstrap
//because of function : renderJS
//but since the channel checking is async,
//we can't use code structure like:
// if channel communication is ok
// tmp_constructor = RenderJSGadget
// else
// tmp_constructor = RenderJSEmbeddedGadget
if (window.self === window.top) {
// XXX Copy/Paste from declareGadgetKlass
TmpConstructor = function () {
RenderJSGadget.call(this);
};
TmpConstructor.declareMethod = RenderJSGadget.declareMethod;
TmpConstructor.declareJob = RenderJSGadget.declareJob;
TmpConstructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod;
TmpConstructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition;
TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice();
TmpConstructor.ready = RenderJSGadget.ready;
TmpConstructor.setState = RenderJSGadget.setState;
TmpConstructor.onStateChange = RenderJSGadget.onStateChange;
TmpConstructor.__service_list = RenderJSGadget.__service_list.slice();
TmpConstructor.declareService =
RenderJSGadget.declareService;
TmpConstructor.onEvent =
RenderJSGadget.onEvent;
TmpConstructor.prototype = new RenderJSGadget();
TmpConstructor.prototype.constructor = TmpConstructor;
TmpConstructor.prototype.__path = url;
gadget_model_defer_dict[url] = {
promise: RSVP.resolve(TmpConstructor)
};
// Create the root gadget instance and put it in the loading stack // Create the root gadget instance and put it in the loading stack
root_gadget = new TmpConstructor(); TmpConstructor = RenderJSEmbeddedGadget;
TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice();
setAqParent(root_gadget, last_acquisition_gadget); TmpConstructor.__service_list = RenderJSGadget.__service_list.slice();
TmpConstructor.prototype.__path = url;
root_gadget = new RenderJSEmbeddedGadget();
setAqParent(root_gadget, createLastAcquisitionGadget());
declare_method_list_waiting = [
"getInterfaceList",
"getRequiredCSSList",
"getRequiredJSList",
"getPath",
"getTitle"
];
// Inform parent gadget about declareMethod calls here.
notifyDeclareMethod = function (name) {
declare_method_list_waiting.push(name);
};
} else { real_result_list = [TmpConstructor, root_gadget, embedded_channel,
// Create the root gadget instance and put it in the loading stack declare_method_list_waiting];
TmpConstructor = RenderJSEmbeddedGadget; if (window.self === window.top) {
TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice(); loading_result = real_result_list;
TmpConstructor.__service_list = RenderJSGadget.__service_list.slice(); } else {
TmpConstructor.prototype.__path = url; channel_defer = RSVP.defer();
root_gadget = new RenderJSEmbeddedGadget(); loading_result = RSVP.any([
setAqParent(root_gadget, last_acquisition_gadget); channel_defer.promise,
new RSVP.Queue()
// Create the communication channel .push(function () {
embedded_channel = Channel.build({ // Expect the channel to parent to be usable after 1 second
window: window.parent, // If not, consider the gadget as the root
origin: "*", // Drop all iframe channel communication
scope: "renderJS", return RSVP.delay(1000);
onReady: function () { })
var k; .push(function () {
iframe_top_gadget = false; real_result_list[2] = undefined;
//Default: Define __aq_parent to inform parent window return real_result_list;
root_gadget.__aq_parent = })
TmpConstructor.prototype.__aq_parent = function (method_name, ]);
argument_list, time_out) { // Create the communication channel
return new RSVP.Promise(function (resolve, reject) { embedded_channel = Channel.build({
embedded_channel.call({ window: window.parent,
method: "acquire", origin: "*",
params: [ scope: "renderJS",
method_name, onReady: function () {
argument_list var k,
], len;
success: function (s) { // Channel is ready, so now declare all methods
resolve(s); notifyDeclareMethod = function (name) {
}, declare_method_list_waiting.push(
error: function (e) { new RSVP.Promise(function (resolve, reject) {
reject(e); embedded_channel.call({
}, method: "declareMethod",
timeout: time_out params: name,
}); success: resolve,
}); error: reject
};
// Channel is ready, so now declare Function
notifyDeclareMethod = function (name) {
declare_method_count += 1;
embedded_channel.call({
method: "declareMethod",
params: name,
success: function () {
declare_method_count -= 1;
notifyReady();
},
error: function () {
declare_method_count -= 1;
}
});
};
for (k = 0; k < declare_method_list_waiting.length; k += 1) {
notifyDeclareMethod(declare_method_list_waiting[k]);
}
declare_method_list_waiting = [];
// If Gadget Failed Notify Parent
if (gadget_failed) {
embedded_channel.notify({
method: "failed",
params: gadget_error
});
return;
}
connection_ready = true;
notifyReady();
//the channel is ok
//so bind calls to renderJS method on the instance
embedded_channel.bind("methodCall", function (trans, v) {
root_gadget[v[0]].apply(root_gadget, v[1])
.then(function (g) {
trans.complete(g);
}).fail(function (e) {
trans.error(e.toString());
}); });
trans.delayReturn(true); })
}); );
} };
});
// Notify parent about gadget instanciation len = declare_method_list_waiting.length;
notifyReady = function () { for (k = 0; k < len; k += 1) {
if ((declare_method_count === 0) && (gadget_ready === true)) { notifyDeclareMethod(declare_method_list_waiting[k]);
embedded_channel.notify({method: "ready"});
} }
};
// Inform parent gadget about declareMethod calls here. channel_defer.resolve(real_result_list);
notifyDeclareMethod = function (name) { }
declare_method_list_waiting.push(name); });
}; real_result_list[2] = embedded_channel;
}
notifyDeclareMethod("getInterfaceList"); // Surcharge declareMethod to inform parent window
notifyDeclareMethod("getRequiredCSSList"); TmpConstructor.declareMethod = function (name, callback) {
notifyDeclareMethod("getRequiredJSList"); var result = RenderJSGadget.declareMethod.apply(
notifyDeclareMethod("getPath"); this,
notifyDeclareMethod("getTitle"); [name, callback]
);
// Surcharge declareMethod to inform parent window notifyDeclareMethod(name);
TmpConstructor.declareMethod = function (name, callback) { return result;
var result = RenderJSGadget.declareMethod.apply( };
this,
[name, callback]
);
notifyDeclareMethod(name);
return result;
};
TmpConstructor.declareService = TmpConstructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
TmpConstructor.declareJob = TmpConstructor.declareJob =
RenderJSGadget.declareJob; RenderJSGadget.declareJob;
TmpConstructor.onEvent = TmpConstructor.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
TmpConstructor.declareAcquiredMethod = TmpConstructor.onLoop =
RenderJSGadget.declareAcquiredMethod; RenderJSGadget.onLoop;
TmpConstructor.allowPublicAcquisition = TmpConstructor.declareAcquiredMethod =
RenderJSGadget.allowPublicAcquisition; RenderJSGadget.declareAcquiredMethod;
TmpConstructor.allowPublicAcquisition =
iframe_top_gadget = true; RenderJSGadget.allowPublicAcquisition;
}
TmpConstructor.prototype.__acquired_method_dict = {}; TmpConstructor.prototype.__acquired_method_dict = {};
gadget_loading_klass_list.push(TmpConstructor); gadget_loading_klass_list.push(TmpConstructor);
function init() { return loading_result;
// XXX HTML properties can only be set when the DOM is fully loaded }
var settings = renderJS.parseGadgetHTMLDocument(document, url),
j,
key,
fragment = document.createDocumentFragment();
for (key in settings) {
if (settings.hasOwnProperty(key)) {
TmpConstructor.prototype['__' + key] = settings[key];
}
}
TmpConstructor.__template_element = document.createElement("div");
root_gadget.element = document.body;
root_gadget.state = {};
for (j = 0; j < root_gadget.element.childNodes.length; j += 1) {
fragment.appendChild(
root_gadget.element.childNodes[j].cloneNode(true)
);
}
TmpConstructor.__template_element.appendChild(fragment);
RSVP.all([root_gadget.getRequiredJSList(),
root_gadget.getRequiredCSSList()])
.then(function (all_list) {
var i,
js_list = all_list[0],
css_list = all_list[1];
for (i = 0; i < js_list.length; i += 1) {
javascript_registration_dict[js_list[i]] = null;
}
for (i = 0; i < css_list.length; i += 1) {
stylesheet_registration_dict[css_list[i]] = null;
}
gadget_loading_klass_list.shift();
}).then(function () {
// select the target node
var target = document.querySelector('body'),
// create an observer instance
observer = new MutationObserver(function (mutations) {
var i, k, len, len2, node, added_list;
mutations.forEach(function (mutation) {
if (mutation.type === 'childList') {
len = mutation.removedNodes.length;
for (i = 0; i < len; i += 1) {
node = mutation.removedNodes[i];
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.hasAttribute("data-gadget-url") &&
(node._gadget !== undefined)) {
createMonitor(node._gadget);
}
added_list =
node.querySelectorAll("[data-gadget-url]");
len2 = added_list.length;
for (k = 0; k < len2; k += 1) {
node = added_list[k];
if (node._gadget !== undefined) {
createMonitor(node._gadget);
}
}
}
}
len = mutation.addedNodes.length; function triggerReadyList(TmpConstructor, root_gadget) {
for (i = 0; i < len; i += 1) { // XXX Probably duplicated
node = mutation.addedNodes[i]; var i,
if (node.nodeType === Node.ELEMENT_NODE) { ready_queue = new RSVP.Queue();
if (node.hasAttribute("data-gadget-url") &&
(node._gadget !== undefined)) {
if (document.contains(node)) {
startService(node._gadget);
}
}
added_list =
node.querySelectorAll("[data-gadget-url]");
len2 = added_list.length;
for (k = 0; k < len2; k += 1) {
node = added_list[k];
if (document.contains(node)) {
if (node._gadget !== undefined) {
startService(node._gadget);
}
}
}
}
}
} function ready_wrapper() {
}); return root_gadget;
}), }
// configuration of the observer: function ready_executable_wrapper(fct) {
config = { return function (g) {
childList: true, return fct.call(g, g);
subtree: true, };
attributes: false, }
characterData: false TmpConstructor.ready(function () {
}; return startService(this);
});
// pass in the target node, as well as the observer options
observer.observe(target, config); ready_queue.push(ready_wrapper);
for (i = 0; i < TmpConstructor.__ready_list.length; i += 1) {
return root_gadget; // Put a timeout?
}).then(resolve, function (e) { ready_queue
reject(e); .push(ready_executable_wrapper(TmpConstructor.__ready_list[i]))
console.error(e); // Always return the gadget instance after ready function
throw e; .push(ready_wrapper);
}
return ready_queue;
}
function finishAqParentConfiguration(TmpConstructor, root_gadget,
embedded_channel) {
// Define __aq_parent to inform parent window
root_gadget.__aq_parent =
TmpConstructor.prototype.__aq_parent = function (method_name,
argument_list,
time_out) {
return new RSVP.Promise(function (resolve, reject) {
embedded_channel.call({
method: "acquire",
params: [
method_name,
argument_list
],
success: function (s) {
resolve(s);
},
error: function (e) {
reject(e);
},
timeout: time_out
}); });
} });
document.addEventListener('DOMContentLoaded', init, false); };
// bind calls to renderJS method on the instance
embedded_channel.bind("methodCall", function (trans, v) {
root_gadget[v[0]].apply(root_gadget, v[1])
.push(function (g) {
trans.complete(g);
}, function (e) {
trans.error(e.toString());
});
trans.delayReturn(true);
}); });
}
function bootstrap(url) {
// Create the loading gadget
var wait_for_gadget_loaded = createLoadingGadget(url),
TmpConstructor,
root_gadget,
embedded_channel,
declare_method_list_waiting;
loading_gadget_promise return new RSVP.Queue()
.push(function () { .push(function () {
return loading_klass_promise; // Wait for the loading gadget to be created
return wait_for_gadget_loaded;
}) })
.push(function (root_gadget) { .push(function (result_list) {
var i; TmpConstructor = result_list[0];
root_gadget = result_list[1];
function ready_wrapper() { embedded_channel = result_list[2];
return root_gadget; declare_method_list_waiting = result_list[3];
// Wait for all the gadget dependencies to be loaded
return all_dependency_loaded_deferred.promise;
})
.push(function () {
// Wait for all methods to be correctly declared
return RSVP.all(declare_method_list_waiting);
})
.push(function (result_list) {
if (embedded_channel !== undefined) {
finishAqParentConfiguration(TmpConstructor, root_gadget,
embedded_channel);
} }
function ready_executable_wrapper(fct) { // Check all DOM modifications to correctly start/stop services
return function (g) { return configureMutationObserver(TmpConstructor, url, root_gadget);
return fct.call(g, g); })
}; .push(function () {
// Trigger all ready functions
return triggerReadyList(TmpConstructor, root_gadget);
})
.push(function () {
if (embedded_channel !== undefined) {
embedded_channel.notify({method: "ready"});
} }
TmpConstructor.ready(function () { })
return startService(this); .push(undefined, function (e) {
}); letsCrash(e);
if (embedded_channel !== undefined) {
loading_gadget_promise.push(ready_wrapper); embedded_channel.notify({method: "failed", params: e.toString()});
for (i = 0; i < TmpConstructor.__ready_list.length; i += 1) {
// Put a timeout?
loading_gadget_promise
.push(ready_executable_wrapper(TmpConstructor.__ready_list[i]))
// Always return the gadget instance after ready function
.push(ready_wrapper);
} }
throw e;
}); });
if (window.self === window.top) {
loading_gadget_promise
.fail(function (e) {
letsCrash(e);
throw e;
});
} else {
// Inform parent window that gadget is correctly loaded
loading_gadget_promise
.then(function () {
gadget_ready = true;
if (connection_ready) {
notifyReady();
}
})
.fail(function (e) {
//top gadget in iframe
if (iframe_top_gadget) {
gadget_failed = true;
gadget_error = e.toString();
letsCrash(e);
} else {
embedded_channel.notify({method: "failed", params: e.toString()});
}
throw e;
});
}
} }
bootstrap();
bootstrap(
removeHash(window.location.href)
);
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node, }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
FileReader, Blob, navigator, Event, URL)); FileReader, Blob, navigator, Event, URL));
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment