Commit b3ca6f36 authored by Romain Courteaud's avatar Romain Courteaud

Release version 0.13.0

Performance improvements.
parent 8677f05a
/*
* js_channel is a very lightweight abstraction on top of
* postMessage which defines message formats and semantics
* to support interactions more rich than just message passing
* js_channel supports:
* + query/response - traditional rpc
* + query/update/response - incremental async return of results
* to a query
* + notifications - fire and forget
* + error handling
*
* js_channel is based heavily on json-rpc, but is focused at the
* problem of inter-iframe RPC.
*
* Message types:
* There are 5 types of messages that can flow over this channel,
* and you may determine what type of message an object is by
* examining its parameters:
* 1. Requests
* + integer id
* + string method
* + (optional) any params
* 2. Callback Invocations (or just "Callbacks")
* + integer id
* + string callback
* + (optional) params
* 3. Error Responses (or just "Errors)
* + integer id
* + string error
* + (optional) string message
* 4. Responses
* + integer id
* + (optional) any result
* 5. Notifications
* + string method
* + (optional) any params
*/
;var Channel = (function() {
"use strict";
// current transaction id, start out at a random *odd* number between 1 and a million
// There is one current transaction counter id per page, and it's shared between
// channel instances. That means of all messages posted from a single javascript
// evaluation context, we'll never have two with the same id.
var s_curTranId = Math.floor(Math.random()*1000001);
// no two bound channels in the same javascript evaluation context may have the same origin, scope, and window.
// futher if two bound channels have the same window and scope, they may not have *overlapping* origins
// (either one or both support '*'). This restriction allows a single onMessage handler to efficiently
// route messages based on origin and scope. The s_boundChans maps origins to scopes, to message
// handlers. Request and Notification messages are routed using this table.
// Finally, channels are inserted into this table when built, and removed when destroyed.
var s_boundChans = { };
// add a channel to s_boundChans, throwing if a dup exists
function s_addBoundChan(win, origin, scope, handler) {
function hasWin(arr) {
for (var i = 0; i < arr.length; i++) if (arr[i].win === win) return true;
return false;
}
// does she exist?
var exists = false;
if (origin === '*') {
// we must check all other origins, sadly.
for (var k in s_boundChans) {
if (!s_boundChans.hasOwnProperty(k)) continue;
if (k === '*') continue;
if (typeof s_boundChans[k][scope] === 'object') {
exists = hasWin(s_boundChans[k][scope]);
if (exists) break;
}
}
} else {
// we must check only '*'
if ((s_boundChans['*'] && s_boundChans['*'][scope])) {
exists = hasWin(s_boundChans['*'][scope]);
}
if (!exists && s_boundChans[origin] && s_boundChans[origin][scope])
{
exists = hasWin(s_boundChans[origin][scope]);
}
}
if (exists) throw "A channel is already bound to the same window which overlaps with origin '"+ origin +"' and has scope '"+scope+"'";
if (typeof s_boundChans[origin] != 'object') s_boundChans[origin] = { };
if (typeof s_boundChans[origin][scope] != 'object') s_boundChans[origin][scope] = [ ];
s_boundChans[origin][scope].push({win: win, handler: handler});
}
function s_removeBoundChan(win, origin, scope) {
var arr = s_boundChans[origin][scope];
for (var i = 0; i < arr.length; i++) {
if (arr[i].win === win) {
arr.splice(i,1);
}
}
if (s_boundChans[origin][scope].length === 0) {
delete s_boundChans[origin][scope];
}
}
function s_isArray(obj) {
if (Array.isArray) return Array.isArray(obj);
else {
return (obj.constructor.toString().indexOf("Array") != -1);
}
}
// No two outstanding outbound messages may have the same id, period. Given that, a single table
// mapping "transaction ids" to message handlers, allows efficient routing of Callback, Error, and
// Response messages. Entries are added to this table when requests are sent, and removed when
// responses are received.
var s_transIds = { };
// class singleton onMessage handler
// this function is registered once and all incoming messages route through here. This
// arrangement allows certain efficiencies, message data is only parsed once and dispatch
// is more efficient, especially for large numbers of simultaneous channels.
var s_onMessage = function(e) {
try {
var m = JSON.parse(e.data);
if (typeof m !== 'object' || m === null) throw "malformed";
} catch(e) {
// just ignore any posted messages that do not consist of valid JSON
return;
}
var w = e.source;
var o = e.origin;
var s, i, meth;
if (typeof m.method === 'string') {
var ar = m.method.split('::');
if (ar.length == 2) {
s = ar[0];
meth = ar[1];
} else {
meth = m.method;
}
}
if (typeof m.id !== 'undefined') i = m.id;
// w is message source window
// o is message origin
// m is parsed message
// s is message scope
// i is message id (or undefined)
// meth is unscoped method name
// ^^ based on these factors we can route the message
// if it has a method it's either a notification or a request,
// route using s_boundChans
if (typeof meth === 'string') {
var delivered = false;
if (s_boundChans[o] && s_boundChans[o][s]) {
for (var j = 0; j < s_boundChans[o][s].length; j++) {
if (s_boundChans[o][s][j].win === w) {
s_boundChans[o][s][j].handler(o, meth, m);
delivered = true;
break;
}
}
}
if (!delivered && s_boundChans['*'] && s_boundChans['*'][s]) {
for (var j = 0; j < s_boundChans['*'][s].length; j++) {
if (s_boundChans['*'][s][j].win === w) {
s_boundChans['*'][s][j].handler(o, meth, m);
break;
}
}
}
}
// otherwise it must have an id (or be poorly formed
else if (typeof i != 'undefined') {
if (s_transIds[i]) s_transIds[i](o, meth, m);
}
};
// Setup postMessage event listeners
if (window.addEventListener) window.addEventListener('message', s_onMessage, false);
else if(window.attachEvent) window.attachEvent('onmessage', s_onMessage);
/* a messaging channel is constructed from a window and an origin.
* the channel will assert that all messages received over the
* channel match the origin
*
* Arguments to Channel.build(cfg):
*
* cfg.window - the remote window with which we'll communicate
* cfg.origin - the expected origin of the remote window, may be '*'
* which matches any origin
* cfg.scope - the 'scope' of messages. a scope string that is
* prepended to message names. local and remote endpoints
* of a single channel must agree upon scope. Scope may
* not contain double colons ('::').
* cfg.debugOutput - A boolean value. If true and window.console.log is
* a function, then debug strings will be emitted to that
* function.
* cfg.debugOutput - A boolean value. If true and window.console.log is
* a function, then debug strings will be emitted to that
* function.
* cfg.postMessageObserver - A function that will be passed two arguments,
* an origin and a message. It will be passed these immediately
* before messages are posted.
* cfg.gotMessageObserver - A function that will be passed two arguments,
* an origin and a message. It will be passed these arguments
* immediately after they pass scope and origin checks, but before
* they are processed.
* cfg.onReady - A function that will be invoked when a channel becomes "ready",
* this occurs once both sides of the channel have been
* instantiated and an application level handshake is exchanged.
* the onReady function will be passed a single argument which is
* the channel object that was returned from build().
*/
return {
build: function(cfg) {
var debug = function(m) {
if (cfg.debugOutput && window.console && window.console.log) {
// try to stringify, if it doesn't work we'll let javascript's built in toString do its magic
try { if (typeof m !== 'string') m = JSON.stringify(m); } catch(e) { }
console.log("["+chanId+"] " + m);
}
};
/* browser capabilities check */
if (!window.postMessage) throw("jschannel cannot run this browser, no postMessage");
if (!window.JSON || !window.JSON.stringify || ! window.JSON.parse) {
throw("jschannel cannot run this browser, no JSON parsing/serialization");
}
/* basic argument validation */
if (typeof cfg != 'object') throw("Channel build invoked without a proper object argument");
if (!cfg.window || !cfg.window.postMessage) throw("Channel.build() called without a valid window argument");
/* we'd have to do a little more work to be able to run multiple channels that intercommunicate the same
* window... Not sure if we care to support that */
if (window === cfg.window) throw("target window is same as present window -- not allowed");
// let's require that the client specify an origin. if we just assume '*' we'll be
// propagating unsafe practices. that would be lame.
var validOrigin = false;
if (typeof cfg.origin === 'string') {
var oMatch;
if (cfg.origin === "*") validOrigin = true;
// allow valid domains under http and https. Also, trim paths off otherwise valid origins.
else if (null !== (oMatch = cfg.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))) {
cfg.origin = oMatch[0].toLowerCase();
validOrigin = true;
}
}
if (!validOrigin) throw ("Channel.build() called with an invalid origin");
if (typeof cfg.scope !== 'undefined') {
if (typeof cfg.scope !== 'string') throw 'scope, when specified, must be a string';
if (cfg.scope.split('::').length > 1) throw "scope may not contain double colons: '::'";
}
/* private variables */
// generate a random and psuedo unique id for this channel
var chanId = (function () {
var text = "";
var alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for(var i=0; i < 5; i++) text += alpha.charAt(Math.floor(Math.random() * alpha.length));
return text;
})();
// registrations: mapping method names to call objects
var regTbl = { };
// current oustanding sent requests
var outTbl = { };
// current oustanding received requests
var inTbl = { };
// are we ready yet? when false we will block outbound messages.
var ready = false;
var pendingQueue = [ ];
var createTransaction = function(id,origin,callbacks) {
var shouldDelayReturn = false;
var completed = false;
return {
origin: origin,
invoke: function(cbName, v) {
// verify in table
if (!inTbl[id]) throw "attempting to invoke a callback of a nonexistent transaction: " + id;
// verify that the callback name is valid
var valid = false;
for (var i = 0; i < callbacks.length; i++) if (cbName === callbacks[i]) { valid = true; break; }
if (!valid) throw "request supports no such callback '" + cbName + "'";
// send callback invocation
postMessage({ id: id, callback: cbName, params: v});
},
error: function(error, message) {
completed = true;
// verify in table
if (!inTbl[id]) throw "error called for nonexistent message: " + id;
// remove transaction from table
delete inTbl[id];
// send error
postMessage({ id: id, error: error, message: message });
},
complete: function(v) {
completed = true;
// verify in table
if (!inTbl[id]) throw "complete called for nonexistent message: " + id;
// remove transaction from table
delete inTbl[id];
// send complete
postMessage({ id: id, result: v });
},
delayReturn: function(delay) {
if (typeof delay === 'boolean') {
shouldDelayReturn = (delay === true);
}
return shouldDelayReturn;
},
completed: function() {
return completed;
}
};
};
var setTransactionTimeout = function(transId, timeout, method) {
return window.setTimeout(function() {
if (outTbl[transId]) {
// XXX: what if client code raises an exception here?
var msg = "timeout (" + timeout + "ms) exceeded on method '" + method + "'";
(1,outTbl[transId].error)("timeout_error", msg);
delete outTbl[transId];
delete s_transIds[transId];
}
}, timeout);
};
var onMessage = function(origin, method, m) {
// if an observer was specified at allocation time, invoke it
if (typeof cfg.gotMessageObserver === 'function') {
// pass observer a clone of the object so that our
// manipulations are not visible (i.e. method unscoping).
// This is not particularly efficient, but then we expect
// that message observers are primarily for debugging anyway.
try {
cfg.gotMessageObserver(origin, m);
} catch (e) {
debug("gotMessageObserver() raised an exception: " + e.toString());
}
}
// now, what type of message is this?
if (m.id && method) {
// a request! do we have a registered handler for this request?
if (regTbl[method]) {
var trans = createTransaction(m.id, origin, m.callbacks ? m.callbacks : [ ]);
inTbl[m.id] = { };
try {
// callback handling. we'll magically create functions inside the parameter list for each
// callback
if (m.callbacks && s_isArray(m.callbacks) && m.callbacks.length > 0) {
for (var i = 0; i < m.callbacks.length; i++) {
var path = m.callbacks[i];
var obj = m.params;
var pathItems = path.split('/');
for (var j = 0; j < pathItems.length - 1; j++) {
var cp = pathItems[j];
if (typeof obj[cp] !== 'object') obj[cp] = { };
obj = obj[cp];
}
obj[pathItems[pathItems.length - 1]] = (function() {
var cbName = path;
return function(params) {
return trans.invoke(cbName, params);
};
})();
}
}
var resp = regTbl[method](trans, m.params);
if (!trans.delayReturn() && !trans.completed()) trans.complete(resp);
} catch(e) {
// automagic handling of exceptions:
var error = "runtime_error";
var message = null;
// * if it's a string then it gets an error code of 'runtime_error' and string is the message
if (typeof e === 'string') {
message = e;
} else if (typeof e === 'object') {
// either an array or an object
// * if it's an array of length two, then array[0] is the code, array[1] is the error message
if (e && s_isArray(e) && e.length == 2) {
error = e[0];
message = e[1];
}
// * if it's an object then we'll look form error and message parameters
else if (typeof e.error === 'string') {
error = e.error;
if (!e.message) message = "";
else if (typeof e.message === 'string') message = e.message;
else e = e.message; // let the stringify/toString message give us a reasonable verbose error string
}
}
// message is *still* null, let's try harder
if (message === null) {
try {
message = JSON.stringify(e);
/* On MSIE8, this can result in 'out of memory', which
* leaves message undefined. */
if (typeof(message) == 'undefined')
message = e.toString();
} catch (e2) {
message = e.toString();
}
}
trans.error(error,message);
}
}
} else if (m.id && m.callback) {
if (!outTbl[m.id] ||!outTbl[m.id].callbacks || !outTbl[m.id].callbacks[m.callback])
{
debug("ignoring invalid callback, id:"+m.id+ " (" + m.callback +")");
} else {
// XXX: what if client code raises an exception here?
outTbl[m.id].callbacks[m.callback](m.params);
}
} else if (m.id) {
if (!outTbl[m.id]) {
debug("ignoring invalid response: " + m.id);
} else {
// XXX: what if client code raises an exception here?
if (m.error) {
(1,outTbl[m.id].error)(m.error, m.message);
} else {
if (m.result !== undefined) (1,outTbl[m.id].success)(m.result);
else (1,outTbl[m.id].success)();
}
delete outTbl[m.id];
delete s_transIds[m.id];
}
} else if (method) {
// tis a notification.
if (regTbl[method]) {
// yep, there's a handler for that.
// transaction has only origin for notifications.
regTbl[method]({ origin: origin }, m.params);
// if the client throws, we'll just let it bubble out
// what can we do? Also, here we'll ignore return values
}
}
};
// now register our bound channel for msg routing
s_addBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''), onMessage);
// scope method names based on cfg.scope specified when the Channel was instantiated
var scopeMethod = function(m) {
if (typeof cfg.scope === 'string' && cfg.scope.length) m = [cfg.scope, m].join("::");
return m;
};
// a small wrapper around postmessage whose primary function is to handle the
// case that clients start sending messages before the other end is "ready"
var postMessage = function(msg, force) {
if (!msg) throw "postMessage called with null message";
// delay posting if we're not ready yet.
var verb = (ready ? "post " : "queue ");
debug(verb + " message: " + JSON.stringify(msg));
if (!force && !ready) {
pendingQueue.push(msg);
} else {
if (typeof cfg.postMessageObserver === 'function') {
try {
cfg.postMessageObserver(cfg.origin, msg);
} catch (e) {
debug("postMessageObserver() raised an exception: " + e.toString());
}
}
cfg.window.postMessage(JSON.stringify(msg), cfg.origin);
}
};
var onReady = function(trans, type) {
debug('ready msg received');
if (ready) throw "received ready message while in ready state. help!";
if (type === 'ping') {
chanId += '-R';
} else {
chanId += '-L';
}
obj.unbind('__ready'); // now this handler isn't needed any more.
ready = true;
debug('ready msg accepted.');
if (type === 'ping') {
obj.notify({ method: '__ready', params: 'pong' });
}
// flush queue
while (pendingQueue.length) {
postMessage(pendingQueue.pop());
}
// invoke onReady observer if provided
if (typeof cfg.onReady === 'function') cfg.onReady(obj);
};
var obj = {
// tries to unbind a bound message handler. returns false if not possible
unbind: function (method) {
if (regTbl[method]) {
if (!(delete regTbl[method])) throw ("can't delete method: " + method);
return true;
}
return false;
},
bind: function (method, cb) {
if (!method || typeof method !== 'string') throw "'method' argument to bind must be string";
if (!cb || typeof cb !== 'function') throw "callback missing from bind params";
if (regTbl[method]) throw "method '"+method+"' is already bound!";
regTbl[method] = cb;
return this;
},
call: function(m) {
if (!m) throw 'missing arguments to call function';
if (!m.method || typeof m.method !== 'string') throw "'method' argument to call must be string";
if (!m.success || typeof m.success !== 'function') throw "'success' callback missing from call";
// now it's time to support the 'callback' feature of jschannel. We'll traverse the argument
// object and pick out all of the functions that were passed as arguments.
var callbacks = { };
var callbackNames = [ ];
var pruneFunctions = function (path, obj) {
if (typeof obj === 'object') {
for (var k in obj) {
if (!obj.hasOwnProperty(k)) continue;
var np = path + (path.length ? '/' : '') + k;
if (typeof obj[k] === 'function') {
callbacks[np] = obj[k];
callbackNames.push(np);
delete obj[k];
} else if (typeof obj[k] === 'object') {
pruneFunctions(np, obj[k]);
}
}
}
};
pruneFunctions("", m.params);
// build a 'request' message and send it
var msg = { id: s_curTranId, method: scopeMethod(m.method), params: m.params };
if (callbackNames.length) msg.callbacks = callbackNames;
if (m.timeout)
// XXX: This function returns a timeout ID, but we don't do anything with it.
// We might want to keep track of it so we can cancel it using clearTimeout()
// when the transaction completes.
setTransactionTimeout(s_curTranId, m.timeout, scopeMethod(m.method));
// insert into the transaction table
outTbl[s_curTranId] = { callbacks: callbacks, error: m.error, success: m.success };
s_transIds[s_curTranId] = onMessage;
// increment current id
s_curTranId++;
postMessage(msg);
},
notify: function(m) {
if (!m) throw 'missing arguments to notify function';
if (!m.method || typeof m.method !== 'string') throw "'method' argument to notify must be string";
// no need to go into any transaction table
postMessage({ method: scopeMethod(m.method), params: m.params });
},
destroy: function () {
s_removeBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''));
if (window.removeEventListener) window.removeEventListener('message', onMessage, false);
else if(window.detachEvent) window.detachEvent('onmessage', onMessage);
ready = false;
regTbl = { };
inTbl = { };
outTbl = { };
cfg.origin = null;
pendingQueue = [ ];
debug("channel destroyed");
chanId = "";
}
};
obj.bind('__ready', onReady);
setTimeout(function() {
postMessage({ method: scopeMethod('__ready'), params: "ping" }, true);
}, 0);
return obj;
}
};
})();
;/*
* DOMParser HTML extension
* 2012-09-04
*
* By Eli Grey, http://eligrey.com
* Public domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*! @source https://gist.github.com/1129031 */
(function (DOMParser) {
"use strict";
var DOMParser_proto = DOMParser.prototype,
real_parseFromString = DOMParser_proto.parseFromString;
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if ((new DOMParser()).parseFromString("", "text/html")) {
// text/html parsing is natively supported
return;
}
} catch (ignore) {}
DOMParser_proto.parseFromString = function (markup, type) {
var result, doc, doc_elt, first_elt;
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
doc = document.implementation.createHTMLDocument("");
doc_elt = doc.documentElement;
doc_elt.innerHTML = markup;
first_elt = doc_elt.firstElementChild;
if (doc_elt.childElementCount === 1
&& first_elt.localName.toLowerCase() === "html") {
doc.replaceChild(first_elt, doc_elt);
}
result = doc;
} else {
result = real_parseFromString.apply(this, arguments);
}
return result;
};
}(DOMParser));
;// IE does not support have Document.prototype.contains.
if (typeof document.contains !== 'function') {
Document.prototype.contains = function(node) {
if (node === this || node.parentNode === this)
return true;
return this.documentElement.contains(node);
}
}
;/*! RenderJs */
/*jslint nomen: true*/
/*
* renderJs - Generic Gadget library renderer.
* http://www.renderjs.org/documentation
*/
(function (document, window, RSVP, DOMParser, Channel, MutationObserver,
Node, FileReader, Blob, navigator, Event, URL) {
"use strict";
function readBlobAsDataURL(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject) {
fr.addEventListener("load", function (evt) {
resolve(evt.target.result);
});
fr.addEventListener("error", reject);
fr.readAsDataURL(blob);
}, function () {
fr.abort();
});
}
function loopEventListener(target, type, useCapture, callback,
prevent_default) {
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
if (prevent_default === undefined) {
prevent_default = true;
}
function cancelResolver() {
if ((callback_promise !== undefined) &&
(typeof callback_promise.cancel === "function")) {
callback_promise.cancel();
}
}
function canceller() {
if (handle_event_callback !== undefined) {
target.removeEventListener(type, handle_event_callback, useCapture);
}
cancelResolver();
}
function itsANonResolvableTrap(resolve, reject) {
var result;
handle_event_callback = function (evt) {
if (prevent_default) {
evt.stopPropagation();
evt.preventDefault();
}
cancelResolver();
try {
result = callback(evt);
} catch (e) {
result = RSVP.reject(e);
}
callback_promise = result;
new RSVP.Queue()
.push(function () {
return result;
})
.push(undefined, function (error) {
if (!(error instanceof RSVP.CancellationError)) {
canceller();
reject(error);
}
});
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(itsANonResolvableTrap, canceller);
}
function ajax(url) {
var xhr;
function resolver(resolve, reject) {
function handler() {
try {
if (xhr.readyState === 0) {
// UNSENT
reject(xhr);
} else if (xhr.readyState === 4) {
// DONE
if ((xhr.status < 200) || (xhr.status >= 300) ||
(!/^text\/html[;]?/.test(
xhr.getResponseHeader("Content-Type") || ""
))) {
reject(xhr);
} else {
resolve(xhr);
}
}
} catch (e) {
reject(e);
}
}
xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.setRequestHeader('Accept', 'text/html');
xhr.withCredentials = true;
xhr.send();
}
function canceller() {
if ((xhr !== undefined) && (xhr.readyState !== xhr.DONE)) {
xhr.abort();
}
}
return new RSVP.Promise(resolver, canceller);
}
var gadget_model_defer_dict = {},
javascript_registration_dict = {},
stylesheet_registration_dict = {},
gadget_loading_klass_list = [],
loading_klass_promise,
renderJS,
Monitor,
scope_increment = 0,
isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
is_page_unloaded = false,
error_list = [];
window.addEventListener('error', function (error) {
error_list.push(error);
});
window.addEventListener('beforeunload', function () {
// XXX If another listener cancel the page unload,
// it will not restore renderJS crash report
is_page_unloaded = true;
});
/////////////////////////////////////////////////////////////////
// Helper functions
/////////////////////////////////////////////////////////////////
function removeHash(url) {
var index = url.indexOf('#');
if (index > 0) {
url = url.substring(0, index);
}
return url;
}
function letsCrash(e) {
var i,
body,
container,
paragraph,
link,
error;
if (is_page_unloaded) {
/*global console*/
console.info('-- Error dropped, as page is unloaded');
console.info(e);
return;
}
error_list.push(e);
// Add error handling stack
error_list.push(new Error('stopping renderJS'));
body = document.getElementsByTagName('body')[0];
while (body.firstChild) {
body.removeChild(body.firstChild);
}
container = document.createElement("section");
paragraph = document.createElement("h1");
paragraph.textContent = 'Unhandled Error';
container.appendChild(paragraph);
paragraph = document.createElement("p");
paragraph.textContent = 'Please report this error to the support team';
container.appendChild(paragraph);
paragraph = document.createElement("p");
paragraph.textContent = 'Location: ';
link = document.createElement("a");
link.href = link.textContent = window.location.toString();
paragraph.appendChild(link);
container.appendChild(paragraph);
paragraph = document.createElement("p");
paragraph.textContent = 'User-agent: ' + navigator.userAgent;
container.appendChild(paragraph);
paragraph = document.createElement("p");
paragraph.textContent = 'Date: ' + new Date(Date.now()).toISOString();
container.appendChild(paragraph);
body.appendChild(container);
for (i = 0; i < error_list.length; i += 1) {
error = error_list[i];
if (error instanceof Event) {
error = {
string: error.toString(),
message: error.message,
type: error.type,
target: error.target
};
if (error.target !== undefined) {
error_list.splice(i + 1, 0, error.target);
}
}
if (error instanceof XMLHttpRequest) {
error = {
message: error.toString(),
readyState: error.readyState,
status: error.status,
statusText: error.statusText,
response: error.response,
responseUrl: error.responseUrl,
response_headers: error.getAllResponseHeaders()
};
}
if (error.constructor === Array ||
error.constructor === String ||
error.constructor === Object) {
try {
error = JSON.stringify(error);
} catch (ignore) {
}
}
container = document.createElement("section");
paragraph = document.createElement("h2");
paragraph.textContent = error.message || error;
container.appendChild(paragraph);
if (error.fileName !== undefined) {
paragraph = document.createElement("p");
paragraph.textContent = 'File: ' +
error.fileName +
': ' + error.lineNumber;
container.appendChild(paragraph);
}
if (error.stack !== undefined) {
paragraph = document.createElement("pre");
paragraph.textContent = 'Stack: ' + error.stack;
container.appendChild(paragraph);
}
body.appendChild(container);
}
// XXX Do not crash the application if it fails
// Where to write the error?
/*global console*/
console.error(e.stack);
console.error(e);
}
/////////////////////////////////////////////////////////////////
// Service Monitor promise
/////////////////////////////////////////////////////////////////
function ResolvedMonitorError(message) {
this.name = "resolved";
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Default Message";
}
ResolvedMonitorError.prototype = new Error();
ResolvedMonitorError.prototype.constructor = ResolvedMonitorError;
Monitor = function () {
var monitor = this,
promise_list = [],
promise,
reject,
notify,
resolved;
if (!(this instanceof Monitor)) {
return new Monitor();
}
function canceller() {
var len = promise_list.length,
i;
for (i = 0; i < len; i += 1) {
promise_list[i].cancel();
}
// Clean it to speed up other canceller run
promise_list = [];
}
promise = new RSVP.Promise(function (done, fail, progress) {
reject = function (rejectedReason) {
if (resolved) {
return;
}
monitor.isRejected = true;
monitor.rejectedReason = rejectedReason;
resolved = true;
canceller();
return fail(rejectedReason);
};
notify = progress;
}, canceller);
monitor.cancel = function () {
if (resolved) {
return;
}
resolved = true;
promise.cancel();
promise.fail(function (rejectedReason) {
monitor.isRejected = true;
monitor.rejectedReason = rejectedReason;
});
};
monitor.then = function () {
return promise.then.apply(promise, arguments);
};
monitor.fail = function () {
return promise.fail.apply(promise, arguments);
};
monitor.monitor = function (promise_to_monitor) {
if (resolved) {
throw new ResolvedMonitorError();
}
var queue = new RSVP.Queue()
.push(function () {
return promise_to_monitor;
})
.push(function (fulfillmentValue) {
// Promise to monitor is fullfilled, remove it from the list
var len = promise_list.length,
sub_promise_to_monitor,
new_promise_list = [],
i;
for (i = 0; i < len; i += 1) {
sub_promise_to_monitor = promise_list[i];
if (!(sub_promise_to_monitor.isFulfilled ||
sub_promise_to_monitor.isRejected)) {
new_promise_list.push(sub_promise_to_monitor);
}
}
promise_list = new_promise_list;
}, function (rejectedReason) {
if (rejectedReason instanceof RSVP.CancellationError) {
if (!(promise_to_monitor.isFulfilled &&
promise_to_monitor.isRejected)) {
// The queue could be cancelled before the first push is run
promise_to_monitor.cancel();
}
}
reject(rejectedReason);
throw rejectedReason;
}, function (notificationValue) {
notify(notificationValue);
return notificationValue;
});
promise_list.push(queue);
return this;
};
};
Monitor.prototype = Object.create(RSVP.Promise.prototype);
Monitor.prototype.constructor = Monitor;
/////////////////////////////////////////////////////////////////
// RenderJSGadget
/////////////////////////////////////////////////////////////////
function RenderJSGadget() {
if (!(this instanceof RenderJSGadget)) {
return new RenderJSGadget();
}
}
RenderJSGadget.prototype.__title = "";
RenderJSGadget.prototype.__interface_list = [];
RenderJSGadget.prototype.__path = "";
RenderJSGadget.prototype.__html = "";
RenderJSGadget.prototype.__required_css_list = [];
RenderJSGadget.prototype.__required_js_list = [];
function createMonitor(g) {
if (g.__monitor !== undefined) {
g.__monitor.cancel();
}
g.__monitor = new Monitor();
g.__job_dict = {};
g.__job_list = [];
g.__job_triggered = false;
g.__monitor.fail(function (error) {
if (!(error instanceof RSVP.CancellationError)) {
return g.aq_reportServiceError(error);
}
}).fail(function (error) {
// Crash the application if the acquisition generates an error.
return letsCrash(error);
});
}
function clearGadgetInternalParameters(g) {
g.__sub_gadget_dict = {};
createMonitor(g);
}
function loadSubGadgetDOMDeclaration(g) {
var element_list = g.element.querySelectorAll('[data-gadget-url]'),
element,
promise_list = [],
scope,
url,
sandbox,
i;
for (i = 0; i < element_list.length; i += 1) {
element = element_list[i];
scope = element.getAttribute("data-gadget-scope");
url = element.getAttribute("data-gadget-url");
sandbox = element.getAttribute("data-gadget-sandbox");
if (url !== null) {
promise_list.push(g.declareGadget(url, {
element: element,
scope: scope || undefined,
sandbox: sandbox || undefined
}));
}
}
return RSVP.all(promise_list);
}
RenderJSGadget.__ready_list = [clearGadgetInternalParameters,
loadSubGadgetDOMDeclaration];
RenderJSGadget.ready = function (callback) {
this.__ready_list.push(callback);
return this;
};
RenderJSGadget.setState = function (state_dict) {
var json_state = JSON.stringify(state_dict);
return this.ready(function () {
this.state = JSON.parse(json_state);
});
};
RenderJSGadget.onStateChange = function (callback) {
this.prototype.__state_change_callback = callback;
return this;
};
RenderJSGadget.__service_list = [];
RenderJSGadget.declareService = function (callback) {
this.__service_list.push(callback);
return this;
};
RenderJSGadget.onEvent = function (type, callback, use_capture,
prevent_default) {
this.__service_list.push(function () {
return loopEventListener(this.element, type, use_capture,
callback.bind(this), prevent_default);
});
return this;
};
function runJob(gadget, name, callback, argument_list) {
var job_promise = new RSVP.Queue()
.push(function () {
return callback.apply(gadget, argument_list);
});
if (gadget.__job_dict.hasOwnProperty(name)) {
gadget.__job_dict[name].cancel();
}
gadget.__job_dict[name] = job_promise;
gadget.__monitor.monitor(new RSVP.Queue()
.push(function () {
return job_promise;
})
.push(undefined, function (error) {
if (!(error instanceof RSVP.CancellationError)) {
throw error;
}
}));
}
function startService(gadget) {
gadget.__monitor.monitor(new RSVP.Queue()
.push(function () {
var i,
service_list = gadget.constructor.__service_list,
job_list = gadget.__job_list;
for (i = 0; i < service_list.length; i += 1) {
gadget.__monitor.monitor(service_list[i].apply(gadget));
}
for (i = 0; i < job_list.length; i += 1) {
runJob(gadget, job_list[i][0], job_list[i][1], job_list[i][2]);
}
gadget.__job_list = [];
gadget.__job_triggered = true;
})
);
}
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareJob
// gadget internal method, which trigger execution
// of a function inside a service
/////////////////////////////////////////////////////////////////
RenderJSGadget.declareJob = function (name, callback) {
this.prototype[name] = function () {
var context = this,
argument_list = arguments;
if (context.__job_triggered) {
runJob(context, name, callback, argument_list);
} else {
context.__job_list.push([name, callback, argument_list]);
}
};
// Allow chain
return this;
};
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareMethod
/////////////////////////////////////////////////////////////////
RenderJSGadget.declareMethod = function (name, callback) {
this.prototype[name] = function () {
var context = this,
argument_list = arguments;
return new RSVP.Queue()
.push(function () {
return callback.apply(context, argument_list);
});
};
// Allow chain
return this;
};
RenderJSGadget
.declareMethod('getInterfaceList', function () {
// Returns the list of gadget prototype
return this.__interface_list;
})
.declareMethod('getRequiredCSSList', function () {
// Returns a list of CSS required by the gadget
return this.__required_css_list;
})
.declareMethod('getRequiredJSList', function () {
// Returns a list of JS required by the gadget
return this.__required_js_list;
})
.declareMethod('getPath', function () {
// Returns the path of the code of a gadget
return this.__path;
})
.declareMethod('getTitle', function () {
// Returns the title of a gadget
return this.__title;
})
.declareMethod('getElement', function () {
// Returns the DOM Element of a gadget
// XXX Kept for compatibility. Use element property directly
if (this.element === undefined) {
throw new Error("No element defined");
}
return this.element;
})
.declareMethod('changeState', function (state_dict) {
var key,
modified = false,
previous_cancelled = this.hasOwnProperty('__modification_dict'),
modification_dict,
context = this;
if (previous_cancelled) {
modification_dict = this.__modification_dict;
modified = true;
} 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 () {
return context.__state_change_callback(modification_dict);
})
.push(function (result) {
delete context.__modification_dict;
return result;
});
}
});
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareAcquiredMethod
/////////////////////////////////////////////////////////////////
function acquire(child_gadget, method_name, argument_list) {
var gadget = this,
key,
gadget_scope;
for (key in gadget.__sub_gadget_dict) {
if (gadget.__sub_gadget_dict.hasOwnProperty(key)) {
if (gadget.__sub_gadget_dict[key] === child_gadget) {
gadget_scope = key;
}
}
}
return new RSVP.Queue()
.push(function () {
// Do not specify default __acquired_method_dict on prototype
// to prevent modifying this default value (with
// allowPublicAcquiredMethod for example)
var aq_dict = gadget.__acquired_method_dict || {};
if (aq_dict.hasOwnProperty(method_name)) {
return aq_dict[method_name].apply(gadget,
[argument_list, gadget_scope]);
}
throw new renderJS.AcquisitionError("aq_dynamic is not defined");
})
.push(undefined, function (error) {
if (error instanceof renderJS.AcquisitionError) {
return gadget.__aq_parent(method_name, argument_list);
}
throw error;
});
}
RenderJSGadget.declareAcquiredMethod =
function (name, method_name_to_acquire) {
this.prototype[name] = function () {
var argument_list = Array.prototype.slice.call(arguments, 0),
gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.__aq_parent(method_name_to_acquire, argument_list);
});
};
// Allow chain
return this;
};
RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
"reportServiceError");
/////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition
/////////////////////////////////////////////////////////////////
RenderJSGadget.allowPublicAcquisition =
function (method_name, callback) {
this.prototype.__acquired_method_dict[method_name] = callback;
// Allow chain
return this;
};
// Set aq_parent on gadget_instance which call acquire on parent_gadget
function setAqParent(gadget_instance, parent_gadget) {
gadget_instance.__aq_parent = function (method_name, argument_list) {
return acquire.apply(parent_gadget, [gadget_instance, method_name,
argument_list]);
};
}
/////////////////////////////////////////////////////////////////
// RenderJSEmbeddedGadget
/////////////////////////////////////////////////////////////////
// Class inheritance
function RenderJSEmbeddedGadget() {
if (!(this instanceof RenderJSEmbeddedGadget)) {
return new RenderJSEmbeddedGadget();
}
RenderJSGadget.call(this);
}
RenderJSEmbeddedGadget.__ready_list = RenderJSGadget.__ready_list.slice();
RenderJSEmbeddedGadget.__service_list =
RenderJSGadget.__service_list.slice();
RenderJSEmbeddedGadget.ready =
RenderJSGadget.ready;
RenderJSEmbeddedGadget.setState =
RenderJSGadget.setState;
RenderJSEmbeddedGadget.onStateChange =
RenderJSGadget.onStateChange;
RenderJSEmbeddedGadget.declareService =
RenderJSGadget.declareService;
RenderJSEmbeddedGadget.onEvent =
RenderJSGadget.onEvent;
RenderJSEmbeddedGadget.prototype = new RenderJSGadget();
RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget;
/////////////////////////////////////////////////////////////////
// privateDeclarePublicGadget
/////////////////////////////////////////////////////////////////
function privateDeclarePublicGadget(url, options, parent_gadget) {
return new RSVP.Queue()
.push(function () {
return renderJS.declareGadgetKlass(url)
// gadget loading should not be interrupted
// if not, gadget's definition will not be complete
//.then will return another promise
//so loading_klass_promise can't be cancel
.then(function (result) {
return result;
});
})
// Get the gadget class and instanciate it
.push(function (Klass) {
if (options.element === undefined) {
options.element = document.createElement("div");
}
var i,
gadget_instance,
template_node_list = Klass.__template_element.body.childNodes,
fragment = document.createDocumentFragment();
gadget_instance = new Klass();
gadget_instance.element = options.element;
gadget_instance.state = {};
for (i = 0; i < template_node_list.length; i += 1) {
fragment.appendChild(
template_node_list[i].cloneNode(true)
);
}
gadget_instance.element.appendChild(fragment);
setAqParent(gadget_instance, parent_gadget);
return gadget_instance;
});
}
/////////////////////////////////////////////////////////////////
// RenderJSIframeGadget
/////////////////////////////////////////////////////////////////
function RenderJSIframeGadget() {
if (!(this instanceof RenderJSIframeGadget)) {
return new RenderJSIframeGadget();
}
RenderJSGadget.call(this);
}
RenderJSIframeGadget.__ready_list = RenderJSGadget.__ready_list.slice();
RenderJSIframeGadget.ready =
RenderJSGadget.ready;
RenderJSIframeGadget.setState =
RenderJSGadget.setState;
RenderJSIframeGadget.onStateChange =
RenderJSGadget.onStateChange;
RenderJSIframeGadget.__service_list = RenderJSGadget.__service_list.slice();
RenderJSIframeGadget.declareService =
RenderJSGadget.declareService;
RenderJSIframeGadget.onEvent =
RenderJSGadget.onEvent;
RenderJSIframeGadget.prototype = new RenderJSGadget();
RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget;
/////////////////////////////////////////////////////////////////
// privateDeclareIframeGadget
/////////////////////////////////////////////////////////////////
function privateDeclareIframeGadget(url, options, parent_gadget) {
var gadget_instance,
iframe,
iframe_loading_deferred = RSVP.defer();
if (options.element === undefined) {
throw new Error("DOM element is required to create Iframe Gadget " +
url);
}
// Check if the element is attached to the DOM
if (!document.contains(options.element)) {
throw new Error("The parent element is not attached to the DOM for " +
url);
}
gadget_instance = new RenderJSIframeGadget();
setAqParent(gadget_instance, parent_gadget);
iframe = document.createElement("iframe");
// gadget_instance.element.setAttribute("seamless", "seamless");
iframe.setAttribute("src", url);
gadget_instance.__path = url;
gadget_instance.element = options.element;
gadget_instance.state = {};
// Attach it to the DOM
options.element.appendChild(iframe);
// XXX Manage unbind when deleting the gadget
// Create the communication channel with the iframe
gadget_instance.__chan = Channel.build({
window: iframe.contentWindow,
origin: "*",
scope: "renderJS"
});
// Create new method from the declareMethod call inside the iframe
gadget_instance.__chan.bind("declareMethod",
function (trans, method_name) {
gadget_instance[method_name] = function () {
var argument_list = arguments,
wait_promise = new RSVP.Promise(function (resolve, reject) {
gadget_instance.__chan.call({
method: "methodCall",
params: [
method_name,
Array.prototype.slice.call(argument_list, 0)],
success: function (s) {
resolve(s);
},
error: function (e) {
reject(e);
}
});
});
return new RSVP.Queue()
.push(function () {
return wait_promise;
});
};
return "OK";
});
// Wait for the iframe to be loaded before continuing
gadget_instance.__chan.bind("ready", function (trans) {
iframe_loading_deferred.resolve(gadget_instance);
return "OK";
});
gadget_instance.__chan.bind("failed", function (trans, params) {
iframe_loading_deferred.reject(params);
return "OK";
});
gadget_instance.__chan.bind("acquire", function (trans, params) {
gadget_instance.__aq_parent.apply(gadget_instance, params)
.then(function (g) {
trans.complete(g);
}).fail(function (e) {
trans.error(e.toString());
});
trans.delayReturn(true);
});
return RSVP.any([
iframe_loading_deferred.promise,
// Timeout to prevent non renderJS embeddable gadget
// XXX Maybe using iframe.onload/onerror would be safer?
new RSVP.Queue()
.push(function () {
return RSVP.timeout(5000);
})
.push(undefined, function () {
throw new Error('Timeout while loading: ' + url);
})
]);
}
/////////////////////////////////////////////////////////////////
// privateDeclareDataUrlGadget
/////////////////////////////////////////////////////////////////
function privateDeclareDataUrlGadget(url, options, parent_gadget) {
return new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (xhr) {
// Insert a "base" element, in order to resolve all relative links
// which could get broken with a data url
var doc = (new DOMParser()).parseFromString(xhr.responseText,
'text/html'),
base = doc.createElement('base'),
blob;
base.href = url;
doc.head.insertBefore(base, doc.head.firstChild);
blob = new Blob([doc.documentElement.outerHTML],
{type: "text/html;charset=UTF-8"});
return readBlobAsDataURL(blob);
})
.push(function (data_url) {
return privateDeclareIframeGadget(data_url, options, parent_gadget);
});
}
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareGadget
/////////////////////////////////////////////////////////////////
RenderJSGadget
.declareMethod('declareGadget', function (url, options) {
var parent_gadget = this;
if (options === undefined) {
options = {};
}
if (options.sandbox === undefined) {
options.sandbox = "public";
}
// transform url to absolute url if it is relative
url = renderJS.getAbsoluteURL(url, this.__path);
return new RSVP.Queue()
.push(function () {
var method;
if (options.sandbox === "public") {
method = privateDeclarePublicGadget;
} else if (options.sandbox === "iframe") {
method = privateDeclareIframeGadget;
} else if (options.sandbox === "dataurl") {
method = privateDeclareDataUrlGadget;
} else {
throw new Error("Unsupported sandbox options '" +
options.sandbox + "'");
}
return method(url, options, parent_gadget);
})
// Set the HTML context
.push(function (gadget_instance) {
var i,
scope,
queue = new RSVP.Queue();
// Trigger calling of all ready callback
function ready_wrapper() {
return gadget_instance;
}
function ready_executable_wrapper(fct) {
return function () {
return fct.call(gadget_instance, gadget_instance);
};
}
for (i = 0; i < gadget_instance.constructor.__ready_list.length;
i += 1) {
// Put a timeout?
queue.push(ready_executable_wrapper(
gadget_instance.constructor.__ready_list[i]
));
// Always return the gadget instance after ready function
queue.push(ready_wrapper);
}
// Store local reference to the gadget instance
scope = options.scope;
if (scope === undefined) {
scope = 'RJS_' + scope_increment;
scope_increment += 1;
while (parent_gadget.__sub_gadget_dict.hasOwnProperty(scope)) {
scope = 'RJS_' + scope_increment;
scope_increment += 1;
}
}
parent_gadget.__sub_gadget_dict[scope] = gadget_instance;
gadget_instance.element.setAttribute("data-gadget-scope",
scope);
// Put some attribute to ease page layout comprehension
gadget_instance.element.setAttribute("data-gadget-url", url);
gadget_instance.element.setAttribute("data-gadget-sandbox",
options.sandbox);
gadget_instance.element._gadget = gadget_instance;
if (document.contains(gadget_instance.element)) {
// Put a timeout
queue.push(startService);
}
// Always return the gadget instance after ready function
queue.push(ready_wrapper);
return queue;
});
})
.declareMethod('getDeclaredGadget', function (gadget_scope) {
if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
}
return this.__sub_gadget_dict[gadget_scope];
})
.declareMethod('dropGadget', function (gadget_scope) {
if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
}
// http://perfectionkills.com/understanding-delete/
delete this.__sub_gadget_dict[gadget_scope];
});
/////////////////////////////////////////////////////////////////
// renderJS selector
/////////////////////////////////////////////////////////////////
renderJS = function (selector) {
var result;
if (selector === window) {
// window is the 'this' value when loading a javascript file
// In this case, use the current loading gadget constructor
result = gadget_loading_klass_list[0];
}
if (result === undefined) {
throw new Error("Unknown selector '" + selector + "'");
}
return result;
};
/////////////////////////////////////////////////////////////////
// renderJS.AcquisitionError
/////////////////////////////////////////////////////////////////
renderJS.AcquisitionError = function (message) {
this.name = "AcquisitionError";
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Acquisition failed";
};
renderJS.AcquisitionError.prototype = new Error();
renderJS.AcquisitionError.prototype.constructor =
renderJS.AcquisitionError;
/////////////////////////////////////////////////////////////////
// renderJS.getAbsoluteURL
/////////////////////////////////////////////////////////////////
renderJS.getAbsoluteURL = function (url, base_url) {
if (base_url && url) {
return new URL(url, base_url).href;
}
return url;
};
/////////////////////////////////////////////////////////////////
// renderJS.declareJS
/////////////////////////////////////////////////////////////////
renderJS.declareJS = function (url, container, pop) {
// https://www.html5rocks.com/en/tutorials/speed/script-loading/
// Prevent infinite recursion if loading render.js
// more than once
var result;
if (javascript_registration_dict.hasOwnProperty(url)) {
result = RSVP.resolve();
} else {
javascript_registration_dict[url] = null;
result = new RSVP.Promise(function (resolve, reject) {
var newScript;
newScript = document.createElement('script');
newScript.async = false;
newScript.type = 'text/javascript';
newScript.onload = function () {
if (pop === true) {
// Drop the current loading klass info used by selector
gadget_loading_klass_list.shift();
}
resolve();
};
newScript.onerror = function (e) {
if (pop === true) {
// Drop the current loading klass info used by selector
gadget_loading_klass_list.shift();
}
reject(e);
};
newScript.src = url;
container.appendChild(newScript);
});
}
return result;
};
/////////////////////////////////////////////////////////////////
// renderJS.declareCSS
/////////////////////////////////////////////////////////////////
renderJS.declareCSS = function (url, container) {
// https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
// No way to cleanly check if a css has been loaded
// So, always resolve the promise...
// http://requirejs.org/docs/faq-advanced.html#css
var result;
if (stylesheet_registration_dict.hasOwnProperty(url)) {
result = RSVP.resolve();
} else {
result = new RSVP.Promise(function (resolve, reject) {
var link;
link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = url;
link.onload = function () {
stylesheet_registration_dict[url] = null;
resolve();
};
link.onerror = function (e) {
reject(e);
};
container.appendChild(link);
});
}
return result;
};
/////////////////////////////////////////////////////////////////
// renderJS.declareGadgetKlass
/////////////////////////////////////////////////////////////////
function parse(xhr, url) {
var tmp_constructor,
key,
parsed_html;
// Class inheritance
tmp_constructor = function () {
RenderJSGadget.call(this);
};
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.declareMethod =
RenderJSGadget.declareMethod;
tmp_constructor.declareJob =
RenderJSGadget.declareJob;
tmp_constructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition;
tmp_constructor.ready =
RenderJSGadget.ready;
tmp_constructor.setState =
RenderJSGadget.setState;
tmp_constructor.onStateChange =
RenderJSGadget.onStateChange;
tmp_constructor.declareService =
RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {};
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
tmp_constructor.__template_element =
(new DOMParser()).parseFromString(xhr.responseText, "text/html");
parsed_html = renderJS.parseGadgetHTMLDocument(
tmp_constructor.__template_element,
url
);
for (key in parsed_html) {
if (parsed_html.hasOwnProperty(key)) {
tmp_constructor.prototype['__' + key] = parsed_html[key];
}
}
return tmp_constructor;
}
renderJS.declareGadgetKlass = function (url) {
if (gadget_model_defer_dict.hasOwnProperty(url)) {
// Return klass object if it already exists
return gadget_model_defer_dict[url].promise;
}
var tmp_constructor,
defer = RSVP.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
return new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (result) {
tmp_constructor = parse(result, url);
var fragment = document.createDocumentFragment(),
promise_list = [],
i,
js_list = tmp_constructor.prototype.__required_js_list,
css_list = tmp_constructor.prototype.__required_css_list;
// Load JS
if (js_list.length) {
gadget_loading_klass_list.push(tmp_constructor);
for (i = 0; i < js_list.length - 1; i += 1) {
promise_list.push(renderJS.declareJS(js_list[i], fragment));
}
promise_list.push(renderJS.declareJS(js_list[i], fragment, true));
}
// Load CSS
for (i = 0; i < css_list.length; i += 1) {
promise_list.push(renderJS.declareCSS(css_list[i], fragment));
}
document.head.appendChild(fragment);
return RSVP.all(promise_list);
})
.push(function () {
defer.resolve(tmp_constructor);
return tmp_constructor;
})
.push(undefined, function (e) {
// Drop the current loading klass info used by selector
// even in case of error
defer.reject(e);
throw e;
});
};
/////////////////////////////////////////////////////////////////
// renderJS.clearGadgetKlassList
/////////////////////////////////////////////////////////////////
// For test purpose only
renderJS.clearGadgetKlassList = function () {
gadget_model_defer_dict = {};
javascript_registration_dict = {};
stylesheet_registration_dict = {};
};
/////////////////////////////////////////////////////////////////
// renderJS.parseGadgetHTMLDocument
/////////////////////////////////////////////////////////////////
renderJS.parseGadgetHTMLDocument = function (document_element, url) {
var settings = {
title: "",
interface_list: [],
required_css_list: [],
required_js_list: []
},
i,
element;
if (!url || !isAbsoluteOrDataURL.test(url)) {
throw new Error("The url should be absolute: " + url);
}
if (document_element.nodeType === 9) {
settings.title = document_element.title;
if (document_element.head !== null) {
for (i = 0; i < document_element.head.children.length; i += 1) {
element = document_element.head.children[i];
if (element.href !== null) {
// XXX Manage relative URL during extraction of URLs
// element.href returns absolute URL in firefox but "" in chrome;
if (element.rel === "stylesheet") {
settings.required_css_list.push(
renderJS.getAbsoluteURL(element.getAttribute("href"), url)
);
} else if (element.nodeName === "SCRIPT" &&
(element.type === "text/javascript" ||
!element.type)) {
settings.required_js_list.push(
renderJS.getAbsoluteURL(element.getAttribute("src"), url)
);
} else if (element.rel ===
"http://www.renderjs.org/rel/interface") {
settings.interface_list.push(
renderJS.getAbsoluteURL(element.getAttribute("href"), url)
);
}
}
}
}
} else {
throw new Error("The first parameter should be an HTMLDocument");
}
return settings;
};
/////////////////////////////////////////////////////////////////
// global
/////////////////////////////////////////////////////////////////
window.rJS = window.renderJS = renderJS;
window.__RenderJSGadget = RenderJSGadget;
window.__RenderJSEmbeddedGadget = RenderJSEmbeddedGadget;
window.__RenderJSIframeGadget = RenderJSIframeGadget;
///////////////////////////////////////////////////
// Bootstrap process. Register the self gadget.
///////////////////////////////////////////////////
function bootstrap() {
var url = removeHash(window.location.href),
TmpConstructor,
root_gadget,
loading_gadget_promise = new RSVP.Queue(),
declare_method_count = 0,
embedded_channel,
notifyReady,
notifyDeclareMethod,
gadget_ready = false,
iframe_top_gadget,
last_acquisition_gadget,
declare_method_list_waiting = [],
gadget_failed = false,
gadget_error,
connection_ready = false;
// Create the gadget class for the current url
if (gadget_model_defer_dict.hasOwnProperty(url)) {
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
root_gadget = new TmpConstructor();
setAqParent(root_gadget, last_acquisition_gadget);
} else {
// Create the root gadget instance and put it in the loading stack
TmpConstructor = RenderJSEmbeddedGadget;
TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice();
TmpConstructor.__service_list = RenderJSGadget.__service_list.slice();
TmpConstructor.prototype.__path = url;
root_gadget = new RenderJSEmbeddedGadget();
setAqParent(root_gadget, last_acquisition_gadget);
// Create the communication channel
embedded_channel = Channel.build({
window: window.parent,
origin: "*",
scope: "renderJS",
onReady: function () {
var k;
iframe_top_gadget = false;
//Default: 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
});
});
};
// 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
notifyReady = function () {
if ((declare_method_count === 0) && (gadget_ready === true)) {
embedded_channel.notify({method: "ready"});
}
};
// Inform parent gadget about declareMethod calls here.
notifyDeclareMethod = function (name) {
declare_method_list_waiting.push(name);
};
notifyDeclareMethod("getInterfaceList");
notifyDeclareMethod("getRequiredCSSList");
notifyDeclareMethod("getRequiredJSList");
notifyDeclareMethod("getPath");
notifyDeclareMethod("getTitle");
// Surcharge declareMethod to inform parent window
TmpConstructor.declareMethod = function (name, callback) {
var result = RenderJSGadget.declareMethod.apply(
this,
[name, callback]
);
notifyDeclareMethod(name);
return result;
};
TmpConstructor.declareService =
RenderJSGadget.declareService;
TmpConstructor.declareJob =
RenderJSGadget.declareJob;
TmpConstructor.onEvent =
RenderJSGadget.onEvent;
TmpConstructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod;
TmpConstructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition;
iframe_top_gadget = true;
}
TmpConstructor.prototype.__acquired_method_dict = {};
gadget_loading_klass_list.push(TmpConstructor);
function init() {
// 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;
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;
}).then(resolve, function (e) {
reject(e);
console.error(e);
throw e;
});
}
document.addEventListener('DOMContentLoaded', init, false);
});
loading_gadget_promise
.push(function () {
return loading_klass_promise;
})
.push(function (root_gadget) {
var i;
function ready_wrapper() {
return root_gadget;
}
function ready_executable_wrapper(fct) {
return function (g) {
return fct.call(g, g);
};
}
TmpConstructor.ready(function (g) {
return startService(g);
});
loading_gadget_promise.push(ready_wrapper);
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);
}
});
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();
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
FileReader, Blob, navigator, Event, URL));
var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state. help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";function m(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function n(a,b,d,e,f){function g(){void 0!==k&&"function"==typeof k.cancel&&k.cancel()}function h(){void 0!==j&&a.removeEventListener(b,j,d),g()}function i(i,l){var m;j=function(a){f&&(a.stopPropagation(),a.preventDefault()),g();try{m=e(a)}catch(b){m=c.reject(b)}k=m,(new c.Queue).push(function(){return m}).push(void 0,function(a){a instanceof c.CancellationError||(h(),l(a))})},a.addEventListener(b,j,d)}var j,k;return void 0===f&&(f=!0),new c.Promise(i,h)}function o(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function p(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function q(c){var d,e,f,g,h,i;if(Q)return console.info("-- Error dropped, as page is unloaded"),void console.info(c);for(R.push(c),R.push(new Error("stopping renderJS")),e=a.getElementsByTagName("body")[0];e.firstChild;)e.removeChild(e.firstChild);for(f=a.createElement("section"),g=a.createElement("h1"),g.textContent="Unhandled Error",f.appendChild(g),g=a.createElement("p"),g.textContent="Please report this error to the support team",f.appendChild(g),g=a.createElement("p"),g.textContent="Location: ",h=a.createElement("a"),h.href=h.textContent=b.location.toString(),g.appendChild(h),f.appendChild(g),g=a.createElement("p"),g.textContent="User-agent: "+j.userAgent,f.appendChild(g),g=a.createElement("p"),g.textContent="Date: "+new Date(Date.now()).toISOString(),f.appendChild(g),e.appendChild(f),d=0;d<R.length;d+=1){if(i=R[d],i instanceof k&&(i={string:i.toString(),message:i.message,type:i.type,target:i.target},void 0!==i.target&&R.splice(d+1,0,i.target)),i instanceof XMLHttpRequest&&(i={message:i.toString(),readyState:i.readyState,status:i.status,statusText:i.statusText,response:i.response,responseUrl:i.responseUrl,response_headers:i.getAllResponseHeaders()}),i.constructor===Array||i.constructor===String||i.constructor===Object)try{i=JSON.stringify(i)}catch(l){}f=a.createElement("section"),g=a.createElement("h2"),g.textContent=i.message||i,f.appendChild(g),void 0!==i.fileName&&(g=a.createElement("p"),g.textContent="File: "+i.fileName+": "+i.lineNumber,f.appendChild(g)),void 0!==i.stack&&(g=a.createElement("pre"),g.textContent="Stack: "+i.stack,f.appendChild(g)),e.appendChild(f)}console.error(c.stack),console.error(c)}function r(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function s(){return this instanceof s?void 0:new s}function t(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new J,a.__job_dict={},a.__job_list=[],a.__job_triggered=!1,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return q(a)})}function u(a){a.__sub_gadget_dict={},t(a)}function v(a){var b,d,e,f,g,h=a.element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function w(a,b,d,e){var f=(new c.Queue).push(function(){return d.apply(a,e)});a.__job_dict.hasOwnProperty(b)&&a.__job_dict[b].cancel(),a.__job_dict[b]=f,a.__monitor.monitor((new c.Queue).push(function(){return f}).push(void 0,function(a){if(!(a instanceof c.CancellationError))throw a}))}function x(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list,d=a.__job_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a));for(b=0;b<d.length;b+=1)w(a,d[b][0],d[b][1],d[b][2]);a.__job_list=[],a.__job_triggered=!0}))}function y(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new I.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof I.AcquisitionError)return g.__aq_parent(b,d);throw a})}function z(a,b){a.__aq_parent=function(c,d){return y.apply(b,[a,c,d])}}function A(){return this instanceof A?void s.call(this):new A}function B(b,d,e){return(new c.Queue).push(function(){return I.declareGadgetKlass(b).then(function(a){return a})}).push(function(b){void 0===d.element&&(d.element=a.createElement("div"));var c,f,g=b.__template_element.body.childNodes,h=a.createDocumentFragment();for(f=new b,f.element=d.element,f.state={},c=0;c<g.length;c+=1)h.appendChild(g[c].cloneNode(!0));return f.element.appendChild(h),z(f,e),f})}function C(){return this instanceof C?void s.call(this):new C}function D(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new C,z(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.element=d.element,g.state={},d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,(new c.Queue).push(function(){return c.timeout(5e3)}).push(void 0,function(){throw new Error("Timeout while loading: "+b)})])}function E(a,b,e){return(new c.Queue).push(function(){return o(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),m(c)}).push(function(a){return D(a,b,e)})}function F(a,b){var c,e,f;c=function(){s.call(this)},c.__ready_list=s.__ready_list.slice(),c.__service_list=s.__service_list.slice(),c.declareMethod=s.declareMethod,c.declareJob=s.declareJob,c.declareAcquiredMethod=s.declareAcquiredMethod,c.allowPublicAcquisition=s.allowPublicAcquisition,c.ready=s.ready,c.setState=s.setState,c.onStateChange=s.onStateChange,c.declareService=s.declareService,c.onEvent=s.onEvent,c.prototype=new s,c.prototype.constructor=c,c.prototype.__path=b,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(a.responseText,"text/html"),f=I.parseGadgetHTMLDocument(c.__template_element,b);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);return c}function G(){var d,h,i,j,k,l,m,n,o=p(b.location.href),r=new c.Queue,u=0,v=!1,w=[],y=!1,B=!1;if(K.hasOwnProperty(o))throw new Error("bootstrap should not be called twice");H=new c.Promise(function(p,r){function C(){var b,e,i=I.parseGadgetHTMLDocument(a,o),j=a.createDocumentFragment();for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.element=a.body,h.state={},b=0;b<h.element.childNodes.length;b+=1)j.appendChild(h.element.childNodes[b].cloneNode(!0));d.__template_element.appendChild(j),c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)L[c[b]]=null;for(b=0;b<d.length;b+=1)M[d[b]]=null;N.shift()}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&t(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&t(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&x(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&x(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(p,function(a){throw r(a),console.error(a),a})}m=new s,m.__acquired_method_dict={reportServiceError:function(a){q(a[0])}},m.__aq_parent=function(a){throw new I.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){s.call(this)},d.declareMethod=s.declareMethod,d.declareJob=s.declareJob,d.declareAcquiredMethod=s.declareAcquiredMethod,d.allowPublicAcquisition=s.allowPublicAcquisition,d.__ready_list=s.__ready_list.slice(),d.ready=s.ready,d.setState=s.setState,d.onStateChange=s.onStateChange,d.__service_list=s.__service_list.slice(),d.declareService=s.declareService,d.onEvent=s.onEvent,d.prototype=new s,d.prototype.constructor=d,d.prototype.__path=o,K[o]={promise:c.resolve(d)},h=new d,z(h,m)):(d=A,d.__ready_list=s.__ready_list.slice(),d.__service_list=s.__service_list.slice(),d.prototype.__path=o,h=new A,z(h,m),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(l=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){u+=1,i.call({method:"declareMethod",params:a,success:function(){u-=1,j()},error:function(){u-=1}})},a=0;a<w.length;a+=1)k(w[a]);return w=[],y?void i.notify({method:"failed",params:n}):(B=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===u&&v===!0&&i.notify({method:"ready"})},k=function(a){w.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=s.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=s.declareService,d.declareJob=s.declareJob,d.onEvent=s.onEvent,d.declareAcquiredMethod=s.declareAcquiredMethod,d.allowPublicAcquisition=s.allowPublicAcquisition,l=!0),d.prototype.__acquired_method_dict={},N.push(d),a.addEventListener("DOMContentLoaded",C,!1)}),r.push(function(){return H}).push(function(a){function b(){return a}function c(a){return function(b){return a.call(b,b)}}var e;for(d.ready(function(a){return x(a)}),r.push(b),e=0;e<d.__ready_list.length;e+=1)r.push(c(d.__ready_list[e])).push(b)}),b.self===b.top?r.fail(function(a){throw q(a),a}):r.then(function(){v=!0,B&&j()}).fail(function(a){throw l?(y=!0,n=a.toString(),q(a)):i.notify({method:"failed",params:a.toString()}),a})}var H,I,J,K={},L={},M={},N=[],O=0,P=new RegExp("^(?:[a-z]+:)?//|data:","i"),Q=!1,R=[];b.addEventListener("error",function(a){R.push(a)}),b.addEventListener("beforeunload",function(){Q=!0}),r.prototype=new Error,r.prototype.constructor=r,J=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof J?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new r;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new J},J.prototype=Object.create(c.Promise.prototype),J.prototype.constructor=J,s.prototype.__title="",s.prototype.__interface_list=[],s.prototype.__path="",s.prototype.__html="",s.prototype.__required_css_list=[],s.prototype.__required_js_list=[],s.__ready_list=[u,v],s.ready=function(a){return this.__ready_list.push(a),this},s.setState=function(a){var b=JSON.stringify(a);return this.ready(function(){this.state=JSON.parse(b)})},s.onStateChange=function(a){return this.prototype.__state_change_callback=a,this},s.__service_list=[],s.declareService=function(a){return this.__service_list.push(a),this},s.onEvent=function(a,b,c,d){return this.__service_list.push(function(){return n(this.element,a,c,b.bind(this),d)}),this},s.declareJob=function(a,b){return this.prototype[a]=function(){var c=this,d=arguments;c.__job_triggered?w(c,a,b,d):c.__job_list.push([a,b,d])},this},s.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},s.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.element)throw new Error("No element defined");return this.element}).declareMethod("changeState",function(a){var b,d,e=!1,f=this.hasOwnProperty("__modification_dict"),g=this;f?(d=this.__modification_dict,e=!0):(d={},this.__modification_dict=d);for(b in a)a.hasOwnProperty(b)&&a[b]!==this.state[b]&&(this.state[b]=a[b],d[b]=a[b],e=!0);return e&&void 0!==this.__state_change_callback?(new c.Queue).push(function(){return g.__state_change_callback(d)}).push(function(a){return delete g.__modification_dict,a}):void 0}),s.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},s.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),s.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},A.__ready_list=s.__ready_list.slice(),A.__service_list=s.__service_list.slice(),A.ready=s.ready,A.setState=s.setState,A.onStateChange=s.onStateChange,A.declareService=s.declareService,A.onEvent=s.onEvent,A.prototype=new s,A.prototype.constructor=A,C.__ready_list=s.__ready_list.slice(),C.ready=s.ready,C.setState=s.setState,C.onStateChange=s.onStateChange,C.__service_list=s.__service_list.slice(),C.declareService=s.declareService,C.onEvent=s.onEvent,C.prototype=new s,C.prototype.constructor=C,s.declareMethod("declareGadget",function(b,d){var e=this;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=I.getAbsoluteURL(b,this.__path),(new c.Queue).push(function(){var a;if("public"===d.sandbox)a=B;else if("iframe"===d.sandbox)a=D;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=E}return a(b,d,e)}).push(function(f){function g(){return f}function h(a){return function(){return a.call(f,f)}}var i,j,k=new c.Queue;for(i=0;i<f.constructor.__ready_list.length;i+=1)k.push(h(f.constructor.__ready_list[i])),k.push(g);if(j=d.scope,void 0===j)for(j="RJS_"+O,O+=1;e.__sub_gadget_dict.hasOwnProperty(j);)j="RJS_"+O,O+=1;return e.__sub_gadget_dict[j]=f,f.element.setAttribute("data-gadget-scope",j),f.element.setAttribute("data-gadget-url",b),f.element.setAttribute("data-gadget-sandbox",d.sandbox),f.element._gadget=f,a.contains(f.element)&&k.push(x),k.push(g),k})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),I=function(a){var c;if(a===b&&(c=N[0]),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},I.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},I.AcquisitionError.prototype=new Error,I.AcquisitionError.prototype.constructor=I.AcquisitionError,I.getAbsoluteURL=function(a,b){return b&&a?new l(a,b).href:a},I.declareJS=function(b,d,e){var f;return L.hasOwnProperty(b)?f=c.resolve():(L[b]=null,f=new c.Promise(function(c,f){var g;g=a.createElement("script"),g.async=!1,g.type="text/javascript",g.onload=function(){e===!0&&N.shift(),c()},g.onerror=function(a){e===!0&&N.shift(),f(a)},g.src=b,d.appendChild(g)})),f},I.declareCSS=function(b,d){var e;return e=M.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,e){var f;f=a.createElement("link"),f.rel="stylesheet",f.type="text/css",f.href=b,f.onload=function(){M[b]=null,c()},f.onerror=function(a){e(a)},d.appendChild(f)})},I.declareGadgetKlass=function(b){if(K.hasOwnProperty(b))return K[b].promise;var d,e=c.defer();return K[b]=e,H=e.promise,(new c.Queue).push(function(){return o(b)}).push(function(e){d=F(e,b);var f,g=a.createDocumentFragment(),h=[],i=d.prototype.__required_js_list,j=d.prototype.__required_css_list;if(i.length){for(N.push(d),f=0;f<i.length-1;f+=1)h.push(I.declareJS(i[f],g));h.push(I.declareJS(i[f],g,!0))}for(f=0;f<j.length;f+=1)h.push(I.declareCSS(j[f],g));return a.head.appendChild(g),c.all(h)}).push(function(){return e.resolve(d),d}).push(void 0,function(a){throw e.reject(a),a})},I.clearGadgetKlassList=function(){K={},L={},M={}},I.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!P.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(I.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(I.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(I.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=I,b.__RenderJSGadget=s,b.__RenderJSEmbeddedGadget=A,b.__RenderJSIframeGadget=C,G()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob,navigator,Event,URL);
\ No newline at end of file
...@@ -673,7 +673,7 @@ if (typeof document.contains !== 'function') { ...@@ -673,7 +673,7 @@ if (typeof document.contains !== 'function') {
* http://www.renderjs.org/documentation * http://www.renderjs.org/documentation
*/ */
(function (document, window, RSVP, DOMParser, Channel, MutationObserver, (function (document, window, RSVP, DOMParser, Channel, MutationObserver,
Node, FileReader, Blob, navigator, Event) { Node, FileReader, Blob, navigator, Event, URL) {
"use strict"; "use strict";
function readBlobAsDataURL(blob) { function readBlobAsDataURL(blob) {
...@@ -789,10 +789,10 @@ if (typeof document.contains !== 'function') { ...@@ -789,10 +789,10 @@ if (typeof document.contains !== 'function') {
return new RSVP.Promise(resolver, canceller); return new RSVP.Promise(resolver, canceller);
} }
var gadget_model_dict = {}, var gadget_model_defer_dict = {},
javascript_registration_dict = {}, javascript_registration_dict = {},
stylesheet_registration_dict = {}, stylesheet_registration_dict = {},
gadget_loading_klass, gadget_loading_klass_list = [],
loading_klass_promise, loading_klass_promise,
renderJS, renderJS,
Monitor, Monitor,
...@@ -1381,56 +1381,37 @@ if (typeof document.contains !== 'function') { ...@@ -1381,56 +1381,37 @@ if (typeof document.contains !== 'function') {
// privateDeclarePublicGadget // privateDeclarePublicGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
function privateDeclarePublicGadget(url, options, parent_gadget) { function privateDeclarePublicGadget(url, options, parent_gadget) {
var gadget_instance;
if (options.element === undefined) {
options.element = document.createElement("div");
}
function loadDependency(method, url) {
return function () {
return method(url);
};
}
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return renderJS.declareGadgetKlass(url); return renderJS.declareGadgetKlass(url)
// gadget loading should not be interrupted
// if not, gadget's definition will not be complete
//.then will return another promise
//so loading_klass_promise can't be cancel
.then(function (result) {
return result;
});
}) })
// Get the gadget class and instanciate it // Get the gadget class and instanciate it
.push(function (Klass) { .push(function (Klass) {
if (options.element === undefined) {
options.element = document.createElement("div");
}
var i, var i,
template_node_list = Klass.__template_element.body.childNodes; gadget_instance,
gadget_loading_klass = Klass; template_node_list = Klass.__template_element.body.childNodes,
fragment = document.createDocumentFragment();
gadget_instance = new Klass(); gadget_instance = new Klass();
gadget_instance.element = options.element; gadget_instance.element = options.element;
gadget_instance.state = {}; gadget_instance.state = {};
for (i = 0; i < template_node_list.length; i += 1) { for (i = 0; i < template_node_list.length; i += 1) {
gadget_instance.element.appendChild( fragment.appendChild(
template_node_list[i].cloneNode(true) template_node_list[i].cloneNode(true)
); );
} }
gadget_instance.element.appendChild(fragment);
setAqParent(gadget_instance, parent_gadget); setAqParent(gadget_instance, parent_gadget);
// Load dependencies if needed
return RSVP.all([
gadget_instance.getRequiredJSList(),
gadget_instance.getRequiredCSSList()
]);
})
// Load all JS/CSS
.push(function (all_list) {
var q = new RSVP.Queue(),
i;
// Load JS
for (i = 0; i < all_list[0].length; i += 1) {
q.push(loadDependency(renderJS.declareJS, all_list[0][i]));
}
// Load CSS
for (i = 0; i < all_list[1].length; i += 1) {
q.push(loadDependency(renderJS.declareCSS, all_list[1][i]));
}
return q;
})
.push(function () {
return gadget_instance; return gadget_instance;
}); });
} }
...@@ -1589,10 +1570,7 @@ if (typeof document.contains !== 'function') { ...@@ -1589,10 +1570,7 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
RenderJSGadget RenderJSGadget
.declareMethod('declareGadget', function (url, options) { .declareMethod('declareGadget', function (url, options) {
var queue, var parent_gadget = this;
parent_gadget = this,
local_loading_klass_promise,
previous_loading_klass_promise = loading_klass_promise;
if (options === undefined) { if (options === undefined) {
options = {}; options = {};
...@@ -1603,16 +1581,8 @@ if (typeof document.contains !== 'function') { ...@@ -1603,16 +1581,8 @@ if (typeof document.contains !== 'function') {
// transform url to absolute url if it is relative // transform url to absolute url if it is relative
url = renderJS.getAbsoluteURL(url, this.__path); url = renderJS.getAbsoluteURL(url, this.__path);
// Change the global variable to update the loading queue
loading_klass_promise = new RSVP.Queue() return new RSVP.Queue()
// Wait for previous gadget loading to finish first
.push(function () {
return previous_loading_klass_promise;
})
.push(undefined, function () {
// Forget previous declareGadget error
return;
})
.push(function () { .push(function () {
var method; var method;
if (options.sandbox === "public") { if (options.sandbox === "public") {
...@@ -1628,41 +1598,17 @@ if (typeof document.contains !== 'function') { ...@@ -1628,41 +1598,17 @@ if (typeof document.contains !== 'function') {
return method(url, options, parent_gadget); return method(url, options, parent_gadget);
}) })
// Set the HTML context // Set the HTML context
.push(function (gadget_instance) {
// Drop the current loading klass info used by selector
gadget_loading_klass = undefined;
return gadget_instance;
})
.push(undefined, function (e) {
// Drop the current loading klass info used by selector
// even in case of error
gadget_loading_klass = undefined;
throw e;
});
//gadget loading should not be interrupted
//if not, gadget's definition will not be complete
//.then will return another promise
//so loading_klass_promise can't be cancel
local_loading_klass_promise = loading_klass_promise
.then(function (gadget_instance) {
return gadget_instance;
});
queue = new RSVP.Queue()
.push(function () {
return local_loading_klass_promise;
})
// Set the HTML context
.push(function (gadget_instance) { .push(function (gadget_instance) {
var i, var i,
scope; scope,
queue = new RSVP.Queue();
// Trigger calling of all ready callback // Trigger calling of all ready callback
function ready_wrapper() { function ready_wrapper() {
return gadget_instance; return gadget_instance;
} }
function ready_executable_wrapper(fct) { function ready_executable_wrapper(fct) {
return function (g) { return function () {
return fct.call(g, g); return fct.call(gadget_instance, gadget_instance);
}; };
} }
for (i = 0; i < gadget_instance.constructor.__ready_list.length; for (i = 0; i < gadget_instance.constructor.__ready_list.length;
...@@ -1702,9 +1648,8 @@ if (typeof document.contains !== 'function') { ...@@ -1702,9 +1648,8 @@ if (typeof document.contains !== 'function') {
// Always return the gadget instance after ready function // Always return the gadget instance after ready function
queue.push(ready_wrapper); queue.push(ready_wrapper);
return gadget_instance; return queue;
}); });
return queue;
}) })
.declareMethod('getDeclaredGadget', function (gadget_scope) { .declareMethod('getDeclaredGadget', function (gadget_scope) {
if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) { if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
...@@ -1728,7 +1673,7 @@ if (typeof document.contains !== 'function') { ...@@ -1728,7 +1673,7 @@ if (typeof document.contains !== 'function') {
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
// In this case, use the current loading gadget constructor // In this case, use the current loading gadget constructor
result = gadget_loading_klass; result = gadget_loading_klass_list[0];
} }
if (result === undefined) { if (result === undefined) {
throw new Error("Unknown selector '" + selector + "'"); throw new Error("Unknown selector '" + selector + "'");
...@@ -1754,18 +1699,8 @@ if (typeof document.contains !== 'function') { ...@@ -1754,18 +1699,8 @@ if (typeof document.contains !== 'function') {
// renderJS.getAbsoluteURL // renderJS.getAbsoluteURL
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.getAbsoluteURL = function (url, base_url) { renderJS.getAbsoluteURL = function (url, base_url) {
var doc, base, link, if (base_url && url) {
html = "<!doctype><html><head></head></html>"; return new URL(url, base_url).href;
if (url && base_url && !isAbsoluteOrDataURL.test(url)) {
doc = (new DOMParser()).parseFromString(html, 'text/html');
base = doc.createElement('base');
link = doc.createElement('link');
doc.head.appendChild(base);
doc.head.appendChild(link);
base.href = base_url;
link.href = url;
return link.href;
} }
return url; return url;
}; };
...@@ -1773,26 +1708,36 @@ if (typeof document.contains !== 'function') { ...@@ -1773,26 +1708,36 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.declareJS // renderJS.declareJS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareJS = function (url) { renderJS.declareJS = function (url, container, pop) {
// 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
var result; var result;
if (javascript_registration_dict.hasOwnProperty(url)) { if (javascript_registration_dict.hasOwnProperty(url)) {
result = RSVP.resolve(); result = RSVP.resolve();
} else { } else {
javascript_registration_dict[url] = null;
result = new RSVP.Promise(function (resolve, reject) { result = new RSVP.Promise(function (resolve, reject) {
var newScript; var newScript;
newScript = document.createElement('script'); newScript = document.createElement('script');
newScript.async = false;
newScript.type = 'text/javascript'; newScript.type = 'text/javascript';
newScript.src = url;
newScript.onload = function () { newScript.onload = function () {
javascript_registration_dict[url] = null; if (pop === true) {
// Drop the current loading klass info used by selector
gadget_loading_klass_list.shift();
}
resolve(); resolve();
}; };
newScript.onerror = function (e) { newScript.onerror = function (e) {
if (pop === true) {
// Drop the current loading klass info used by selector
gadget_loading_klass_list.shift();
}
reject(e); reject(e);
}; };
document.head.appendChild(newScript); newScript.src = url;
container.appendChild(newScript);
}); });
} }
return result; return result;
...@@ -1801,7 +1746,7 @@ if (typeof document.contains !== 'function') { ...@@ -1801,7 +1746,7 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.declareCSS // renderJS.declareCSS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareCSS = function (url) { renderJS.declareCSS = function (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...
...@@ -1823,7 +1768,7 @@ if (typeof document.contains !== 'function') { ...@@ -1823,7 +1768,7 @@ if (typeof document.contains !== 'function') {
link.onerror = function (e) { link.onerror = function (e) {
reject(e); reject(e);
}; };
document.head.appendChild(link); container.appendChild(link);
}); });
} }
return result; return result;
...@@ -1832,77 +1777,107 @@ if (typeof document.contains !== 'function') { ...@@ -1832,77 +1777,107 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// renderJS.declareGadgetKlass // renderJS.declareGadgetKlass
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareGadgetKlass = function (url) {
var result;
function parse(xhr) {
var tmp_constructor,
key,
parsed_html;
if (!gadget_model_dict.hasOwnProperty(url)) {
// Class inheritance
tmp_constructor = function () {
RenderJSGadget.call(this);
};
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.declareMethod =
RenderJSGadget.declareMethod;
tmp_constructor.declareJob =
RenderJSGadget.declareJob;
tmp_constructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition;
tmp_constructor.ready =
RenderJSGadget.ready;
tmp_constructor.setState =
RenderJSGadget.setState;
tmp_constructor.onStateChange =
RenderJSGadget.onStateChange;
tmp_constructor.declareService =
RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {};
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
tmp_constructor.__template_element =
(new DOMParser()).parseFromString(xhr.responseText, "text/html");
parsed_html = renderJS.parseGadgetHTMLDocument(
tmp_constructor.__template_element,
url
);
for (key in parsed_html) {
if (parsed_html.hasOwnProperty(key)) {
tmp_constructor.prototype['__' + key] = parsed_html[key];
}
}
gadget_model_dict[url] = tmp_constructor; function parse(xhr, url) {
var tmp_constructor,
key,
parsed_html;
// Class inheritance
tmp_constructor = function () {
RenderJSGadget.call(this);
};
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.declareMethod =
RenderJSGadget.declareMethod;
tmp_constructor.declareJob =
RenderJSGadget.declareJob;
tmp_constructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition;
tmp_constructor.ready =
RenderJSGadget.ready;
tmp_constructor.setState =
RenderJSGadget.setState;
tmp_constructor.onStateChange =
RenderJSGadget.onStateChange;
tmp_constructor.declareService =
RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {};
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
tmp_constructor.__template_element =
(new DOMParser()).parseFromString(xhr.responseText, "text/html");
parsed_html = renderJS.parseGadgetHTMLDocument(
tmp_constructor.__template_element,
url
);
for (key in parsed_html) {
if (parsed_html.hasOwnProperty(key)) {
tmp_constructor.prototype['__' + key] = parsed_html[key];
} }
return gadget_model_dict[url];
} }
return tmp_constructor;
}
if (gadget_model_dict.hasOwnProperty(url)) { renderJS.declareGadgetKlass = function (url) {
if (gadget_model_defer_dict.hasOwnProperty(url)) {
// Return klass object if it already exists // Return klass object if it already exists
result = RSVP.resolve(gadget_model_dict[url]); return gadget_model_defer_dict[url].promise;
} else {
// Fetch the HTML page and parse it
result = new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (xhr) {
return parse(xhr);
});
} }
return result;
var tmp_constructor,
defer = RSVP.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
return new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (result) {
tmp_constructor = parse(result, url);
var fragment = document.createDocumentFragment(),
promise_list = [],
i,
js_list = tmp_constructor.prototype.__required_js_list,
css_list = tmp_constructor.prototype.__required_css_list;
// Load JS
if (js_list.length) {
gadget_loading_klass_list.push(tmp_constructor);
for (i = 0; i < js_list.length - 1; i += 1) {
promise_list.push(renderJS.declareJS(js_list[i], fragment));
}
promise_list.push(renderJS.declareJS(js_list[i], fragment, true));
}
// Load CSS
for (i = 0; i < css_list.length; i += 1) {
promise_list.push(renderJS.declareCSS(css_list[i], fragment));
}
document.head.appendChild(fragment);
return RSVP.all(promise_list);
})
.push(function () {
defer.resolve(tmp_constructor);
return tmp_constructor;
})
.push(undefined, function (e) {
// Drop the current loading klass info used by selector
// even in case of error
defer.reject(e);
throw e;
});
}; };
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1910,7 +1885,7 @@ if (typeof document.contains !== 'function') { ...@@ -1910,7 +1885,7 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// For test purpose only // For test purpose only
renderJS.clearGadgetKlassList = function () { renderJS.clearGadgetKlassList = function () {
gadget_model_dict = {}; gadget_model_defer_dict = {};
javascript_registration_dict = {}; javascript_registration_dict = {};
stylesheet_registration_dict = {}; stylesheet_registration_dict = {};
}; };
...@@ -1980,7 +1955,7 @@ if (typeof document.contains !== 'function') { ...@@ -1980,7 +1955,7 @@ if (typeof document.contains !== 'function') {
function bootstrap() { function bootstrap() {
var url = removeHash(window.location.href), var url = removeHash(window.location.href),
tmp_constructor, TmpConstructor,
root_gadget, root_gadget,
loading_gadget_promise = new RSVP.Queue(), loading_gadget_promise = new RSVP.Queue(),
declare_method_count = 0, declare_method_count = 0,
...@@ -1996,7 +1971,7 @@ if (typeof document.contains !== 'function') { ...@@ -1996,7 +1971,7 @@ if (typeof document.contains !== 'function') {
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_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) { loading_klass_promise = new RSVP.Promise(function (resolve, reject) {
...@@ -2025,40 +2000,42 @@ if (typeof document.contains !== 'function') { ...@@ -2025,40 +2000,42 @@ if (typeof document.contains !== 'function') {
// tmp_constructor = RenderJSEmbeddedGadget // tmp_constructor = RenderJSEmbeddedGadget
if (window.self === window.top) { if (window.self === window.top) {
// XXX Copy/Paste from declareGadgetKlass // XXX Copy/Paste from declareGadgetKlass
tmp_constructor = function () { TmpConstructor = function () {
RenderJSGadget.call(this); RenderJSGadget.call(this);
}; };
tmp_constructor.declareMethod = RenderJSGadget.declareMethod; TmpConstructor.declareMethod = RenderJSGadget.declareMethod;
tmp_constructor.declareJob = RenderJSGadget.declareJob; TmpConstructor.declareJob = RenderJSGadget.declareJob;
tmp_constructor.declareAcquiredMethod = TmpConstructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod; RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition = TmpConstructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition; RenderJSGadget.allowPublicAcquisition;
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice(); TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice();
tmp_constructor.ready = RenderJSGadget.ready; TmpConstructor.ready = RenderJSGadget.ready;
tmp_constructor.setState = RenderJSGadget.setState; TmpConstructor.setState = RenderJSGadget.setState;
tmp_constructor.onStateChange = RenderJSGadget.onStateChange; TmpConstructor.onStateChange = RenderJSGadget.onStateChange;
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice(); TmpConstructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.declareService = TmpConstructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.onEvent = TmpConstructor.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget(); TmpConstructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor; TmpConstructor.prototype.constructor = TmpConstructor;
tmp_constructor.prototype.__path = url; TmpConstructor.prototype.__path = url;
gadget_model_dict[url] = tmp_constructor; 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 gadget_model_dict[url](); root_gadget = new TmpConstructor();
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
// Create the root gadget instance and put it in the loading stack // Create the root gadget instance and put it in the loading stack
tmp_constructor = RenderJSEmbeddedGadget; TmpConstructor = RenderJSEmbeddedGadget;
tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice(); TmpConstructor.__ready_list = RenderJSGadget.__ready_list.slice();
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice(); TmpConstructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.prototype.__path = url; TmpConstructor.prototype.__path = url;
root_gadget = new RenderJSEmbeddedGadget(); root_gadget = new RenderJSEmbeddedGadget();
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
...@@ -2072,7 +2049,7 @@ if (typeof document.contains !== 'function') { ...@@ -2072,7 +2049,7 @@ if (typeof document.contains !== 'function') {
iframe_top_gadget = false; iframe_top_gadget = false;
//Default: Define __aq_parent to inform parent window //Default: Define __aq_parent to inform parent window
root_gadget.__aq_parent = root_gadget.__aq_parent =
tmp_constructor.prototype.__aq_parent = function (method_name, TmpConstructor.prototype.__aq_parent = function (method_name,
argument_list, time_out) { argument_list, time_out) {
return new RSVP.Promise(function (resolve, reject) { return new RSVP.Promise(function (resolve, reject) {
embedded_channel.call({ embedded_channel.call({
...@@ -2154,7 +2131,7 @@ if (typeof document.contains !== 'function') { ...@@ -2154,7 +2131,7 @@ if (typeof document.contains !== 'function') {
notifyDeclareMethod("getTitle"); notifyDeclareMethod("getTitle");
// Surcharge declareMethod to inform parent window // Surcharge declareMethod to inform parent window
tmp_constructor.declareMethod = function (name, callback) { TmpConstructor.declareMethod = function (name, callback) {
var result = RenderJSGadget.declareMethod.apply( var result = RenderJSGadget.declareMethod.apply(
this, this,
[name, callback] [name, callback]
...@@ -2163,41 +2140,43 @@ if (typeof document.contains !== 'function') { ...@@ -2163,41 +2140,43 @@ if (typeof document.contains !== 'function') {
return result; return result;
}; };
tmp_constructor.declareService = TmpConstructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.declareJob = TmpConstructor.declareJob =
RenderJSGadget.declareJob; RenderJSGadget.declareJob;
tmp_constructor.onEvent = TmpConstructor.onEvent =
RenderJSGadget.onEvent; RenderJSGadget.onEvent;
tmp_constructor.declareAcquiredMethod = TmpConstructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod; RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition = TmpConstructor.allowPublicAcquisition =
RenderJSGadget.allowPublicAcquisition; RenderJSGadget.allowPublicAcquisition;
iframe_top_gadget = true; iframe_top_gadget = true;
} }
tmp_constructor.prototype.__acquired_method_dict = {}; TmpConstructor.prototype.__acquired_method_dict = {};
gadget_loading_klass = tmp_constructor; gadget_loading_klass_list.push(TmpConstructor);
function init() { function init() {
// XXX HTML properties can only be set when the DOM is fully loaded // XXX HTML properties can only be set when the DOM is fully loaded
var settings = renderJS.parseGadgetHTMLDocument(document, url), var settings = renderJS.parseGadgetHTMLDocument(document, url),
j, j,
key; key,
fragment = document.createDocumentFragment();
for (key in settings) { for (key in settings) {
if (settings.hasOwnProperty(key)) { if (settings.hasOwnProperty(key)) {
tmp_constructor.prototype['__' + key] = settings[key]; TmpConstructor.prototype['__' + key] = settings[key];
} }
} }
tmp_constructor.__template_element = document.createElement("div"); TmpConstructor.__template_element = document.createElement("div");
root_gadget.element = document.body; root_gadget.element = document.body;
root_gadget.state = {}; root_gadget.state = {};
for (j = 0; j < root_gadget.element.childNodes.length; j += 1) { for (j = 0; j < root_gadget.element.childNodes.length; j += 1) {
tmp_constructor.__template_element.appendChild( fragment.appendChild(
root_gadget.element.childNodes[j].cloneNode(true) root_gadget.element.childNodes[j].cloneNode(true)
); );
} }
TmpConstructor.__template_element.appendChild(fragment);
RSVP.all([root_gadget.getRequiredJSList(), RSVP.all([root_gadget.getRequiredJSList(),
root_gadget.getRequiredCSSList()]) root_gadget.getRequiredCSSList()])
.then(function (all_list) { .then(function (all_list) {
...@@ -2210,7 +2189,7 @@ if (typeof document.contains !== 'function') { ...@@ -2210,7 +2189,7 @@ if (typeof document.contains !== 'function') {
for (i = 0; i < css_list.length; i += 1) { for (i = 0; i < css_list.length; i += 1) {
stylesheet_registration_dict[css_list[i]] = null; stylesheet_registration_dict[css_list[i]] = null;
} }
gadget_loading_klass = undefined; gadget_loading_klass_list.shift();
}).then(function () { }).then(function () {
// select the target node // select the target node
...@@ -2304,15 +2283,15 @@ if (typeof document.contains !== 'function') { ...@@ -2304,15 +2283,15 @@ if (typeof document.contains !== 'function') {
return fct.call(g, g); return fct.call(g, g);
}; };
} }
tmp_constructor.ready(function (g) { TmpConstructor.ready(function (g) {
return startService(g); return startService(g);
}); });
loading_gadget_promise.push(ready_wrapper); loading_gadget_promise.push(ready_wrapper);
for (i = 0; i < tmp_constructor.__ready_list.length; i += 1) { for (i = 0; i < TmpConstructor.__ready_list.length; i += 1) {
// Put a timeout? // Put a timeout?
loading_gadget_promise loading_gadget_promise
.push(ready_executable_wrapper(tmp_constructor.__ready_list[i])) .push(ready_executable_wrapper(TmpConstructor.__ready_list[i]))
// Always return the gadget instance after ready function // Always return the gadget instance after ready function
.push(ready_wrapper); .push(ready_wrapper);
} }
...@@ -2349,4 +2328,4 @@ if (typeof document.contains !== 'function') { ...@@ -2349,4 +2328,4 @@ if (typeof document.contains !== 'function') {
bootstrap(); bootstrap();
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node, }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
FileReader, Blob, navigator, Event)); FileReader, Blob, navigator, Event, URL));
var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state. help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i,j,k){"use strict";function l(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function m(a,b,d,e,f){function g(){void 0!==k&&"function"==typeof k.cancel&&k.cancel()}function h(){void 0!==j&&a.removeEventListener(b,j,d),g()}function i(i,l){var m;j=function(a){f&&(a.stopPropagation(),a.preventDefault()),g();try{m=e(a)}catch(b){m=c.reject(b)}k=m,(new c.Queue).push(function(){return m}).push(void 0,function(a){a instanceof c.CancellationError||(h(),l(a))})},a.addEventListener(b,j,d)}var j,k;return void 0===f&&(f=!0),new c.Promise(i,h)}function n(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function o(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function p(c){var d,e,f,g,h,i;if(O)return console.info("-- Error dropped, as page is unloaded"),void console.info(c);for(P.push(c),P.push(new Error("stopping renderJS")),e=a.getElementsByTagName("body")[0];e.firstChild;)e.removeChild(e.firstChild);for(f=a.createElement("section"),g=a.createElement("h1"),g.textContent="Unhandled Error",f.appendChild(g),g=a.createElement("p"),g.textContent="Please report this error to the support team",f.appendChild(g),g=a.createElement("p"),g.textContent="Location: ",h=a.createElement("a"),h.href=h.textContent=b.location.toString(),g.appendChild(h),f.appendChild(g),g=a.createElement("p"),g.textContent="User-agent: "+j.userAgent,f.appendChild(g),g=a.createElement("p"),g.textContent="Date: "+new Date(Date.now()).toISOString(),f.appendChild(g),e.appendChild(f),d=0;d<P.length;d+=1){if(i=P[d],i instanceof k&&(i={string:i.toString(),message:i.message,type:i.type,target:i.target},void 0!==i.target&&P.splice(d+1,0,i.target)),i instanceof XMLHttpRequest&&(i={message:i.toString(),readyState:i.readyState,status:i.status,statusText:i.statusText,response:i.response,responseUrl:i.responseUrl,response_headers:i.getAllResponseHeaders()}),i.constructor===Array||i.constructor===String||i.constructor===Object)try{i=JSON.stringify(i)}catch(l){}f=a.createElement("section"),g=a.createElement("h2"),g.textContent=i.message||i,f.appendChild(g),void 0!==i.fileName&&(g=a.createElement("p"),g.textContent="File: "+i.fileName+": "+i.lineNumber,f.appendChild(g)),void 0!==i.stack&&(g=a.createElement("pre"),g.textContent="Stack: "+i.stack,f.appendChild(g)),e.appendChild(f)}console.error(c.stack),console.error(c)}function q(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function r(){return this instanceof r?void 0:new r}function s(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new I,a.__job_dict={},a.__job_list=[],a.__job_triggered=!1,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return p(a)})}function t(a){a.__sub_gadget_dict={},s(a)}function u(a){var b,d,e,f,g,h=a.element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function v(a,b,d,e){var f=(new c.Queue).push(function(){return d.apply(a,e)});a.__job_dict.hasOwnProperty(b)&&a.__job_dict[b].cancel(),a.__job_dict[b]=f,a.__monitor.monitor((new c.Queue).push(function(){return f}).push(void 0,function(a){if(!(a instanceof c.CancellationError))throw a}))}function w(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list,d=a.__job_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a));for(b=0;b<d.length;b+=1)v(a,d[b][0],d[b][1],d[b][2]);a.__job_list=[],a.__job_triggered=!0}))}function x(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new H.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof H.AcquisitionError)return g.__aq_parent(b,d);throw a})}function y(a,b){a.__aq_parent=function(c,d){return x.apply(b,[a,c,d])}}function z(){return this instanceof z?void r.call(this):new z}function A(b,d,e){function f(a,b){return function(){return a(b)}}var g;return void 0===d.element&&(d.element=a.createElement("div")),(new c.Queue).push(function(){return H.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(F=a,g=new a,g.element=d.element,g.state={},b=0;b<f.length;b+=1)g.element.appendChild(f[b].cloneNode(!0));return y(g,e),c.all([g.getRequiredJSList(),g.getRequiredCSSList()])}).push(function(a){var b,d=new c.Queue;for(b=0;b<a[0].length;b+=1)d.push(f(H.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(H.declareCSS,a[1][b]));return d}).push(function(){return g})}function B(){return this instanceof B?void r.call(this):new B}function C(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new B,y(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.element=d.element,g.state={},d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,(new c.Queue).push(function(){return c.timeout(5e3)}).push(void 0,function(){throw new Error("Timeout while loading: "+b)})])}function D(a,b,e){return(new c.Queue).push(function(){return n(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),l(c)}).push(function(a){return C(a,b,e)})}function E(){var d,h,i,j,k,l,m,n,q=o(b.location.href),t=new c.Queue,u=0,v=!1,x=[],A=!1,B=!1;if(J.hasOwnProperty(q))throw new Error("bootstrap should not be called twice");G=new c.Promise(function(o,t){function C(){var b,e,i=H.parseGadgetHTMLDocument(a,q);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.element=a.body,h.state={},b=0;b<h.element.childNodes.length;b+=1)d.__template_element.appendChild(h.element.childNodes[b].cloneNode(!0));c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)K[c[b]]=null;for(b=0;b<d.length;b+=1)L[d[b]]=null;F=void 0}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&s(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&s(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&w(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&w(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(o,function(a){throw t(a),console.error(a),a})}m=new r,m.__acquired_method_dict={reportServiceError:function(a){p(a[0])}},m.__aq_parent=function(a){throw new H.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){r.call(this)},d.declareMethod=r.declareMethod,d.declareJob=r.declareJob,d.declareAcquiredMethod=r.declareAcquiredMethod,d.allowPublicAcquisition=r.allowPublicAcquisition,d.__ready_list=r.__ready_list.slice(),d.ready=r.ready,d.setState=r.setState,d.onStateChange=r.onStateChange,d.__service_list=r.__service_list.slice(),d.declareService=r.declareService,d.onEvent=r.onEvent,d.prototype=new r,d.prototype.constructor=d,d.prototype.__path=q,J[q]=d,h=new J[q],y(h,m)):(d=z,d.__ready_list=r.__ready_list.slice(),d.__service_list=r.__service_list.slice(),d.prototype.__path=q,h=new z,y(h,m),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(l=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){u+=1,i.call({method:"declareMethod",params:a,success:function(){u-=1,j()},error:function(){u-=1}})},a=0;a<x.length;a+=1)k(x[a]);return x=[],A?void i.notify({method:"failed",params:n}):(B=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===u&&v===!0&&i.notify({method:"ready"})},k=function(a){x.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=r.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=r.declareService,d.declareJob=r.declareJob,d.onEvent=r.onEvent,d.declareAcquiredMethod=r.declareAcquiredMethod,d.allowPublicAcquisition=r.allowPublicAcquisition,l=!0),d.prototype.__acquired_method_dict={},F=d,a.addEventListener("DOMContentLoaded",C,!1)}),t.push(function(){return G}).push(function(a){function b(){return a}function c(a){return function(b){return a.call(b,b)}}var e;for(d.ready(function(a){return w(a)}),t.push(b),e=0;e<d.__ready_list.length;e+=1)t.push(c(d.__ready_list[e])).push(b)}),b.self===b.top?t.fail(function(a){throw p(a),a}):t.then(function(){v=!0,B&&j()}).fail(function(a){throw l?(A=!0,n=a.toString(),p(a)):i.notify({method:"failed",params:a.toString()}),a})}var F,G,H,I,J={},K={},L={},M=0,N=new RegExp("^(?:[a-z]+:)?//|data:","i"),O=!1,P=[];b.addEventListener("error",function(a){P.push(a)}),b.addEventListener("beforeunload",function(){O=!0}),q.prototype=new Error,q.prototype.constructor=q,I=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof I?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new q;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new I},I.prototype=Object.create(c.Promise.prototype),I.prototype.constructor=I,r.prototype.__title="",r.prototype.__interface_list=[],r.prototype.__path="",r.prototype.__html="",r.prototype.__required_css_list=[],r.prototype.__required_js_list=[],r.__ready_list=[t,u],r.ready=function(a){return this.__ready_list.push(a),this},r.setState=function(a){var b=JSON.stringify(a);return this.ready(function(){this.state=JSON.parse(b)})},r.onStateChange=function(a){return this.prototype.__state_change_callback=a,this},r.__service_list=[],r.declareService=function(a){return this.__service_list.push(a),this},r.onEvent=function(a,b,c,d){return this.__service_list.push(function(){return m(this.element,a,c,b.bind(this),d)}),this},r.declareJob=function(a,b){return this.prototype[a]=function(){var c=this,d=arguments;c.__job_triggered?v(c,a,b,d):c.__job_list.push([a,b,d])},this},r.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},r.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.element)throw new Error("No element defined");return this.element}).declareMethod("changeState",function(a){var b,d,e=!1,f=this.hasOwnProperty("__modification_dict"),g=this;f?(d=this.__modification_dict,e=!0):(d={},this.__modification_dict=d);for(b in a)a.hasOwnProperty(b)&&a[b]!==this.state[b]&&(this.state[b]=a[b],d[b]=a[b],e=!0);return e&&void 0!==this.__state_change_callback?(new c.Queue).push(function(){return g.__state_change_callback(d)}).push(function(a){return delete g.__modification_dict,a}):void 0}),r.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},r.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),r.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},z.__ready_list=r.__ready_list.slice(),z.__service_list=r.__service_list.slice(),z.ready=r.ready,z.setState=r.setState,z.onStateChange=r.onStateChange,z.declareService=r.declareService,z.onEvent=r.onEvent,z.prototype=new r,z.prototype.constructor=z,B.__ready_list=r.__ready_list.slice(),B.ready=r.ready,B.setState=r.setState,B.onStateChange=r.onStateChange,B.__service_list=r.__service_list.slice(),B.declareService=r.declareService,B.onEvent=r.onEvent,B.prototype=new r,B.prototype.constructor=B,r.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=G;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=H.getAbsoluteURL(b,this.__path),G=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=A;else if("iframe"===d.sandbox)a=C;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=D}return a(b,d,g)}).push(function(a){return F=void 0,a}).push(void 0,function(a){throw F=void 0,a}),f=G.then(function(a){return a}),e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}function h(a){return function(b){return a.call(b,b)}}var i,j;for(i=0;i<c.constructor.__ready_list.length;i+=1)e.push(h(c.constructor.__ready_list[i])),e.push(f);if(j=d.scope,void 0===j)for(j="RJS_"+M,M+=1;g.__sub_gadget_dict.hasOwnProperty(j);)j="RJS_"+M,M+=1;return g.__sub_gadget_dict[j]=c,c.element.setAttribute("data-gadget-scope",j),c.element.setAttribute("data-gadget-url",b),c.element.setAttribute("data-gadget-sandbox",d.sandbox),c.element._gadget=c,a.contains(c.element)&&e.push(w),e.push(f),c})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),H=function(a){var c;if(a===b&&(c=F),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},H.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},H.AcquisitionError.prototype=new Error,H.AcquisitionError.prototype.constructor=H.AcquisitionError,H.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!N.test(a)?(c=(new d).parseFromString(g,"text/html"),e=c.createElement("base"),f=c.createElement("link"),c.head.appendChild(e),c.head.appendChild(f),e.href=b,f.href=a,f.href):a},H.declareJS=function(b){var d;return d=K.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("script"),e.type="text/javascript",e.src=b,e.onload=function(){K[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},H.declareCSS=function(b){var d;return d=L.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("link"),e.rel="stylesheet",e.type="text/css",e.href=b,e.onload=function(){L[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},H.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!J.hasOwnProperty(a)){c=function(){r.call(this)},c.__ready_list=r.__ready_list.slice(),c.__service_list=r.__service_list.slice(),c.declareMethod=r.declareMethod,c.declareJob=r.declareJob,c.declareAcquiredMethod=r.declareAcquiredMethod,c.allowPublicAcquisition=r.allowPublicAcquisition,c.ready=r.ready,c.setState=r.setState,c.onStateChange=r.onStateChange,c.declareService=r.declareService,c.onEvent=r.onEvent,c.prototype=new r,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=H.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);J[a]=c}return J[a]}var e;return e=J.hasOwnProperty(a)?c.resolve(J[a]):(new c.Queue).push(function(){return n(a)}).push(function(a){return b(a)})},H.clearGadgetKlassList=function(){J={},K={},L={}},H.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!N.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(H.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(H.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(H.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=H,b.__RenderJSGadget=r,b.__RenderJSEmbeddedGadget=z,b.__RenderJSIframeGadget=B,E()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob,navigator,Event); var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state. help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";function m(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function n(a,b,d,e,f){function g(){void 0!==k&&"function"==typeof k.cancel&&k.cancel()}function h(){void 0!==j&&a.removeEventListener(b,j,d),g()}function i(i,l){var m;j=function(a){f&&(a.stopPropagation(),a.preventDefault()),g();try{m=e(a)}catch(b){m=c.reject(b)}k=m,(new c.Queue).push(function(){return m}).push(void 0,function(a){a instanceof c.CancellationError||(h(),l(a))})},a.addEventListener(b,j,d)}var j,k;return void 0===f&&(f=!0),new c.Promise(i,h)}function o(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function p(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function q(c){var d,e,f,g,h,i;if(Q)return console.info("-- Error dropped, as page is unloaded"),void console.info(c);for(R.push(c),R.push(new Error("stopping renderJS")),e=a.getElementsByTagName("body")[0];e.firstChild;)e.removeChild(e.firstChild);for(f=a.createElement("section"),g=a.createElement("h1"),g.textContent="Unhandled Error",f.appendChild(g),g=a.createElement("p"),g.textContent="Please report this error to the support team",f.appendChild(g),g=a.createElement("p"),g.textContent="Location: ",h=a.createElement("a"),h.href=h.textContent=b.location.toString(),g.appendChild(h),f.appendChild(g),g=a.createElement("p"),g.textContent="User-agent: "+j.userAgent,f.appendChild(g),g=a.createElement("p"),g.textContent="Date: "+new Date(Date.now()).toISOString(),f.appendChild(g),e.appendChild(f),d=0;d<R.length;d+=1){if(i=R[d],i instanceof k&&(i={string:i.toString(),message:i.message,type:i.type,target:i.target},void 0!==i.target&&R.splice(d+1,0,i.target)),i instanceof XMLHttpRequest&&(i={message:i.toString(),readyState:i.readyState,status:i.status,statusText:i.statusText,response:i.response,responseUrl:i.responseUrl,response_headers:i.getAllResponseHeaders()}),i.constructor===Array||i.constructor===String||i.constructor===Object)try{i=JSON.stringify(i)}catch(l){}f=a.createElement("section"),g=a.createElement("h2"),g.textContent=i.message||i,f.appendChild(g),void 0!==i.fileName&&(g=a.createElement("p"),g.textContent="File: "+i.fileName+": "+i.lineNumber,f.appendChild(g)),void 0!==i.stack&&(g=a.createElement("pre"),g.textContent="Stack: "+i.stack,f.appendChild(g)),e.appendChild(f)}console.error(c.stack),console.error(c)}function r(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function s(){return this instanceof s?void 0:new s}function t(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new J,a.__job_dict={},a.__job_list=[],a.__job_triggered=!1,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return q(a)})}function u(a){a.__sub_gadget_dict={},t(a)}function v(a){var b,d,e,f,g,h=a.element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function w(a,b,d,e){var f=(new c.Queue).push(function(){return d.apply(a,e)});a.__job_dict.hasOwnProperty(b)&&a.__job_dict[b].cancel(),a.__job_dict[b]=f,a.__monitor.monitor((new c.Queue).push(function(){return f}).push(void 0,function(a){if(!(a instanceof c.CancellationError))throw a}))}function x(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list,d=a.__job_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a));for(b=0;b<d.length;b+=1)w(a,d[b][0],d[b][1],d[b][2]);a.__job_list=[],a.__job_triggered=!0}))}function y(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new I.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof I.AcquisitionError)return g.__aq_parent(b,d);throw a})}function z(a,b){a.__aq_parent=function(c,d){return y.apply(b,[a,c,d])}}function A(){return this instanceof A?void s.call(this):new A}function B(b,d,e){return(new c.Queue).push(function(){return I.declareGadgetKlass(b).then(function(a){return a})}).push(function(b){void 0===d.element&&(d.element=a.createElement("div"));var c,f,g=b.__template_element.body.childNodes,h=a.createDocumentFragment();for(f=new b,f.element=d.element,f.state={},c=0;c<g.length;c+=1)h.appendChild(g[c].cloneNode(!0));return f.element.appendChild(h),z(f,e),f})}function C(){return this instanceof C?void s.call(this):new C}function D(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new C,z(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.element=d.element,g.state={},d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,(new c.Queue).push(function(){return c.timeout(5e3)}).push(void 0,function(){throw new Error("Timeout while loading: "+b)})])}function E(a,b,e){return(new c.Queue).push(function(){return o(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),m(c)}).push(function(a){return D(a,b,e)})}function F(a,b){var c,e,f;c=function(){s.call(this)},c.__ready_list=s.__ready_list.slice(),c.__service_list=s.__service_list.slice(),c.declareMethod=s.declareMethod,c.declareJob=s.declareJob,c.declareAcquiredMethod=s.declareAcquiredMethod,c.allowPublicAcquisition=s.allowPublicAcquisition,c.ready=s.ready,c.setState=s.setState,c.onStateChange=s.onStateChange,c.declareService=s.declareService,c.onEvent=s.onEvent,c.prototype=new s,c.prototype.constructor=c,c.prototype.__path=b,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(a.responseText,"text/html"),f=I.parseGadgetHTMLDocument(c.__template_element,b);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);return c}function G(){var d,h,i,j,k,l,m,n,o=p(b.location.href),r=new c.Queue,u=0,v=!1,w=[],y=!1,B=!1;if(K.hasOwnProperty(o))throw new Error("bootstrap should not be called twice");H=new c.Promise(function(p,r){function C(){var b,e,i=I.parseGadgetHTMLDocument(a,o),j=a.createDocumentFragment();for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.element=a.body,h.state={},b=0;b<h.element.childNodes.length;b+=1)j.appendChild(h.element.childNodes[b].cloneNode(!0));d.__template_element.appendChild(j),c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)L[c[b]]=null;for(b=0;b<d.length;b+=1)M[d[b]]=null;N.shift()}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&t(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&t(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&x(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&x(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(p,function(a){throw r(a),console.error(a),a})}m=new s,m.__acquired_method_dict={reportServiceError:function(a){q(a[0])}},m.__aq_parent=function(a){throw new I.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){s.call(this)},d.declareMethod=s.declareMethod,d.declareJob=s.declareJob,d.declareAcquiredMethod=s.declareAcquiredMethod,d.allowPublicAcquisition=s.allowPublicAcquisition,d.__ready_list=s.__ready_list.slice(),d.ready=s.ready,d.setState=s.setState,d.onStateChange=s.onStateChange,d.__service_list=s.__service_list.slice(),d.declareService=s.declareService,d.onEvent=s.onEvent,d.prototype=new s,d.prototype.constructor=d,d.prototype.__path=o,K[o]={promise:c.resolve(d)},h=new d,z(h,m)):(d=A,d.__ready_list=s.__ready_list.slice(),d.__service_list=s.__service_list.slice(),d.prototype.__path=o,h=new A,z(h,m),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(l=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){u+=1,i.call({method:"declareMethod",params:a,success:function(){u-=1,j()},error:function(){u-=1}})},a=0;a<w.length;a+=1)k(w[a]);return w=[],y?void i.notify({method:"failed",params:n}):(B=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===u&&v===!0&&i.notify({method:"ready"})},k=function(a){w.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=s.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=s.declareService,d.declareJob=s.declareJob,d.onEvent=s.onEvent,d.declareAcquiredMethod=s.declareAcquiredMethod,d.allowPublicAcquisition=s.allowPublicAcquisition,l=!0),d.prototype.__acquired_method_dict={},N.push(d),a.addEventListener("DOMContentLoaded",C,!1)}),r.push(function(){return H}).push(function(a){function b(){return a}function c(a){return function(b){return a.call(b,b)}}var e;for(d.ready(function(a){return x(a)}),r.push(b),e=0;e<d.__ready_list.length;e+=1)r.push(c(d.__ready_list[e])).push(b)}),b.self===b.top?r.fail(function(a){throw q(a),a}):r.then(function(){v=!0,B&&j()}).fail(function(a){throw l?(y=!0,n=a.toString(),q(a)):i.notify({method:"failed",params:a.toString()}),a})}var H,I,J,K={},L={},M={},N=[],O=0,P=new RegExp("^(?:[a-z]+:)?//|data:","i"),Q=!1,R=[];b.addEventListener("error",function(a){R.push(a)}),b.addEventListener("beforeunload",function(){Q=!0}),r.prototype=new Error,r.prototype.constructor=r,J=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof J?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new r;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new J},J.prototype=Object.create(c.Promise.prototype),J.prototype.constructor=J,s.prototype.__title="",s.prototype.__interface_list=[],s.prototype.__path="",s.prototype.__html="",s.prototype.__required_css_list=[],s.prototype.__required_js_list=[],s.__ready_list=[u,v],s.ready=function(a){return this.__ready_list.push(a),this},s.setState=function(a){var b=JSON.stringify(a);return this.ready(function(){this.state=JSON.parse(b)})},s.onStateChange=function(a){return this.prototype.__state_change_callback=a,this},s.__service_list=[],s.declareService=function(a){return this.__service_list.push(a),this},s.onEvent=function(a,b,c,d){return this.__service_list.push(function(){return n(this.element,a,c,b.bind(this),d)}),this},s.declareJob=function(a,b){return this.prototype[a]=function(){var c=this,d=arguments;c.__job_triggered?w(c,a,b,d):c.__job_list.push([a,b,d])},this},s.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},s.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.element)throw new Error("No element defined");return this.element}).declareMethod("changeState",function(a){var b,d,e=!1,f=this.hasOwnProperty("__modification_dict"),g=this;f?(d=this.__modification_dict,e=!0):(d={},this.__modification_dict=d);for(b in a)a.hasOwnProperty(b)&&a[b]!==this.state[b]&&(this.state[b]=a[b],d[b]=a[b],e=!0);return e&&void 0!==this.__state_change_callback?(new c.Queue).push(function(){return g.__state_change_callback(d)}).push(function(a){return delete g.__modification_dict,a}):void 0}),s.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},s.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),s.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},A.__ready_list=s.__ready_list.slice(),A.__service_list=s.__service_list.slice(),A.ready=s.ready,A.setState=s.setState,A.onStateChange=s.onStateChange,A.declareService=s.declareService,A.onEvent=s.onEvent,A.prototype=new s,A.prototype.constructor=A,C.__ready_list=s.__ready_list.slice(),C.ready=s.ready,C.setState=s.setState,C.onStateChange=s.onStateChange,C.__service_list=s.__service_list.slice(),C.declareService=s.declareService,C.onEvent=s.onEvent,C.prototype=new s,C.prototype.constructor=C,s.declareMethod("declareGadget",function(b,d){var e=this;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=I.getAbsoluteURL(b,this.__path),(new c.Queue).push(function(){var a;if("public"===d.sandbox)a=B;else if("iframe"===d.sandbox)a=D;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=E}return a(b,d,e)}).push(function(f){function g(){return f}function h(a){return function(){return a.call(f,f)}}var i,j,k=new c.Queue;for(i=0;i<f.constructor.__ready_list.length;i+=1)k.push(h(f.constructor.__ready_list[i])),k.push(g);if(j=d.scope,void 0===j)for(j="RJS_"+O,O+=1;e.__sub_gadget_dict.hasOwnProperty(j);)j="RJS_"+O,O+=1;return e.__sub_gadget_dict[j]=f,f.element.setAttribute("data-gadget-scope",j),f.element.setAttribute("data-gadget-url",b),f.element.setAttribute("data-gadget-sandbox",d.sandbox),f.element._gadget=f,a.contains(f.element)&&k.push(x),k.push(g),k})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),I=function(a){var c;if(a===b&&(c=N[0]),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},I.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},I.AcquisitionError.prototype=new Error,I.AcquisitionError.prototype.constructor=I.AcquisitionError,I.getAbsoluteURL=function(a,b){return b&&a?new l(a,b).href:a},I.declareJS=function(b,d,e){var f;return L.hasOwnProperty(b)?f=c.resolve():(L[b]=null,f=new c.Promise(function(c,f){var g;g=a.createElement("script"),g.async=!1,g.type="text/javascript",g.onload=function(){e===!0&&N.shift(),c()},g.onerror=function(a){e===!0&&N.shift(),f(a)},g.src=b,d.appendChild(g)})),f},I.declareCSS=function(b,d){var e;return e=M.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,e){var f;f=a.createElement("link"),f.rel="stylesheet",f.type="text/css",f.href=b,f.onload=function(){M[b]=null,c()},f.onerror=function(a){e(a)},d.appendChild(f)})},I.declareGadgetKlass=function(b){if(K.hasOwnProperty(b))return K[b].promise;var d,e=c.defer();return K[b]=e,H=e.promise,(new c.Queue).push(function(){return o(b)}).push(function(e){d=F(e,b);var f,g=a.createDocumentFragment(),h=[],i=d.prototype.__required_js_list,j=d.prototype.__required_css_list;if(i.length){for(N.push(d),f=0;f<i.length-1;f+=1)h.push(I.declareJS(i[f],g));h.push(I.declareJS(i[f],g,!0))}for(f=0;f<j.length;f+=1)h.push(I.declareCSS(j[f],g));return a.head.appendChild(g),c.all(h)}).push(function(){return e.resolve(d),d}).push(void 0,function(a){throw e.reject(a),a})},I.clearGadgetKlassList=function(){K={},L={},M={}},I.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!P.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(I.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(I.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(I.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=I,b.__RenderJSGadget=s,b.__RenderJSEmbeddedGadget=A,b.__RenderJSIframeGadget=C,G()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob,navigator,Event,URL);
\ No newline at end of file \ No newline at end of file
{ {
"name": "renderjs", "name": "renderjs",
"version": "0.12.1", "version": "0.13.0",
"description": "RenderJs provides HTML5 gadgets", "description": "RenderJs provides HTML5 gadgets",
"main": "dist/renderjs-latest.js", "main": "dist/renderjs-latest.js",
"dependencies": { "dependencies": {
......
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