Commit 0c2428ca authored by Romain Courteaud's avatar Romain Courteaud

Give a name to all anonymous functions.

This will make JS stack more readable.
parent be096475
...@@ -5,19 +5,20 @@ ...@@ -5,19 +5,20 @@
* renderJs - Generic Gadget library renderer. * renderJs - Generic Gadget library renderer.
* http://www.renderjs.org/documentation * http://www.renderjs.org/documentation
*/ */
(function (document, window, RSVP, DOMParser, Channel, MutationObserver, (function wrapRenderJS(document, window, RSVP, DOMParser, Channel,
Node, FileReader, Blob, navigator, Event, URL) { MutationObserver, Node, FileReader, Blob, navigator,
Event, URL) {
"use strict"; "use strict";
function readBlobAsDataURL(blob) { function readBlobAsDataURL(blob) {
var fr = new FileReader(); var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject) { return new RSVP.Promise(function waitFormDataURLRead(resolve, reject) {
fr.addEventListener("load", function (evt) { fr.addEventListener("load", function handleDataURLRead(evt) {
resolve(evt.target.result); resolve(evt.target.result);
}); });
fr.addEventListener("error", reject); fr.addEventListener("error", reject);
fr.readAsDataURL(blob); fr.readAsDataURL(blob);
}, function () { }, function cancelReadBlobAsDataURL() {
fr.abort(); fr.abort();
}); });
} }
...@@ -50,7 +51,7 @@ ...@@ -50,7 +51,7 @@
} }
function itsANonResolvableTrap(resolve, reject) { function itsANonResolvableTrap(resolve, reject) {
var result; var result;
handle_event_callback = function (evt) { handle_event_callback = function handleEventCallback(evt) {
if (prevent_default) { if (prevent_default) {
evt.stopPropagation(); evt.stopPropagation();
evt.preventDefault(); evt.preventDefault();
...@@ -66,10 +67,10 @@ ...@@ -66,10 +67,10 @@
callback_promise = result; callback_promise = result;
new RSVP.Queue() new RSVP.Queue()
.push(function () { .push(function waitForEventCallbackResult() {
return result; return result;
}) })
.push(undefined, function (error) { .push(undefined, function handleEventCallbackError(error) {
if (!(error instanceof RSVP.CancellationError)) { if (!(error instanceof RSVP.CancellationError)) {
canceller(); canceller();
reject(error); reject(error);
...@@ -147,11 +148,11 @@ ...@@ -147,11 +148,11 @@
error_list = [], error_list = [],
all_dependency_loaded_deferred; all_dependency_loaded_deferred;
window.addEventListener('error', function (error) { window.addEventListener('error', function handleGlobalError(error) {
error_list.push(error); error_list.push(error);
}); });
window.addEventListener('beforeunload', function () { window.addEventListener('beforeunload', function handleBeforeUnload() {
// XXX If another listener cancel the page unload, // XXX If another listener cancel the page unload,
// it will not restore renderJS crash report // it will not restore renderJS crash report
is_page_unloaded = true; is_page_unloaded = true;
...@@ -294,7 +295,7 @@ ...@@ -294,7 +295,7 @@
ResolvedMonitorError.prototype = new Error(); ResolvedMonitorError.prototype = new Error();
ResolvedMonitorError.prototype.constructor = ResolvedMonitorError; ResolvedMonitorError.prototype.constructor = ResolvedMonitorError;
Monitor = function () { Monitor = function createMonitor() {
var monitor = this, var monitor = this,
promise_list = [], promise_list = [],
promise, promise,
...@@ -316,8 +317,8 @@ ...@@ -316,8 +317,8 @@
promise_list = []; promise_list = [];
} }
promise = new RSVP.Promise(function (done, fail, progress) { promise = new RSVP.Promise(function promiseMonitor(done, fail, progress) {
reject = function (rejectedReason) { reject = function rejectMonitor(rejectedReason) {
if (resolved) { if (resolved) {
return; return;
} }
...@@ -330,33 +331,29 @@ ...@@ -330,33 +331,29 @@
notify = progress; notify = progress;
}, canceller); }, canceller);
monitor.cancel = function () { monitor.cancel = function cancelMonitor() {
if (resolved) { if (resolved) {
return; return;
} }
resolved = true; resolved = true;
promise.cancel(); promise.cancel();
promise.fail(function (rejectedReason) { promise.fail(function rejectMonitorPromise(rejectedReason) {
monitor.isRejected = true; monitor.isRejected = true;
monitor.rejectedReason = rejectedReason; monitor.rejectedReason = rejectedReason;
}); });
}; };
monitor.then = function () { monitor.then = promise.then.bind(promise);
return promise.then.apply(promise, arguments); monitor.fail = promise.fail.bind(promise);
};
monitor.fail = function () {
return promise.fail.apply(promise, arguments);
};
monitor.monitor = function (promise_to_monitor) { monitor.monitor = function startMonitor(promise_to_monitor) {
if (resolved) { if (resolved) {
throw new ResolvedMonitorError(); throw new ResolvedMonitorError();
} }
var queue = new RSVP.Queue() var queue = new RSVP.Queue()
.push(function () { .push(function waitForPromiseToMonitor() {
return promise_to_monitor; return promise_to_monitor;
}) })
.push(function (fulfillmentValue) { .push(function handlePromiseToMonitorSuccess(fulfillmentValue) {
// Promise to monitor is fullfilled, remove it from the list // Promise to monitor is fullfilled, remove it from the list
var len = promise_list.length, var len = promise_list.length,
sub_promise_to_monitor, sub_promise_to_monitor,
...@@ -370,7 +367,7 @@ ...@@ -370,7 +367,7 @@
} }
} }
promise_list = new_promise_list; promise_list = new_promise_list;
}, function (rejectedReason) { }, function handlePromiseToMonitorError(rejectedReason) {
if (rejectedReason instanceof RSVP.CancellationError) { if (rejectedReason instanceof RSVP.CancellationError) {
if (!(promise_to_monitor.isFulfilled && if (!(promise_to_monitor.isFulfilled &&
promise_to_monitor.isRejected)) { promise_to_monitor.isRejected)) {
...@@ -380,7 +377,7 @@ ...@@ -380,7 +377,7 @@
} }
reject(rejectedReason); reject(rejectedReason);
throw rejectedReason; throw rejectedReason;
}, function (notificationValue) { }, function handlePromiseToMonitorNotification(notificationValue) {
notify(notificationValue); notify(notificationValue);
return notificationValue; return notificationValue;
}); });
...@@ -409,7 +406,7 @@ ...@@ -409,7 +406,7 @@
RenderJSGadget.prototype.__required_css_list = []; RenderJSGadget.prototype.__required_css_list = [];
RenderJSGadget.prototype.__required_js_list = []; RenderJSGadget.prototype.__required_js_list = [];
function createMonitor(g) { function createGadgetMonitor(g) {
if (g.__monitor !== undefined) { if (g.__monitor !== undefined) {
g.__monitor.cancel(); g.__monitor.cancel();
} }
...@@ -417,19 +414,17 @@ ...@@ -417,19 +414,17 @@
g.__job_dict = {}; g.__job_dict = {};
g.__job_list = []; g.__job_list = [];
g.__job_triggered = false; g.__job_triggered = false;
g.__monitor.fail(function (error) { g.__monitor.fail(function handleGadgetMonitorError(error) {
if (!(error instanceof RSVP.CancellationError)) { if (!(error instanceof RSVP.CancellationError)) {
return g.aq_reportServiceError(error); return g.aq_reportServiceError(error);
} }
}).fail(function (error) {
// Crash the application if the acquisition generates an error. // Crash the application if the acquisition generates an error.
return letsCrash(error); }).fail(letsCrash);
});
} }
function clearGadgetInternalParameters() { function clearGadgetInternalParameters() {
this.__sub_gadget_dict = {}; this.__sub_gadget_dict = {};
createMonitor(this); createGadgetMonitor(this);
} }
function loadSubGadgetDOMDeclaration() { function loadSubGadgetDOMDeclaration() {
...@@ -443,7 +438,7 @@ ...@@ -443,7 +438,7 @@
context = this; context = this;
function prepareReportGadgetDeclarationError(scope) { function prepareReportGadgetDeclarationError(scope) {
return function (error) { return function reportGadgetDeclarationError(error) {
var aq_dict = context.__acquired_method_dict || {}, var aq_dict = context.__acquired_method_dict || {},
method_name = 'reportGadgetDeclarationError'; method_name = 'reportGadgetDeclarationError';
if (aq_dict.hasOwnProperty(method_name)) { if (aq_dict.hasOwnProperty(method_name)) {
...@@ -476,58 +471,56 @@ ...@@ -476,58 +471,56 @@
RenderJSGadget.__ready_list = [clearGadgetInternalParameters, RenderJSGadget.__ready_list = [clearGadgetInternalParameters,
loadSubGadgetDOMDeclaration]; loadSubGadgetDOMDeclaration];
RenderJSGadget.ready = function (callback) { RenderJSGadget.ready = function ready(callback) {
this.__ready_list.push(callback); this.__ready_list.push(callback);
return this; return this;
}; };
RenderJSGadget.setState = function (state_dict) { RenderJSGadget.setState = function setState(state_dict) {
var json_state = JSON.stringify(state_dict); var json_state = JSON.stringify(state_dict);
this.__ready_list.unshift(function () { this.__ready_list.unshift(function setStateDefaultValue() {
this.state = JSON.parse(json_state); this.state = JSON.parse(json_state);
}); });
return this; return this;
}; };
RenderJSGadget.onStateChange = function (callback) { RenderJSGadget.onStateChange = function onStateChange(callback) {
this.prototype.__state_change_callback = callback; this.prototype.__state_change_callback = callback;
return this; return this;
}; };
RenderJSGadget.__service_list = []; RenderJSGadget.__service_list = [];
RenderJSGadget.declareService = function (callback) { RenderJSGadget.declareService = function declareService(callback) {
this.__service_list.push(callback); this.__service_list.push(callback);
return this; return this;
}; };
RenderJSGadget.onEvent = function (type, callback, use_capture, RenderJSGadget.onEvent = function onEvent(type, callback, use_capture,
prevent_default) { prevent_default) {
this.__service_list.push(function () { this.__service_list.push(function startLoopEventListenerService() {
return loopEventListener(this.element, type, use_capture, return loopEventListener(this.element, type, use_capture,
callback.bind(this), prevent_default); callback.bind(this), prevent_default);
}); });
return this; return this;
}; };
RenderJSGadget.onLoop = function (callback, delay) { RenderJSGadget.onLoop = function onLoop(callback, delay) {
if (delay === undefined) { if (delay === undefined) {
delay = 0; delay = 0;
} }
this.__service_list.push(function () { this.__service_list.push(function handleServiceCallback() {
var queue_loop = new RSVP.Queue(), var queue_loop = new RSVP.Queue(),
context = this, context = this,
wait = function () { wait = function waitForLoopIteration() {
queue_loop queue_loop
.push(function () { .push(function waitNextOnLoopDelay() {
return RSVP.delay(delay); return RSVP.delay(delay);
}) })
.push(function () { .push(function waitNextOnLoopAnimationFrame() {
// Only loop when the app has the focus // Only loop when the app has the focus
return promiseAnimationFrame(); return promiseAnimationFrame();
}) })
.push(function () { .push(function executeOnLoopCallback() {
return callback.apply(context, []); return callback.apply(context, []);
}) })
.push(function () { .push(wait);
wait();
});
}; };
wait(); wait();
return queue_loop; return queue_loop;
...@@ -537,7 +530,7 @@ ...@@ -537,7 +530,7 @@
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 waitForJobCallback() {
return callback.apply(gadget, argument_list); return callback.apply(gadget, argument_list);
}); });
if (gadget.__job_dict.hasOwnProperty(name)) { if (gadget.__job_dict.hasOwnProperty(name)) {
...@@ -545,10 +538,10 @@ ...@@ -545,10 +538,10 @@
} }
gadget.__job_dict[name] = job_promise; gadget.__job_dict[name] = job_promise;
gadget.__monitor.monitor(new RSVP.Queue() gadget.__monitor.monitor(new RSVP.Queue()
.push(function () { .push(function waitForJobPromise() {
return job_promise; return job_promise;
}) })
.push(undefined, function (error) { .push(undefined, function handleJobError(error) {
if (!(error instanceof RSVP.CancellationError)) { if (!(error instanceof RSVP.CancellationError)) {
throw error; throw error;
} }
...@@ -557,7 +550,7 @@ ...@@ -557,7 +550,7 @@
function startService(gadget) { function startService(gadget) {
gadget.__monitor.monitor(new RSVP.Queue() gadget.__monitor.monitor(new RSVP.Queue()
.push(function () { .push(function monitorAllServiceList() {
var i, var i,
service_list = gadget.constructor.__service_list, service_list = gadget.constructor.__service_list,
job_list = gadget.__job_list; job_list = gadget.__job_list;
...@@ -578,8 +571,8 @@ ...@@ -578,8 +571,8 @@
// gadget internal method, which trigger execution // gadget internal method, which trigger execution
// of a function inside a service // of a function inside a service
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
RenderJSGadget.declareJob = function (name, callback) { RenderJSGadget.declareJob = function declareJob(name, callback) {
this.prototype[name] = function () { this.prototype[name] = function triggerJob() {
var context = this, var context = this,
argument_list = arguments; argument_list = arguments;
...@@ -596,13 +589,13 @@ ...@@ -596,13 +589,13 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.declareMethod // RenderJSGadget.declareMethod
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
RenderJSGadget.declareMethod = function (name, callback) { RenderJSGadget.declareMethod = function declareMethod(name, callback) {
this.prototype[name] = function () { this.prototype[name] = function triggerMethod() {
var context = this, var context = this,
argument_list = arguments; argument_list = arguments;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForMethodCallback() {
return callback.apply(context, argument_list); return callback.apply(context, argument_list);
}); });
}; };
...@@ -611,27 +604,27 @@ ...@@ -611,27 +604,27 @@
}; };
RenderJSGadget RenderJSGadget
.declareMethod('getInterfaceList', function () { .declareMethod('getInterfaceList', function getInterfaceList() {
// Returns the list of gadget prototype // Returns the list of gadget prototype
return this.__interface_list; return this.__interface_list;
}) })
.declareMethod('getRequiredCSSList', function () { .declareMethod('getRequiredCSSList', function getRequiredCSSList() {
// Returns a list of CSS required by the gadget // Returns a list of CSS required by the gadget
return this.__required_css_list; return this.__required_css_list;
}) })
.declareMethod('getRequiredJSList', function () { .declareMethod('getRequiredJSList', function getRequiredJSList() {
// Returns a list of JS required by the gadget // Returns a list of JS required by the gadget
return this.__required_js_list; return this.__required_js_list;
}) })
.declareMethod('getPath', function () { .declareMethod('getPath', function getPath() {
// Returns the path of the code of a gadget // Returns the path of the code of a gadget
return this.__path; return this.__path;
}) })
.declareMethod('getTitle', function () { .declareMethod('getTitle', function getTitle() {
// Returns the title of a gadget // Returns the title of a gadget
return this.__title; return this.__title;
}) })
.declareMethod('getElement', function () { .declareMethod('getElement', function getElement() {
// Returns the DOM Element of a gadget // Returns the DOM Element of a gadget
// XXX Kept for compatibility. Use element property directly // XXX Kept for compatibility. Use element property directly
if (this.element === undefined) { if (this.element === undefined) {
...@@ -639,24 +632,24 @@ ...@@ -639,24 +632,24 @@
} }
return this.element; return this.element;
}) })
.declareMethod('changeState', function (state_dict) { .declareMethod('changeState', function changeState(state_dict) {
var next_onStateChange = new RSVP.Queue(), var next_onStateChange = new RSVP.Queue(),
previous_onStateCHange, previous_onStateCHange,
context = this; context = this;
if (context.hasOwnProperty('__previous_onStateChange')) { if (context.hasOwnProperty('__previous_onStateChange')) {
previous_onStateCHange = context.__previous_onStateChange; previous_onStateCHange = context.__previous_onStateChange;
next_onStateChange next_onStateChange
.push(function () { .push(function waitForPreviousStateChange() {
return previous_onStateCHange; return previous_onStateCHange;
}) })
.push(undefined, function () { .push(undefined, function handlePreviousStateChangeError() {
// Run callback even if previous failed // Run callback even if previous failed
return; return;
}); });
} }
context.__previous_onStateChange = next_onStateChange; context.__previous_onStateChange = next_onStateChange;
return next_onStateChange return next_onStateChange
.push(function () { .push(function checkStateModification() {
var key, var key,
modified = false, modified = false,
previous_cancelled = context.hasOwnProperty('__modification_dict'), previous_cancelled = context.hasOwnProperty('__modification_dict'),
...@@ -678,10 +671,10 @@ ...@@ -678,10 +671,10 @@
if (modified && context.__state_change_callback !== undefined) { if (modified && context.__state_change_callback !== undefined) {
context.__modification_dict = modification_dict; context.__modification_dict = modification_dict;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForStateChangeCallback() {
return context.__state_change_callback(modification_dict); return context.__state_change_callback(modification_dict);
}) })
.push(function (result) { .push(function handleStateChangeSuccess(result) {
delete context.__modification_dict; delete context.__modification_dict;
return result; return result;
}); });
...@@ -705,7 +698,7 @@ ...@@ -705,7 +698,7 @@
} }
} }
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForAcquireMethod() {
// Do not specify default __acquired_method_dict on prototype // Do not specify default __acquired_method_dict on prototype
// to prevent modifying this default value (with // to prevent modifying this default value (with
// allowPublicAcquiredMethod for example) // allowPublicAcquiredMethod for example)
...@@ -716,7 +709,7 @@ ...@@ -716,7 +709,7 @@
} }
throw new renderJS.AcquisitionError("aq_dynamic is not defined"); throw new renderJS.AcquisitionError("aq_dynamic is not defined");
}) })
.push(undefined, function (error) { .push(undefined, function handleAcquireMethodError(error) {
if (error instanceof renderJS.AcquisitionError) { if (error instanceof renderJS.AcquisitionError) {
return gadget.__aq_parent(method_name, argument_list); return gadget.__aq_parent(method_name, argument_list);
} }
...@@ -725,12 +718,12 @@ ...@@ -725,12 +718,12 @@
} }
RenderJSGadget.declareAcquiredMethod = RenderJSGadget.declareAcquiredMethod =
function (name, method_name_to_acquire) { function declareAcquiredMethod(name, method_name_to_acquire) {
this.prototype[name] = function () { this.prototype[name] = function acquireMethod() {
var argument_list = Array.prototype.slice.call(arguments, 0), var argument_list = Array.prototype.slice.call(arguments, 0),
gadget = this; gadget = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForAqParent() {
return gadget.__aq_parent(method_name_to_acquire, argument_list); return gadget.__aq_parent(method_name_to_acquire, argument_list);
}); });
}; };
...@@ -747,7 +740,7 @@ ...@@ -747,7 +740,7 @@
// RenderJSGadget.allowPublicAcquisition // RenderJSGadget.allowPublicAcquisition
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
RenderJSGadget.allowPublicAcquisition = RenderJSGadget.allowPublicAcquisition =
function (method_name, callback) { function allowPublicAcquisition(method_name, callback) {
this.prototype.__acquired_method_dict[method_name] = callback; this.prototype.__acquired_method_dict[method_name] = callback;
// Allow chain // Allow chain
...@@ -756,7 +749,8 @@ ...@@ -756,7 +749,8 @@
// Set aq_parent on gadget_instance which call acquire on parent_gadget // Set aq_parent on gadget_instance which call acquire on parent_gadget
function setAqParent(gadget_instance, parent_gadget) { function setAqParent(gadget_instance, parent_gadget) {
gadget_instance.__aq_parent = function (method_name, argument_list) { gadget_instance.__aq_parent =
function __aq_parent(method_name, argument_list) {
return acquire.apply(parent_gadget, [gadget_instance, method_name, return acquire.apply(parent_gadget, [gadget_instance, method_name,
argument_list]); argument_list]);
}; };
...@@ -795,19 +789,13 @@ ...@@ -795,19 +789,13 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
function privateDeclarePublicGadget(url, options, parent_gadget) { function privateDeclarePublicGadget(url, options, parent_gadget) {
return new RSVP.Queue()
.push(function () {
return renderJS.declareGadgetKlass(url) return renderJS.declareGadgetKlass(url)
// gadget loading should not be interrupted // gadget loading should not be interrupted
// if not, gadget's definition will not be complete // if not, gadget's definition will not be complete
//.then will return another promise //.then will return another promise
//so loading_klass_promise can't be cancel //so loading_klass_promise can't be cancel
.then(function (result) { .then(function createPrivateInstanceFromKlass(Klass) {
return result;
});
})
// Get the gadget class and instanciate it // Get the gadget class and instanciate it
.push(function (Klass) {
if (options.element === undefined) { if (options.element === undefined) {
options.element = document.createElement("div"); options.element = document.createElement("div");
} }
...@@ -876,12 +864,12 @@ ...@@ -876,12 +864,12 @@
gadget_instance = new RenderJSIframeGadget(); gadget_instance = new RenderJSIframeGadget();
setAqParent(gadget_instance, parent_gadget); setAqParent(gadget_instance, parent_gadget);
iframe = document.createElement("iframe"); iframe = document.createElement("iframe");
iframe.addEventListener('error', function (error) { iframe.addEventListener('error', function handleIframeError(error) {
iframe_loading_deferred.reject(error); iframe_loading_deferred.reject(error);
}); });
iframe.addEventListener('load', function () { iframe.addEventListener('load', function handleIframeLoad() {
return RSVP.timeout(5000) return RSVP.timeout(5000)
.fail(function () { .fail(function triggerIframeTimeout() {
iframe_loading_deferred.reject( iframe_loading_deferred.reject(
new Error('Timeout while loading: ' + url) new Error('Timeout while loading: ' + url)
); );
...@@ -906,11 +894,13 @@ ...@@ -906,11 +894,13 @@
}); });
// Create new method from the declareMethod call inside the iframe // Create new method from the declareMethod call inside the iframe
gadget_instance.__chan.bind("declareMethod", gadget_instance.__chan.bind(
function (trans, method_name) { "declareMethod",
gadget_instance[method_name] = function () { function handleChannelDeclareMethod(trans, method_name) {
gadget_instance[method_name] = function triggerChannelDeclareMethod() {
var argument_list = arguments, var argument_list = arguments,
wait_promise = new RSVP.Promise(function (resolve, reject) { wait_promise = new RSVP.Promise(
function handleChannelCall(resolve, reject) {
gadget_instance.__chan.call({ gadget_instance.__chan.call({
method: "methodCall", method: "methodCall",
params: [ params: [
...@@ -919,29 +909,32 @@ ...@@ -919,29 +909,32 @@
success: resolve, success: resolve,
error: reject error: reject
}); });
}); }
);
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForChannelCall() {
return wait_promise; return wait_promise;
}); });
}; };
return "OK"; return "OK";
}); }
);
// Wait for the iframe to be loaded before continuing // Wait for the iframe to be loaded before continuing
gadget_instance.__chan.bind("ready", function (trans) { gadget_instance.__chan.bind("ready", function handleChannelReady(trans) {
iframe_loading_deferred.resolve(gadget_instance); iframe_loading_deferred.resolve(gadget_instance);
return "OK"; return "OK";
}); });
gadget_instance.__chan.bind("failed", function (trans, params) { gadget_instance.__chan.bind("failed",
function handleChannelFail(trans, params) {
iframe_loading_deferred.reject(params); iframe_loading_deferred.reject(params);
return "OK"; return "OK";
}); });
gadget_instance.__chan.bind("acquire", function (trans, params) { gadget_instance.__chan.bind("acquire",
function handleChannelAcquire(trans, params) {
gadget_instance.__aq_parent.apply(gadget_instance, params) gadget_instance.__aq_parent.apply(gadget_instance, params)
.then(function (g) { .then(trans.complete)
trans.complete(g); .fail(function handleChannelAcquireError(e) {
}).fail(function (e) {
trans.error(e.toString()); trans.error(e.toString());
}); });
trans.delayReturn(true); trans.delayReturn(true);
...@@ -956,10 +949,10 @@ ...@@ -956,10 +949,10 @@
function privateDeclareDataUrlGadget(url, options, parent_gadget) { function privateDeclareDataUrlGadget(url, options, parent_gadget) {
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForDataUrlAjax() {
return ajax(url); return ajax(url);
}) })
.push(function (xhr) { .push(function handleDataURLAjaxResponse(xhr) {
// Insert a "base" element, in order to resolve all relative links // Insert a "base" element, in order to resolve all relative links
// which could get broken with a data url // which could get broken with a data url
var doc = (new DOMParser()).parseFromString(xhr.responseText, var doc = (new DOMParser()).parseFromString(xhr.responseText,
...@@ -972,7 +965,7 @@ ...@@ -972,7 +965,7 @@
{type: "text/html;charset=UTF-8"}); {type: "text/html;charset=UTF-8"});
return readBlobAsDataURL(blob); return readBlobAsDataURL(blob);
}) })
.push(function (data_url) { .push(function handleDataURL(data_url) {
return privateDeclareIframeGadget(data_url, options, parent_gadget); return privateDeclareIframeGadget(data_url, options, parent_gadget);
}); });
} }
...@@ -981,7 +974,7 @@ ...@@ -981,7 +974,7 @@
// RenderJSGadget.declareGadget // RenderJSGadget.declareGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
RenderJSGadget RenderJSGadget
.declareMethod('declareGadget', function (url, options) { .declareMethod('declareGadget', function declareGadget(url, options) {
var parent_gadget = this; var parent_gadget = this;
if (options === undefined) { if (options === undefined) {
...@@ -995,7 +988,7 @@ ...@@ -995,7 +988,7 @@
url = renderJS.getAbsoluteURL(url, this.__path); url = renderJS.getAbsoluteURL(url, this.__path);
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForPrivateDeclareGadget() {
var method; var method;
if (options.sandbox === "public") { if (options.sandbox === "public") {
method = privateDeclarePublicGadget; method = privateDeclarePublicGadget;
...@@ -1010,7 +1003,7 @@ ...@@ -1010,7 +1003,7 @@
return method(url, options, parent_gadget); return method(url, options, parent_gadget);
}) })
// Set the HTML context // Set the HTML context
.push(function (gadget_instance) { .push(function setGadgetInstanceHTMLContext(gadget_instance) {
var i, var i,
scope, scope,
queue = new RSVP.Queue(); queue = new RSVP.Queue();
...@@ -1019,7 +1012,7 @@ ...@@ -1019,7 +1012,7 @@
return gadget_instance; return gadget_instance;
} }
function ready_executable_wrapper(fct) { function ready_executable_wrapper(fct) {
return function () { return function executeReadyWrapper() {
return fct.call(gadget_instance, gadget_instance); return fct.call(gadget_instance, gadget_instance);
}; };
} }
...@@ -1063,13 +1056,14 @@ ...@@ -1063,13 +1056,14 @@
return queue; return queue;
}); });
}) })
.declareMethod('getDeclaredGadget', function (gadget_scope) { .declareMethod('getDeclaredGadget',
function getDeclaredGadget(gadget_scope) {
if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) { if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
throw new Error("Gadget scope '" + gadget_scope + "' is not known."); throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
} }
return this.__sub_gadget_dict[gadget_scope]; return this.__sub_gadget_dict[gadget_scope];
}) })
.declareMethod('dropGadget', function (gadget_scope) { .declareMethod('dropGadget', function dropGadget(gadget_scope) {
if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) { if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
throw new Error("Gadget scope '" + gadget_scope + "' is not known."); throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
} }
...@@ -1080,7 +1074,7 @@ ...@@ -1080,7 +1074,7 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS selector // renderJS selector
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS = function (selector) { renderJS = function getLoadingGadget(selector) {
var result; var result;
if (selector === window) { if (selector === window) {
// window is the 'this' value when loading a javascript file // window is the 'this' value when loading a javascript file
...@@ -1096,7 +1090,7 @@ ...@@ -1096,7 +1090,7 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.AcquisitionError // renderJS.AcquisitionError
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.AcquisitionError = function (message) { renderJS.AcquisitionError = function createAcquisitionError(message) {
this.name = "AcquisitionError"; this.name = "AcquisitionError";
if ((message !== undefined) && (typeof message !== "string")) { if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.'); throw new TypeError('You must pass a string.');
...@@ -1110,7 +1104,7 @@ ...@@ -1110,7 +1104,7 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.getAbsoluteURL // renderJS.getAbsoluteURL
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.getAbsoluteURL = function (url, base_url) { renderJS.getAbsoluteURL = function getAbsoluteURL(url, base_url) {
if (base_url && url) { if (base_url && url) {
return new URL(url, base_url).href; return new URL(url, base_url).href;
} }
...@@ -1120,7 +1114,7 @@ ...@@ -1120,7 +1114,7 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.declareJS // renderJS.declareJS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareJS = function (url, container, pop) { renderJS.declareJS = function declareJS(url, container, pop) {
// https://www.html5rocks.com/en/tutorials/speed/script-loading/ // https://www.html5rocks.com/en/tutorials/speed/script-loading/
// Prevent infinite recursion if loading render.js // Prevent infinite recursion if loading render.js
// more than once // more than once
...@@ -1129,19 +1123,20 @@ ...@@ -1129,19 +1123,20 @@
result = RSVP.resolve(); result = RSVP.resolve();
} else { } else {
javascript_registration_dict[url] = null; javascript_registration_dict[url] = null;
result = new RSVP.Promise(function (resolve, reject) { result = new RSVP.Promise(
function waitForJSLoadEvent(resolve, reject) {
var newScript; var newScript;
newScript = document.createElement('script'); newScript = document.createElement('script');
newScript.async = false; newScript.async = false;
newScript.type = 'text/javascript'; newScript.type = 'text/javascript';
newScript.onload = function () { newScript.onload = function triggerJSLoaded() {
if (pop === true) { if (pop === true) {
// Drop the current loading klass info used by selector // Drop the current loading klass info used by selector
gadget_loading_klass_list.shift(); gadget_loading_klass_list.shift();
} }
resolve(); resolve();
}; };
newScript.onerror = function (e) { newScript.onerror = function triggerJSNotLoaded(e) {
if (pop === true) { if (pop === true) {
// Drop the current loading klass info used by selector // Drop the current loading klass info used by selector
gadget_loading_klass_list.shift(); gadget_loading_klass_list.shift();
...@@ -1150,7 +1145,8 @@ ...@@ -1150,7 +1145,8 @@
}; };
newScript.src = url; newScript.src = url;
container.appendChild(newScript); container.appendChild(newScript);
}); }
);
} }
return result; return result;
}; };
...@@ -1158,7 +1154,7 @@ ...@@ -1158,7 +1154,7 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.declareCSS // renderJS.declareCSS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareCSS = function (url, container) { renderJS.declareCSS = function declareCSS(url, container) {
// https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js // https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
// No way to cleanly check if a css has been loaded // No way to cleanly check if a css has been loaded
// So, always resolve the promise... // So, always resolve the promise...
...@@ -1167,19 +1163,17 @@ ...@@ -1167,19 +1163,17 @@
if (stylesheet_registration_dict.hasOwnProperty(url)) { if (stylesheet_registration_dict.hasOwnProperty(url)) {
result = RSVP.resolve(); result = RSVP.resolve();
} else { } else {
result = new RSVP.Promise(function (resolve, reject) { result = new RSVP.Promise(function waitForCSSLoadEvent(resolve, reject) {
var link; var link;
link = document.createElement('link'); link = document.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.type = 'text/css'; link.type = 'text/css';
link.href = url; link.href = url;
link.onload = function () { link.onload = function triggerCSSLoaded() {
stylesheet_registration_dict[url] = null; stylesheet_registration_dict[url] = null;
resolve(); resolve();
}; };
link.onerror = function (e) { link.onerror = reject;
reject(e);
};
container.appendChild(link); container.appendChild(link);
}); });
} }
...@@ -1195,7 +1189,7 @@ ...@@ -1195,7 +1189,7 @@
key, key,
parsed_html; parsed_html;
// Class inheritance // Class inheritance
tmp_constructor = function () { tmp_constructor = function createSuperKlass() {
RenderJSGadget.call(this); RenderJSGadget.call(this);
}; };
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice(); tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
...@@ -1241,7 +1235,7 @@ ...@@ -1241,7 +1235,7 @@
return tmp_constructor; return tmp_constructor;
} }
renderJS.declareGadgetKlass = function (url) { renderJS.declareGadgetKlass = function declareGadgetKlass(url) {
if (gadget_model_defer_dict.hasOwnProperty(url)) { if (gadget_model_defer_dict.hasOwnProperty(url)) {
// Return klass object if it already exists // Return klass object if it already exists
return gadget_model_defer_dict[url].promise; return gadget_model_defer_dict[url].promise;
...@@ -1254,10 +1248,10 @@ ...@@ -1254,10 +1248,10 @@
// 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 waitForGadgetKlassAjax() {
return ajax(url); return ajax(url);
}) })
.push(function (result) { .push(function handleGadgetKlassAjax(result) {
tmp_constructor = parse(result, url); tmp_constructor = parse(result, url);
var fragment = document.createDocumentFragment(), var fragment = document.createDocumentFragment(),
promise_list = [], promise_list = [],
...@@ -1279,11 +1273,11 @@ ...@@ -1279,11 +1273,11 @@
document.head.appendChild(fragment); document.head.appendChild(fragment);
return RSVP.all(promise_list); return RSVP.all(promise_list);
}) })
.push(function () { .push(function handleGadgetKlassLoadingSuccess() {
defer.resolve(tmp_constructor); defer.resolve(tmp_constructor);
return tmp_constructor; return tmp_constructor;
}) })
.push(undefined, function (e) { .push(undefined, function handleGadgetKlassLoadingError(e) {
// Drop the current loading klass info used by selector // Drop the current loading klass info used by selector
// even in case of error // even in case of error
defer.reject(e); defer.reject(e);
...@@ -1295,7 +1289,7 @@ ...@@ -1295,7 +1289,7 @@
// renderJS.clearGadgetKlassList // renderJS.clearGadgetKlassList
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// For test purpose only // For test purpose only
renderJS.clearGadgetKlassList = function () { renderJS.clearGadgetKlassList = function clearGadgetKlassList() {
gadget_model_defer_dict = {}; gadget_model_defer_dict = {};
javascript_registration_dict = {}; javascript_registration_dict = {};
stylesheet_registration_dict = {}; stylesheet_registration_dict = {};
...@@ -1304,7 +1298,8 @@ ...@@ -1304,7 +1298,8 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.parseGadgetHTMLDocument // renderJS.parseGadgetHTMLDocument
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.parseGadgetHTMLDocument = function (document_element, url) { renderJS.parseGadgetHTMLDocument =
function parseGadgetHTMLDocument(document_element, url) {
var settings = { var settings = {
title: "", title: "",
interface_list: [], interface_list: [],
...@@ -1370,7 +1365,7 @@ ...@@ -1370,7 +1365,7 @@
// is triggered before everything was ready. // is triggered before everything was ready.
// (For instance, the HTML-tag for the self gadget gets inserted after // (For instance, the HTML-tag for the self gadget gets inserted after
// page load) // page load)
renderJS.manualBootstrap = function () { renderJS.manualBootstrap = function manualBootstrap() {
all_dependency_loaded_deferred.resolve(); all_dependency_loaded_deferred.resolve();
}; };
document.addEventListener('DOMContentLoaded', document.addEventListener('DOMContentLoaded',
...@@ -1398,7 +1393,7 @@ ...@@ -1398,7 +1393,7 @@
TmpConstructor.__template_element.appendChild(fragment); TmpConstructor.__template_element.appendChild(fragment);
return RSVP.all([root_gadget.getRequiredJSList(), return RSVP.all([root_gadget.getRequiredJSList(),
root_gadget.getRequiredCSSList()]) root_gadget.getRequiredCSSList()])
.then(function (all_list) { .then(function handleRequireDependencyList(all_list) {
var i, var i,
js_list = all_list[0], js_list = all_list[0],
css_list = all_list[1]; css_list = all_list[1];
...@@ -1409,14 +1404,14 @@ ...@@ -1409,14 +1404,14 @@
stylesheet_registration_dict[css_list[i]] = null; stylesheet_registration_dict[css_list[i]] = null;
} }
gadget_loading_klass_list.shift(); gadget_loading_klass_list.shift();
}).then(function () { }).then(function createMutationObserver() {
// select the target node // select the target node
var target = document.querySelector('body'), var target = document.querySelector('body'),
// create an observer instance // create an observer instance
observer = new MutationObserver(function (mutations) { observer = new MutationObserver(function observeMutatios(mutations) {
var i, k, len, len2, node, added_list; var i, k, len, len2, node, added_list;
mutations.forEach(function (mutation) { mutations.forEach(function observerMutation(mutation) {
if (mutation.type === 'childList') { if (mutation.type === 'childList') {
len = mutation.removedNodes.length; len = mutation.removedNodes.length;
...@@ -1425,7 +1420,7 @@ ...@@ -1425,7 +1420,7 @@
if (node.nodeType === Node.ELEMENT_NODE) { if (node.nodeType === Node.ELEMENT_NODE) {
if (node.hasAttribute("data-gadget-url") && if (node.hasAttribute("data-gadget-url") &&
(node._gadget !== undefined)) { (node._gadget !== undefined)) {
createMonitor(node._gadget); createGadgetMonitor(node._gadget);
} }
added_list = added_list =
node.querySelectorAll("[data-gadget-url]"); node.querySelectorAll("[data-gadget-url]");
...@@ -1433,7 +1428,7 @@ ...@@ -1433,7 +1428,7 @@
for (k = 0; k < len2; k += 1) { for (k = 0; k < len2; k += 1) {
node = added_list[k]; node = added_list[k];
if (node._gadget !== undefined) { if (node._gadget !== undefined) {
createMonitor(node._gadget); createGadgetMonitor(node._gadget);
} }
} }
} }
...@@ -1484,13 +1479,13 @@ ...@@ -1484,13 +1479,13 @@
function createLastAcquisitionGadget() { function createLastAcquisitionGadget() {
var last_acquisition_gadget = new RenderJSGadget(); var last_acquisition_gadget = new RenderJSGadget();
last_acquisition_gadget.__acquired_method_dict = { last_acquisition_gadget.__acquired_method_dict = {
reportServiceError: function (param_list) { reportServiceError: function reportServiceError(param_list) {
letsCrash(param_list[0]); letsCrash(param_list[0]);
} }
}; };
// Stop acquisition on the last acquisition gadget // Stop acquisition on the last acquisition gadget
// Do not put this on the klass, as their could be multiple instances // Do not put this on the klass, as their could be multiple instances
last_acquisition_gadget.__aq_parent = function (method_name) { last_acquisition_gadget.__aq_parent = function __aq_parent(method_name) {
throw new renderJS.AcquisitionError( throw new renderJS.AcquisitionError(
"No gadget provides " + method_name "No gadget provides " + method_name
); );
...@@ -1538,7 +1533,7 @@ ...@@ -1538,7 +1533,7 @@
]; ];
// Inform parent gadget about declareMethod calls here. // Inform parent gadget about declareMethod calls here.
notifyDeclareMethod = function (name) { notifyDeclareMethod = function notifyDeclareMethod(name) {
declare_method_list_waiting.push(name); declare_method_list_waiting.push(name);
}; };
...@@ -1551,13 +1546,13 @@ ...@@ -1551,13 +1546,13 @@
loading_result = RSVP.any([ loading_result = RSVP.any([
channel_defer.promise, channel_defer.promise,
new RSVP.Queue() new RSVP.Queue()
.push(function () { .push(function waitForParentChannelCreation() {
// Expect the channel to parent to be usable after 1 second // Expect the channel to parent to be usable after 1 second
// If not, consider the gadget as the root // If not, consider the gadget as the root
// Drop all iframe channel communication // Drop all iframe channel communication
return RSVP.delay(1000); return RSVP.delay(1000);
}) })
.push(function () { .push(function handleParentChannelCreation() {
real_result_list[2] = undefined; real_result_list[2] = undefined;
return real_result_list; return real_result_list;
}) })
...@@ -1567,20 +1562,22 @@ ...@@ -1567,20 +1562,22 @@
window: window.parent, window: window.parent,
origin: "*", origin: "*",
scope: "renderJS", scope: "renderJS",
onReady: function () { onReady: function onChannelReady() {
var k, var k,
len; len;
// Channel is ready, so now declare all methods // Channel is ready, so now declare all methods
notifyDeclareMethod = function (name) { notifyDeclareMethod = function notifyDeclareMethod(name) {
declare_method_list_waiting.push( declare_method_list_waiting.push(
new RSVP.Promise(function (resolve, reject) { new RSVP.Promise(
function promiseChannelDeclareMethodCall(resolve, reject) {
embedded_channel.call({ embedded_channel.call({
method: "declareMethod", method: "declareMethod",
params: name, params: name,
success: resolve, success: resolve,
error: reject error: reject
}); });
}) }
)
); );
}; };
...@@ -1596,7 +1593,7 @@ ...@@ -1596,7 +1593,7 @@
} }
// Surcharge declareMethod to inform parent window // Surcharge declareMethod to inform parent window
TmpConstructor.declareMethod = function (name, callback) { TmpConstructor.declareMethod = function declareMethod(name, callback) {
var result = RenderJSGadget.declareMethod.apply( var result = RenderJSGadget.declareMethod.apply(
this, this,
[name, callback] [name, callback]
...@@ -1633,11 +1630,11 @@ ...@@ -1633,11 +1630,11 @@
return root_gadget; return root_gadget;
} }
function ready_executable_wrapper(fct) { function ready_executable_wrapper(fct) {
return function (g) { return function wrapReadyFunction(g) {
return fct.call(g, g); return fct.call(g, g);
}; };
} }
TmpConstructor.ready(function () { TmpConstructor.ready(function startServiceInReady() {
return startService(this); return startService(this);
}); });
...@@ -1656,33 +1653,30 @@ ...@@ -1656,33 +1653,30 @@
embedded_channel) { embedded_channel) {
// Define __aq_parent to inform parent window // Define __aq_parent to inform parent window
root_gadget.__aq_parent = root_gadget.__aq_parent =
TmpConstructor.prototype.__aq_parent = function (method_name, TmpConstructor.prototype.__aq_parent = function aq_parent(method_name,
argument_list, argument_list,
time_out) { time_out) {
return new RSVP.Promise(function (resolve, reject) { return new RSVP.Promise(
function waitForChannelAcquire(resolve, reject) {
embedded_channel.call({ embedded_channel.call({
method: "acquire", method: "acquire",
params: [ params: [
method_name, method_name,
argument_list argument_list
], ],
success: function (s) { success: resolve,
resolve(s); error: reject,
},
error: function (e) {
reject(e);
},
timeout: time_out timeout: time_out
}); });
}); }
);
}; };
// bind calls to renderJS method on the instance // bind calls to renderJS method on the instance
embedded_channel.bind("methodCall", function (trans, v) { embedded_channel.bind("methodCall", function methodCall(trans, v) {
root_gadget[v[0]].apply(root_gadget, v[1]) root_gadget[v[0]].apply(root_gadget, v[1])
.push(function (g) { .push(trans.complete,
trans.complete(g); function handleMethodCallError(e) {
}, function (e) {
trans.error(e.toString()); trans.error(e.toString());
}); });
trans.delayReturn(true); trans.delayReturn(true);
...@@ -1698,11 +1692,11 @@ ...@@ -1698,11 +1692,11 @@
declare_method_list_waiting; declare_method_list_waiting;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function waitForLoadingGadget() {
// Wait for the loading gadget to be created // Wait for the loading gadget to be created
return wait_for_gadget_loaded; return wait_for_gadget_loaded;
}) })
.push(function (result_list) { .push(function handleLoadingGadget(result_list) {
TmpConstructor = result_list[0]; TmpConstructor = result_list[0];
root_gadget = result_list[1]; root_gadget = result_list[1];
embedded_channel = result_list[2]; embedded_channel = result_list[2];
...@@ -1710,11 +1704,11 @@ ...@@ -1710,11 +1704,11 @@
// Wait for all the gadget dependencies to be loaded // Wait for all the gadget dependencies to be loaded
return all_dependency_loaded_deferred.promise; return all_dependency_loaded_deferred.promise;
}) })
.push(function () { .push(function waitForDeclareMethodList() {
// Wait for all methods to be correctly declared // Wait for all methods to be correctly declared
return RSVP.all(declare_method_list_waiting); return RSVP.all(declare_method_list_waiting);
}) })
.push(function (result_list) { .push(function waitForMutationObserver(result_list) {
if (embedded_channel !== undefined) { if (embedded_channel !== undefined) {
finishAqParentConfiguration(TmpConstructor, root_gadget, finishAqParentConfiguration(TmpConstructor, root_gadget,
embedded_channel); embedded_channel);
...@@ -1722,16 +1716,16 @@ ...@@ -1722,16 +1716,16 @@
// Check all DOM modifications to correctly start/stop services // Check all DOM modifications to correctly start/stop services
return configureMutationObserver(TmpConstructor, url, root_gadget); return configureMutationObserver(TmpConstructor, url, root_gadget);
}) })
.push(function () { .push(function waitForReadyList() {
// Trigger all ready functions // Trigger all ready functions
return triggerReadyList(TmpConstructor, root_gadget); return triggerReadyList(TmpConstructor, root_gadget);
}) })
.push(function () { .push(function notifyReady() {
if (embedded_channel !== undefined) { if (embedded_channel !== undefined) {
embedded_channel.notify({method: "ready"}); embedded_channel.notify({method: "ready"});
} }
}) })
.push(undefined, function (e) { .push(undefined, function handleBootstrapError(e) {
letsCrash(e); letsCrash(e);
if (embedded_channel !== undefined) { if (embedded_channel !== undefined) {
embedded_channel.notify({method: "failed", params: e.toString()}); embedded_channel.notify({method: "failed", params: e.toString()});
......
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