Commit bdbcebe6 authored by Romain Courteaud's avatar Romain Courteaud

WIP automatic URL handler.

parent 914cbd3d
...@@ -666,7 +666,52 @@ if (typeof document.contains !== 'function') { ...@@ -666,7 +666,52 @@ if (typeof document.contains !== 'function') {
} }
} }
;/*! RenderJs */ ;/*! RenderJs */
/*global console*/
/*jslint nomen: true*/ /*jslint nomen: true*/
function loopEventListener(target, type, useCapture, callback) {
"use strict";
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
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) {
handle_event_callback = function (evt) {
evt.stopPropagation();
evt.preventDefault();
cancelResolver();
callback_promise = new RSVP.Queue()
.push(function () {
return callback(evt);
})
.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);
}
/* /*
* renderJs - Generic Gadget library renderer. * renderJs - Generic Gadget library renderer.
...@@ -741,6 +786,71 @@ if (typeof document.contains !== 'function') { ...@@ -741,6 +786,71 @@ if (typeof document.contains !== 'function') {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
function listenHashChange(gadget) {
function extractHashAndDispatch(evt) {
var hash = (evt.newURL || window.location.toString()).split('#')[1],
subhashes,
subhash,
keyvalue,
index,
options = {};
if (hash === undefined) {
hash = "";
} else {
hash = hash.split('?')[0];
}
function optionalize(key, value, dict) {
var key_list = key.split("."),
kk,
i;
for (i = 0; i < key_list.length; i += 1) {
kk = key_list[i];
if (i === key_list.length - 1) {
dict[kk] = value;
} else {
if (!dict.hasOwnProperty(kk)) {
dict[kk] = {};
}
dict = dict[kk];
}
}
}
subhashes = hash.split('&');
for (index in subhashes) {
if (subhashes.hasOwnProperty(index)) {
subhash = subhashes[index];
if (subhash !== '') {
keyvalue = subhash.split('=');
if (keyvalue.length === 2) {
optionalize(decodeURIComponent(keyvalue[0]),
decodeURIComponent(keyvalue[1]),
options);
}
}
}
}
if (gadget.render !== undefined) {
return gadget.render(options);
}
}
var result = loopEventListener(window, 'hashchange', false,
extractHashAndDispatch),
event = document.createEvent("Event");
event.initEvent('hashchange', true, true);
event.newURL = window.location.toString();
window.dispatchEvent(event);
return result;
}
function removeHash(url) { function removeHash(url) {
var index = url.indexOf('#'); var index = url.indexOf('#');
if (index > 0) { if (index > 0) {
...@@ -1070,6 +1180,8 @@ if (typeof document.contains !== 'function') { ...@@ -1070,6 +1180,8 @@ if (typeof document.contains !== 'function') {
}; };
RenderJSGadget.declareAcquiredMethod("aq_reportServiceError", RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
"reportServiceError"); "reportServiceError");
RenderJSGadget.declareAcquiredMethod("aq_pleasePublishMyState",
"pleasePublishMyState");
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition // RenderJSGadget.allowPublicAcquisition
...@@ -1090,6 +1202,22 @@ if (typeof document.contains !== 'function') { ...@@ -1090,6 +1202,22 @@ if (typeof document.contains !== 'function') {
}; };
} }
function pleasePublishMyState(param_list, child_gadget_scope) {
var new_param = {},
key;
for (key in this.state_parameter_dict) {
if (this.state_parameter_dict.hasOwnProperty(key)) {
new_param[key] = this.state_parameter_dict[key];
}
}
if (child_gadget_scope === undefined) {
throw new Error("gadget scope is mandatory");
}
new_param[child_gadget_scope] = param_list[0];
param_list = [new_param];
return this.aq_pleasePublishMyState.apply(this, param_list);
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSEmbeddedGadget // RenderJSEmbeddedGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1557,6 +1685,8 @@ if (typeof document.contains !== 'function') { ...@@ -1557,6 +1685,8 @@ if (typeof document.contains !== 'function') {
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {}; tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest // 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/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM // https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
...@@ -1667,6 +1797,39 @@ if (typeof document.contains !== 'function') { ...@@ -1667,6 +1797,39 @@ if (typeof document.contains !== 'function') {
// Bootstrap process. Register the self gadget. // Bootstrap process. Register the self gadget.
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
function mergeSubDict(dict) {
var subkey,
subkey2,
subresult2,
value,
result = {};
for (subkey in dict) {
if (dict.hasOwnProperty(subkey)) {
value = dict[subkey];
if (value instanceof Object) {
subresult2 = mergeSubDict(value);
for (subkey2 in subresult2) {
if (subresult2.hasOwnProperty(subkey2)) {
// XXX key should not have an . inside
if (result.hasOwnProperty(subkey + "." + subkey2)) {
throw new Error("Key " + subkey + "." +
subkey2 + " already present");
}
result[subkey + "." + subkey2] = subresult2[subkey2];
}
}
} else {
if (result.hasOwnProperty(subkey)) {
throw new Error("Key " + subkey + " already present");
}
result[subkey] = value;
}
}
}
return result;
}
function bootstrap() { function bootstrap() {
var url = removeHash(window.location.href), var url = removeHash(window.location.href),
tmp_constructor, tmp_constructor,
...@@ -1693,6 +1856,26 @@ if (typeof document.contains !== 'function') { ...@@ -1693,6 +1856,26 @@ if (typeof document.contains !== 'function') {
}, },
reportServiceError: function (param_list) { reportServiceError: function (param_list) {
letsCrash(param_list[0]); letsCrash(param_list[0]);
},
pleaseRedirectMyHash: function (param_list) {
window.location.replace(param_list[0]);
},
pleasePublishMyState: function (param_list) {
var key,
first = true,
hash = "#";
param_list[0] = mergeSubDict(param_list[0]);
for (key in param_list[0]) {
if (param_list[0].hasOwnProperty(key)) {
if (!first) {
hash += "&";
}
hash += encodeURIComponent(key) + "=" +
encodeURIComponent(param_list[0][key]);
first = false;
}
}
return hash;
} }
}; };
// Stop acquisition on the last acquisition gadget // Stop acquisition on the last acquisition gadget
...@@ -1734,6 +1917,10 @@ if (typeof document.contains !== 'function') { ...@@ -1734,6 +1917,10 @@ if (typeof document.contains !== 'function') {
// 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 gadget_model_dict[url]();
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
...@@ -1820,6 +2007,8 @@ if (typeof document.contains !== 'function') { ...@@ -1820,6 +2007,8 @@ if (typeof document.contains !== 'function') {
} }
tmp_constructor.prototype.__acquired_method_dict = {}; tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
gadget_loading_klass = tmp_constructor; gadget_loading_klass = tmp_constructor;
function init() { function init() {
...@@ -1972,6 +2161,9 @@ if (typeof document.contains !== 'function') { ...@@ -1972,6 +2161,9 @@ if (typeof document.contains !== 'function') {
//we consider current gadget is parent gadget //we consider current gadget is parent gadget
//redifine last acquisition gadget //redifine last acquisition gadget
iframe_top_gadget = true; iframe_top_gadget = true;
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
throw error; throw error;
......
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){"use strict";function j(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 k(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 l(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function m(b){if(b.constructor===XMLHttpRequest&&(b={readyState:b.readyState,status:b.status,statusText:b.statusText,response_headers:b.getAllResponseHeaders()}),b.constructor===Array||b.constructor===String||b.constructor===Object)try{b=JSON.stringify(b)}catch(c){}a.getElementsByTagName("body")[0].textContent=b,console.error(b.stack),console.error(b)}function n(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 o(){return this instanceof o?void 0:new o}function p(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new E,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return m(a)})}function q(a){a.__sub_gadget_dict={},p(a)}function r(a){var b,d,e,f,g,h=a.__element.querySelectorAll("[data-gadget-scope]"),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!==d&&null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function s(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a))}))}function t(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 D.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof D.AcquisitionError)return g.__aq_parent(b,d);throw a})}function u(a,b){a.__aq_parent=function(c,d){return t.apply(b,[a,c,d])}}function v(){return this instanceof v?void o.call(this):new v}function w(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 D.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(B=a,g=new a,g.__element=d.element,b=0;b<f.length;b+=1)g.__element.appendChild(f[b].cloneNode(!0));return u(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(D.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(D.declareCSS,a[1][b]));return d}).push(function(){return g})}function x(){return this instanceof x?void o.call(this):new x}function y(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 x,u(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.__element=d.element,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(){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,c.timeout(5e3)])}function z(a,b,e){return(new c.Queue).push(function(){return k(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"}),j(c)}).push(function(a){return y(a,b,e)})}function A(){var d,h,i,j,k,n,q,r=l(b.location.href),t=new c.Queue,w=0,x=!1;if(F.hasOwnProperty(r))throw new Error("bootstrap should not be called twice");C=new c.Promise(function(l,n){function t(){var b,e,i=D.parseGadgetHTMLDocument(a,r);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.__element=a.body,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)G[c[b]]=null;for(b=0;b<d.length;b+=1)H[d[b]]=null;B=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&&p(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&p(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)&&s(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&&s(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(l,function(a){throw n(a),console.error(a),a})}q=new o,q.__acquired_method_dict={getTopURL:function(){return r},reportServiceError:function(a){m(a[0])}},q.__aq_parent=function(a){throw new D.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){o.call(this)},d.declareMethod=o.declareMethod,d.declareAcquiredMethod=o.declareAcquiredMethod,d.allowPublicAcquisition=o.allowPublicAcquisition,d.__ready_list=o.__ready_list.slice(),d.ready=o.ready,d.__service_list=o.__service_list.slice(),d.declareService=o.declareService,d.prototype=new o,d.prototype.constructor=d,d.prototype.__path=r,F[r]=d,h=new F[r],u(h,q)):(i=e.build({window:b.parent,origin:"*",scope:"renderJS"}),d=v,d.__ready_list=o.__ready_list.slice(),d.__service_list=o.__service_list.slice(),d.prototype.__path=r,h=new v,j=function(){0===w&&x===!0&&i.notify({method:"ready"})},k=function(a){w+=1,i.call({method:"declareMethod",params:a,success:function(){w-=1,j()},error:function(){w-=1}})},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=o.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=o.declareService,d.declareAcquiredMethod=o.declareAcquiredMethod,d.allowPublicAcquisition=o.allowPublicAcquisition,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})})}),d.prototype.__acquired_method_dict={},B=d,a.addEventListener("DOMContentLoaded",t,!1)}),t.push(function(){return C}).push(function(c){function e(){return c}var f;for(b.top!==b.self&&d.__ready_list.splice(1,0,function(){return c.__aq_parent("getTopURL",[],100).then(function(b){var d=a.createElement("base");d.href=b,d.target="_top",a.head.appendChild(d),i.bind("methodCall",function(a,b){c[b[0]].apply(c,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)})}).fail(function(a){if("timeout_error"!==a)throw a;n=!0,u(c,q)})}),d.ready(function(a){return s(a)}),t.push(e),f=0;f<d.__ready_list.length;f+=1)t.push(d.__ready_list[f]).push(e)}),b.self===b.top?t.fail(function(a){throw m(a),a}):t.then(function(){x=!0,j()}).fail(function(a){throw n?m(a):i.notify({method:"failed",params:a.toString()}),a})}var B,C,D,E,F={},G={},H={},I=new RegExp("^(?:[a-z]+:)?//|data:","i");n.prototype=new Error,n.prototype.constructor=n,E=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 E?(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 n;var b=(new c.Queue).push(function(){return a}).push(function(){var a,b,c=h.length,d=[];for(b=0;c>b;b+=1)a=h[b],a.isFulfilled||a.isRejected||d.push(a);h=d},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 E},E.prototype=Object.create(c.Promise.prototype),E.prototype.constructor=E,o.prototype.__title="",o.prototype.__interface_list=[],o.prototype.__path="",o.prototype.__html="",o.prototype.__required_css_list=[],o.prototype.__required_js_list=[],o.__ready_list=[q,r],o.ready=function(a){return this.__ready_list.push(a),this},o.__service_list=[],o.declareService=function(a){return this.__service_list.push(a),this},o.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},o.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}),o.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},o.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),o.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},v.__ready_list=o.__ready_list.slice(),v.__service_list=o.__service_list.slice(),v.ready=o.ready,v.declareService=o.declareService,v.prototype=new o,v.prototype.constructor=v,x.__ready_list=o.__ready_list.slice(),x.ready=o.ready,x.__service_list=o.__service_list.slice(),x.declareService=o.declareService,x.prototype=new o,x.prototype.constructor=x,o.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=C;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=D.getAbsoluteURL(b,this.__path),C=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=w;else if("iframe"===d.sandbox)a=y;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=z}return a(b,d,g)}).push(function(a){return B=void 0,a}).push(void 0,function(a){throw B=void 0,a}),f=C,e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}var h;for(h=0;h<c.constructor.__ready_list.length;h+=1)e.push(c.constructor.__ready_list[h]),e.push(f);return void 0!==d.scope&&(g.__sub_gadget_dict[d.scope]=c,c.__element.setAttribute("data-gadget-scope",d.scope)),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(s),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]}),D=function(a){var c;if(a===b&&(c=B),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},D.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"},D.AcquisitionError.prototype=new Error,D.AcquisitionError.prototype.constructor=D.AcquisitionError,D.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!I.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},D.declareJS=function(b){var d;return d=G.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(){G[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},D.declareCSS=function(b){var d;return d=H.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(){H[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},D.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!F.hasOwnProperty(a)){c=function(){o.call(this)},c.__ready_list=o.__ready_list.slice(),c.__service_list=o.__service_list.slice(),c.declareMethod=o.declareMethod,c.declareAcquiredMethod=o.declareAcquiredMethod,c.allowPublicAcquisition=o.allowPublicAcquisition,c.ready=o.ready,c.declareService=o.declareService,c.prototype=new o,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=D.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);F[a]=c}return F[a]}var e;return e=F.hasOwnProperty(a)?c.resolve(F[a]):(new c.Queue).push(function(){return k(a)}).push(function(a){return b(a)})},D.clearGadgetKlassList=function(){F={},G={},H={}},D.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!I.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(D.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(D.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(D.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=D,b.__RenderJSGadget=o,b.__RenderJSEmbeddedGadget=v,b.__RenderJSIframeGadget=x,A()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob); function loopEventListener(a,b,c,d){"use strict";function e(){void 0!==i&&"function"==typeof i.cancel&&i.cancel()}function f(){void 0!==h&&a.removeEventListener(b,h,c),e()}function g(g,j){h=function(a){a.stopPropagation(),a.preventDefault(),e(),i=(new RSVP.Queue).push(function(){return d(a)}).push(void 0,function(a){a instanceof RSVP.CancellationError||(f(),j(a))})},a.addEventListener(b,h,c)}var h,i;return new RSVP.Promise(g,f)}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){"use strict";function j(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 k(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 l(c){function d(a){function d(a,b,c){var d,e,f=a.split(".");for(e=0;e<f.length;e+=1)d=f[e],e===f.length-1?c[d]=b:(c.hasOwnProperty(d)||(c[d]={}),c=c[d])}var e,f,g,h,i=(a.newURL||b.location.toString()).split("#")[1],j={};i=void 0===i?"":i.split("?")[0],e=i.split("&");for(h in e)e.hasOwnProperty(h)&&(f=e[h],""!==f&&(g=f.split("="),2===g.length&&d(decodeURIComponent(g[0]),decodeURIComponent(g[1]),j)));return void 0!==c.render?c.render(j):void 0}var e=loopEventListener(b,"hashchange",!1,d),f=a.createEvent("Event");return f.initEvent("hashchange",!0,!0),f.newURL=b.location.toString(),b.dispatchEvent(f),e}function m(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function n(b){if(b.constructor===XMLHttpRequest&&(b={readyState:b.readyState,status:b.status,statusText:b.statusText,response_headers:b.getAllResponseHeaders()}),b.constructor===Array||b.constructor===String||b.constructor===Object)try{b=JSON.stringify(b)}catch(c){}a.getElementsByTagName("body")[0].textContent=b,console.error(b.stack),console.error(b)}function o(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 p(){return this instanceof p?void 0:new p}function q(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new H,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return n(a)})}function r(a){a.__sub_gadget_dict={},q(a)}function s(a){var b,d,e,f,g,h=a.__element.querySelectorAll("[data-gadget-scope]"),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!==d&&null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function t(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a))}))}function u(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 G.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof G.AcquisitionError)return g.__aq_parent(b,d);throw a})}function v(a,b){a.__aq_parent=function(c,d){return u.apply(b,[a,c,d])}}function w(a,b){var c,d={};for(c in this.state_parameter_dict)this.state_parameter_dict.hasOwnProperty(c)&&(d[c]=this.state_parameter_dict[c]);if(void 0===b)throw new Error("gadget scope is mandatory");return d[b]=a[0],a=[d],this.aq_pleasePublishMyState.apply(this,a)}function x(){return this instanceof x?void p.call(this):new x}function y(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 G.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(E=a,g=new a,g.__element=d.element,b=0;b<f.length;b+=1)g.__element.appendChild(f[b].cloneNode(!0));return v(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(G.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(G.declareCSS,a[1][b]));return d}).push(function(){return g})}function z(){return this instanceof z?void p.call(this):new z}function A(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 z,v(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.__element=d.element,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(){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,c.timeout(5e3)])}function B(a,b,e){return(new c.Queue).push(function(){return k(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"}),j(c)}).push(function(a){return A(a,b,e)})}function C(a){var b,c,d,e,f={};for(b in a)if(a.hasOwnProperty(b))if(e=a[b],e instanceof Object){d=C(e);for(c in d)if(d.hasOwnProperty(c)){if(f.hasOwnProperty(b+"."+c))throw new Error("Key "+b+"."+c+" already present");f[b+"."+c]=d[c]}}else{if(f.hasOwnProperty(b))throw new Error("Key "+b+" already present");f[b]=e}return f}function D(){var d,h,i,j,k,o,r,s=m(b.location.href),u=new c.Queue,y=0,z=!1;if(I.hasOwnProperty(s))throw new Error("bootstrap should not be called twice");F=new c.Promise(function(m,o){function u(){var b,e,i=G.parseGadgetHTMLDocument(a,s);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.__element=a.body,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)J[c[b]]=null;for(b=0;b<d.length;b+=1)K[d[b]]=null;E=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&&q(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&q(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)&&t(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&&t(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(m,function(a){throw o(a),console.error(a),a})}r=new p,r.__acquired_method_dict={getTopURL:function(){return s},reportServiceError:function(a){n(a[0])},pleaseRedirectMyHash:function(a){b.location.replace(a[0])},pleasePublishMyState:function(a){var b,c=!0,d="#";a[0]=C(a[0]);for(b in a[0])a[0].hasOwnProperty(b)&&(c||(d+="&"),d+=encodeURIComponent(b)+"="+encodeURIComponent(a[0][b]),c=!1);return d}},r.__aq_parent=function(a){throw new G.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){p.call(this)},d.declareMethod=p.declareMethod,d.declareAcquiredMethod=p.declareAcquiredMethod,d.allowPublicAcquisition=p.allowPublicAcquisition,d.__ready_list=p.__ready_list.slice(),d.ready=p.ready,d.__service_list=p.__service_list.slice(),d.declareService=p.declareService,d.prototype=new p,d.prototype.constructor=d,d.prototype.__path=s,I[s]=d,h=new I[s],d.declareService(function(){return l(this)}),v(h,r)):(i=e.build({window:b.parent,origin:"*",scope:"renderJS"}),d=x,d.__ready_list=p.__ready_list.slice(),d.__service_list=p.__service_list.slice(),d.prototype.__path=s,h=new x,j=function(){0===y&&z===!0&&i.notify({method:"ready"})},k=function(a){y+=1,i.call({method:"declareMethod",params:a,success:function(){y-=1,j()},error:function(){y-=1}})},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=p.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=p.declareService,d.declareAcquiredMethod=p.declareAcquiredMethod,d.allowPublicAcquisition=p.allowPublicAcquisition,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})})}),d.prototype.__acquired_method_dict={},d.allowPublicAcquisition("pleasePublishMyState",w),E=d,a.addEventListener("DOMContentLoaded",u,!1)}),u.push(function(){return F}).push(function(c){function e(){return c}var f;for(b.top!==b.self&&d.__ready_list.splice(1,0,function(){return c.__aq_parent("getTopURL",[],100).then(function(b){var d=a.createElement("base");d.href=b,d.target="_top",a.head.appendChild(d),i.bind("methodCall",function(a,b){c[b[0]].apply(c,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)})}).fail(function(a){if("timeout_error"!==a)throw a;o=!0,d.declareService(function(){return l(this)}),v(c,r)})}),d.ready(function(a){return t(a)}),u.push(e),f=0;f<d.__ready_list.length;f+=1)u.push(d.__ready_list[f]).push(e)}),b.self===b.top?u.fail(function(a){throw n(a),a}):u.then(function(){z=!0,j()}).fail(function(a){throw o?n(a):i.notify({method:"failed",params:a.toString()}),a})}var E,F,G,H,I={},J={},K={},L=new RegExp("^(?:[a-z]+:)?//|data:","i");o.prototype=new Error,o.prototype.constructor=o,H=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 H?(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 o;var b=(new c.Queue).push(function(){return a}).push(function(){var a,b,c=h.length,d=[];for(b=0;c>b;b+=1)a=h[b],a.isFulfilled||a.isRejected||d.push(a);h=d},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 H},H.prototype=Object.create(c.Promise.prototype),H.prototype.constructor=H,p.prototype.__title="",p.prototype.__interface_list=[],p.prototype.__path="",p.prototype.__html="",p.prototype.__required_css_list=[],p.prototype.__required_js_list=[],p.__ready_list=[r,s],p.ready=function(a){return this.__ready_list.push(a),this},p.__service_list=[],p.declareService=function(a){return this.__service_list.push(a),this},p.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},p.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}),p.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},p.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),p.declareAcquiredMethod("aq_pleasePublishMyState","pleasePublishMyState"),p.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},x.__ready_list=p.__ready_list.slice(),x.__service_list=p.__service_list.slice(),x.ready=p.ready,x.declareService=p.declareService,x.prototype=new p,x.prototype.constructor=x,z.__ready_list=p.__ready_list.slice(),z.ready=p.ready,z.__service_list=p.__service_list.slice(),z.declareService=p.declareService,z.prototype=new p,z.prototype.constructor=z,p.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=F;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=G.getAbsoluteURL(b,this.__path),F=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=y;else if("iframe"===d.sandbox)a=A;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=B}return a(b,d,g)}).push(function(a){return E=void 0,a}).push(void 0,function(a){throw E=void 0,a}),f=F,e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}var h;for(h=0;h<c.constructor.__ready_list.length;h+=1)e.push(c.constructor.__ready_list[h]),e.push(f);return void 0!==d.scope&&(g.__sub_gadget_dict[d.scope]=c,c.__element.setAttribute("data-gadget-scope",d.scope)),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(t),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]}),G=function(a){var c;if(a===b&&(c=E),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},G.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"},G.AcquisitionError.prototype=new Error,G.AcquisitionError.prototype.constructor=G.AcquisitionError,G.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!L.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},G.declareJS=function(b){var d;return d=J.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(){J[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},G.declareCSS=function(b){var d;return d=K.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(){K[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},G.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!I.hasOwnProperty(a)){c=function(){p.call(this)},c.__ready_list=p.__ready_list.slice(),c.__service_list=p.__service_list.slice(),c.declareMethod=p.declareMethod,c.declareAcquiredMethod=p.declareAcquiredMethod,c.allowPublicAcquisition=p.allowPublicAcquisition,c.ready=p.ready,c.declareService=p.declareService,c.prototype=new p,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.allowPublicAcquisition("pleasePublishMyState",w),c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=G.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);I[a]=c}return I[a]}var e;return e=I.hasOwnProperty(a)?c.resolve(I[a]):(new c.Queue).push(function(){return k(a)}).push(function(a){return b(a)})},G.clearGadgetKlassList=function(){I={},J={},K={}},G.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!L.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(G.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(G.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(G.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=G,b.__RenderJSGadget=p,b.__RenderJSEmbeddedGadget=x,b.__RenderJSIframeGadget=z,D()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob);
\ No newline at end of file \ No newline at end of file
/*! RenderJs */ /*! RenderJs */
/*global console*/
/*jslint nomen: true*/ /*jslint nomen: true*/
function loopEventListener(target, type, useCapture, callback) {
"use strict";
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
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) {
handle_event_callback = function (evt) {
evt.stopPropagation();
evt.preventDefault();
cancelResolver();
callback_promise = new RSVP.Queue()
.push(function () {
return callback(evt);
})
.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);
}
/* /*
* renderJs - Generic Gadget library renderer. * renderJs - Generic Gadget library renderer.
...@@ -74,6 +119,71 @@ ...@@ -74,6 +119,71 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
function listenHashChange(gadget) {
function extractHashAndDispatch(evt) {
var hash = (evt.newURL || window.location.toString()).split('#')[1],
subhashes,
subhash,
keyvalue,
index,
options = {};
if (hash === undefined) {
hash = "";
} else {
hash = hash.split('?')[0];
}
function optionalize(key, value, dict) {
var key_list = key.split("."),
kk,
i;
for (i = 0; i < key_list.length; i += 1) {
kk = key_list[i];
if (i === key_list.length - 1) {
dict[kk] = value;
} else {
if (!dict.hasOwnProperty(kk)) {
dict[kk] = {};
}
dict = dict[kk];
}
}
}
subhashes = hash.split('&');
for (index in subhashes) {
if (subhashes.hasOwnProperty(index)) {
subhash = subhashes[index];
if (subhash !== '') {
keyvalue = subhash.split('=');
if (keyvalue.length === 2) {
optionalize(decodeURIComponent(keyvalue[0]),
decodeURIComponent(keyvalue[1]),
options);
}
}
}
}
if (gadget.render !== undefined) {
return gadget.render(options);
}
}
var result = loopEventListener(window, 'hashchange', false,
extractHashAndDispatch),
event = document.createEvent("Event");
event.initEvent('hashchange', true, true);
event.newURL = window.location.toString();
window.dispatchEvent(event);
return result;
}
function removeHash(url) { function removeHash(url) {
var index = url.indexOf('#'); var index = url.indexOf('#');
if (index > 0) { if (index > 0) {
...@@ -403,6 +513,8 @@ ...@@ -403,6 +513,8 @@
}; };
RenderJSGadget.declareAcquiredMethod("aq_reportServiceError", RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
"reportServiceError"); "reportServiceError");
RenderJSGadget.declareAcquiredMethod("aq_pleasePublishMyState",
"pleasePublishMyState");
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition // RenderJSGadget.allowPublicAcquisition
...@@ -423,6 +535,22 @@ ...@@ -423,6 +535,22 @@
}; };
} }
function pleasePublishMyState(param_list, child_gadget_scope) {
var new_param = {},
key;
for (key in this.state_parameter_dict) {
if (this.state_parameter_dict.hasOwnProperty(key)) {
new_param[key] = this.state_parameter_dict[key];
}
}
if (child_gadget_scope === undefined) {
throw new Error("gadget scope is mandatory");
}
new_param[child_gadget_scope] = param_list[0];
param_list = [new_param];
return this.aq_pleasePublishMyState.apply(this, param_list);
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSEmbeddedGadget // RenderJSEmbeddedGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -890,6 +1018,8 @@ ...@@ -890,6 +1018,8 @@
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {}; tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest // 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/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM // https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
...@@ -1000,6 +1130,39 @@ ...@@ -1000,6 +1130,39 @@
// Bootstrap process. Register the self gadget. // Bootstrap process. Register the self gadget.
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
function mergeSubDict(dict) {
var subkey,
subkey2,
subresult2,
value,
result = {};
for (subkey in dict) {
if (dict.hasOwnProperty(subkey)) {
value = dict[subkey];
if (value instanceof Object) {
subresult2 = mergeSubDict(value);
for (subkey2 in subresult2) {
if (subresult2.hasOwnProperty(subkey2)) {
// XXX key should not have an . inside
if (result.hasOwnProperty(subkey + "." + subkey2)) {
throw new Error("Key " + subkey + "." +
subkey2 + " already present");
}
result[subkey + "." + subkey2] = subresult2[subkey2];
}
}
} else {
if (result.hasOwnProperty(subkey)) {
throw new Error("Key " + subkey + " already present");
}
result[subkey] = value;
}
}
}
return result;
}
function bootstrap() { function bootstrap() {
var url = removeHash(window.location.href), var url = removeHash(window.location.href),
tmp_constructor, tmp_constructor,
...@@ -1026,6 +1189,26 @@ ...@@ -1026,6 +1189,26 @@
}, },
reportServiceError: function (param_list) { reportServiceError: function (param_list) {
letsCrash(param_list[0]); letsCrash(param_list[0]);
},
pleaseRedirectMyHash: function (param_list) {
window.location.replace(param_list[0]);
},
pleasePublishMyState: function (param_list) {
var key,
first = true,
hash = "#";
param_list[0] = mergeSubDict(param_list[0]);
for (key in param_list[0]) {
if (param_list[0].hasOwnProperty(key)) {
if (!first) {
hash += "&";
}
hash += encodeURIComponent(key) + "=" +
encodeURIComponent(param_list[0][key]);
first = false;
}
}
return hash;
} }
}; };
// Stop acquisition on the last acquisition gadget // Stop acquisition on the last acquisition gadget
...@@ -1067,6 +1250,10 @@ ...@@ -1067,6 +1250,10 @@
// 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 gadget_model_dict[url]();
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
...@@ -1153,6 +1340,8 @@ ...@@ -1153,6 +1340,8 @@
} }
tmp_constructor.prototype.__acquired_method_dict = {}; tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
gadget_loading_klass = tmp_constructor; gadget_loading_klass = tmp_constructor;
function init() { function init() {
...@@ -1305,6 +1494,9 @@ ...@@ -1305,6 +1494,9 @@
//we consider current gadget is parent gadget //we consider current gadget is parent gadget
//redifine last acquisition gadget //redifine last acquisition gadget
iframe_top_gadget = true; iframe_top_gadget = true;
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
throw error; throw error;
......
...@@ -16,8 +16,12 @@ ...@@ -16,8 +16,12 @@
RenderJSIframeGadget = __RenderJSIframeGadget; RenderJSIframeGadget = __RenderJSIframeGadget;
// Keep track of the root gadget // Keep track of the root gadget
renderJS(window).ready(function (g) { renderJS(window)
.ready(function (g) {
root_gadget_defer.resolve(g); root_gadget_defer.resolve(g);
})
.declareMethod("render", function (options) {
this.__last_options = options;
}); });
...@@ -453,7 +457,11 @@ ...@@ -453,7 +457,11 @@
var instance; var instance;
equal(Klass.prototype.__path, url); equal(Klass.prototype.__path, url);
deepEqual(Klass.prototype.__acquired_method_dict, {}); deepEqual(
Klass.prototype.__acquired_method_dict,
{pleasePublishMyState:
Klass.prototype.__acquired_method_dict.pleasePublishMyState}
);
equal(Klass.prototype.__foo, 'bar'); equal(Klass.prototype.__foo, 'bar');
equal(Klass.__template_element.nodeType, 9); equal(Klass.__template_element.nodeType, 9);
...@@ -522,7 +530,11 @@ ...@@ -522,7 +530,11 @@
var instance; var instance;
equal(Klass.prototype.__path, url); equal(Klass.prototype.__path, url);
deepEqual(Klass.prototype.__acquired_method_dict, {}); deepEqual(
Klass.prototype.__acquired_method_dict,
{pleasePublishMyState:
Klass.prototype.__acquired_method_dict.pleasePublishMyState}
);
instance = new Klass(); instance = new Klass();
ok(instance instanceof RenderJSGadget); ok(instance instanceof RenderJSGadget);
...@@ -2269,7 +2281,11 @@ ...@@ -2269,7 +2281,11 @@
gadget.declareGadget(url)//, document.getElementById('qunit-fixture')) gadget.declareGadget(url)//, document.getElementById('qunit-fixture'))
.then(function (new_gadget) { .then(function (new_gadget) {
equal(new_gadget.__path, url); equal(new_gadget.__path, url);
deepEqual(new_gadget.__acquired_method_dict, {}); deepEqual(
new_gadget.__acquired_method_dict,
{pleasePublishMyState:
new_gadget.__acquired_method_dict.pleasePublishMyState}
);
ok(new_gadget instanceof RenderJSGadget); ok(new_gadget instanceof RenderJSGadget);
}) })
.always(function () { .always(function () {
...@@ -3591,8 +3607,15 @@ ...@@ -3591,8 +3607,15 @@
// Check instance // Check instance
equal(root_gadget.__path, equal(root_gadget.__path,
root_gadget_path_without_hash); root_gadget_path_without_hash);
equal(typeof root_gadget.__acquired_method_dict, 'object'); deepEqual(
equal(Object.keys(root_gadget.__acquired_method_dict).length, 1); root_gadget.__acquired_method_dict,
{
pleasePublishMyState:
root_gadget.__acquired_method_dict.pleasePublishMyState,
getTopURL:
root_gadget.__acquired_method_dict.getTopURL
}
);
equal(root_gadget.__title, document.title); equal(root_gadget.__title, document.title);
deepEqual(root_gadget.__interface_list, []); deepEqual(root_gadget.__interface_list, []);
deepEqual(root_gadget.__required_css_list, deepEqual(root_gadget.__required_css_list,
...@@ -3642,7 +3665,7 @@ ...@@ -3642,7 +3665,7 @@
ok(root_gadget.__aq_parent !== undefined); ok(root_gadget.__aq_parent !== undefined);
ok(root_gadget.hasOwnProperty("__sub_gadget_dict")); ok(root_gadget.hasOwnProperty("__sub_gadget_dict"));
deepEqual(root_gadget.__sub_gadget_dict, {}); deepEqual(root_gadget.__sub_gadget_dict, {});
deepEqual(root_gadget_klass.__service_list, []); deepEqual(root_gadget_klass.__service_list.length, 1);
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return root_gadget.getTopURL().then(function (topURL) { return root_gadget.getTopURL().then(function (topURL) {
...@@ -3720,5 +3743,126 @@ ...@@ -3720,5 +3743,126 @@
}); });
}); });
/////////////////////////////////////////////////////////////////
// RenderJSGadget URL
/////////////////////////////////////////////////////////////////
module("RenderJSGadget URL", {
setup: function () {
renderJS.clearGadgetKlassList();
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test('Check that the root gadget renders on hashchange', function () {
var root_gadget,
rand_int = Math.random();
stop();
root_gadget_defer.promise
.then(function (gadget) {
root_gadget = gadget;
window.location.hash = 'a=b&c=de&f.g=h' + rand_int;
return RSVP.delay(200);
})
.then(function () {
deepEqual(
root_gadget.__last_options,
{a: 'b', c: 'de', f: {g: 'h' + rand_int}}
);
})
.fail(function (e) {
ok(false, e);
})
.always(function () {
start();
});
});
test('pleasePublishMyState on root gadget', function () {
stop();
root_gadget_defer.promise
.then(function (root_gadget) {
return root_gadget.aq_pleasePublishMyState({a: 'b', c: {d: 'e'}});
})
.then(function (result) {
equal(result, '#a=b&c.d=e');
})
.fail(function (e) {
ok(false, e);
})
.always(function () {
start();
});
});
test('pleasePublishMyState rejected on anonymous subgadget', function () {
// Check that declare gadget returns the gadget
var url = 'https://example.org/files/qunittest/test',
html = "<html><body></body></html>";
this.server.respondWith("GET", url, [200, {
"Content-Type": "text/html"
}, html]);
stop();
renderJS.declareGadgetKlass(url)
.then(function (root_gadget) {
return root_gadget_defer.promise;
})
.then(function (root_gadget) {
return root_gadget.declareGadget(url);
})
.then(function (new_gadget) {
return new_gadget.aq_pleasePublishMyState({a: 'b', c: {d: 'e'}});
})
.then(function () {
ok(false, "aq_pleasePublishMyState should fail in anonymous");
})
.fail(function (error) {
ok(error instanceof Error);
equal(error.message, "gadget scope is mandatory");
})
.always(function () {
start();
});
});
test('pleasePublishMyState includes gadget scope', function () {
// Check that declare gadget returns the gadget
var url = 'https://example.org/files/qunittest/test',
html = "<html><body></body></html>";
this.server.respondWith("GET", url, [200, {
"Content-Type": "text/html"
}, html]);
stop();
renderJS.declareGadgetKlass(url)
.then(function (root_gadget) {
return root_gadget_defer.promise;
})
.then(function (root_gadget) {
return root_gadget.declareGadget(url, {scope: "foo"});
})
.then(function (new_gadget) {
return new_gadget.aq_pleasePublishMyState({a: 'b', c: {d: 'e'}});
})
.then(function (result) {
equal(result, "#foo.a=b&foo.c.d=e");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
}(document, renderJS, QUnit, sinon, URI)); }(document, renderJS, QUnit, sinon, URI));
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