Commit fe6c5bcc authored by Romain Courteaud's avatar Romain Courteaud

Gadgets are now event targets.

The method .on, .off, .trigger have been added.
See RSVP.EventTarget.mixin for full details.

Propagate the events in case of EmbeddedGadget to the parent IframeGadget.
parent 12476ce5
This diff is collapsed.
!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(a,b,c,d,e,f){"use strict";function g(){return this instanceof g?void 0:new g}function h(){return this instanceof h?(g.call(this),void 0):new h}function i(b,d){var e;return d.element===f&&(d.element=a.createElement("div")),(new c.Queue).push(function(){return o.declareGadgetKlass(b)}).push(function(a){var b,f=a.template_element.body.childNodes;for(m=a,e=new a,e.element=d.element,b=0;b<f.length;b+=1)e.element.appendChild(f[b].cloneNode(!0));return c.all([e.getRequiredJSList(),e.getRequiredCSSList()])}).push(function(a){var b,d=[];for(b=0;b<a[0].length;b+=1)d.push(o.declareJS(a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(o.declareCSS(a[1][b]));return c.all(d)}).push(function(){return e})}function j(){return this instanceof j?(g.call(this),void 0):new j}function k(b,d){var g,h,i,k=c.defer();if(d.element===f)throw new Error("DOM element is required to create Iframe Gadget "+b);for(i=d.element.parentNode;null!==i&&i!==a;)i=i.parentNode;if(null===i)throw new Error("The parent element is not attached to the DOM for "+b);return g=new j,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;return 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)}})})},"OK"}),g.chan.bind("ready",function(){return k.resolve(g),"OK"}),g.chan.bind("failed",function(a,b){return k.reject(b),"OK"}),g.chan.bind("trigger",function(a,b){return g.trigger(b.event_name,b.options)}),c.any([k.promise,c.timeout(5e3)])}function l(){var d,i,j,k,l,s,t=b.location.href,u=0,v=!1;if(p.hasOwnProperty(t))throw new Error("bootstrap should not be called twice");n=new c.Promise(function(n,w){function x(){var b,e,g=o.parseGadgetHTMLDocument(a);for(e in g)g.hasOwnProperty(e)&&(d.prototype[e]=g[e]);for(d.template_element=a.createElement("div"),i.element=a.body,b=0;b<i.element.childNodes.length;b+=1)d.template_element.appendChild(i.element.childNodes[b].cloneNode(!0));c.all([i.getRequiredJSList(),i.getRequiredCSSList()]).then(function(a){function b(){return i}var e,g,h=a[0],j=a[1];for(e=0;e<h.length;e+=1)q[h[e]]=null;for(e=0;e<j.length;e+=1)r[j[e]]=null;for(m=f,g=new c.Queue,g.push(b),e=0;e<d.ready_list.length;e+=1)g.push(d.ready_list[e]),g.push(b);return g.push(n,function(a){throw w(a),a}),g}).fail(function(a){w(a)})}b.self===b.top?(d=function(){g.call(this)},d.declareMethod=g.declareMethod,d.ready_list=[],d.ready=g.ready,d.prototype=new g,d.prototype.constructor=d,d.prototype.path=t,p[t]=d,i=new p[t]):(j=e.build({window:b.parent,origin:"*",scope:"renderJS"}),d=h,i=new h,j.bind("methodCall",function(a,b){i[b[0]].apply(i,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),k=function(){0===u&&v===!0&&j.notify({method:"ready"})},l=function(a){u+=1,j.call({method:"declareMethod",params:a,success:function(){u-=1,k()},error:function(){u-=1}})},l("getInterfaceList"),l("getRequiredCSSList"),l("getRequiredJSList"),l("getPath"),l("getTitle"),d.declareMethod=function(a,b){var c=g.declareMethod.apply(this,[a,b]);return l(a),c},s=function(a,b){j.notify({method:"trigger",params:{event_name:a,options:b}})},d.prototype.trigger=function(a,b){var c=g.prototype.trigger.apply(this,[a,b]);return s(a,b),c}),m=d,a.addEventListener("DOMContentLoaded",x,!1)}),b.self!==b.top&&n.then(function(){v=!0,k()}).fail(function(a){throw j.notify({method:"failed",params:a.toString()}),a})}var m,n,o,p={},q={},r={};g.prototype.title="",g.prototype.interface_list=[],g.prototype.path="",g.prototype.html="",g.prototype.required_css_list=[],g.prototype.required_js_list=[],c.EventTarget.mixin(g.prototype),g.ready_list=[],g.ready=function(a){return this.ready_list.push(a),this},g.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},g.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(this.element===f)throw new Error("No element defined");return this.element}),h.ready_list=[],h.ready=g.ready,h.prototype=new g,h.prototype.constructor=h,j.ready_list=[],j.ready=g.ready,j.prototype=new g,j.prototype.constructor=j,g.prototype.declareGadget=function(a,b){var d,e=n;return b===f&&(b={}),b.sandbox===f&&(b.sandbox="public"),d=(new c.Queue).push(function(){return e}).push(f,function(){}).push(function(){var c;if("public"===b.sandbox)c=i;else{if("iframe"!==b.sandbox)throw new Error("Unsupported sandbox options '"+b.sandbox+"'");c=k}return c(a,b)}).push(function(a){function b(){return a}var c;for(m=f,c=0;c<a.constructor.ready_list.length;c+=1)d.push(a.constructor.ready_list[c]),d.push(b);return a}).push(f,function(a){throw m=f,a}),n=d},o=function(a){var c;if(a===b?c=m:a instanceof g&&(c=a),c===f)throw new Error("Unknown selector '"+a+"'");return c},o.declareJS=function(b){var d;return d=q.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(){q[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},o.declareCSS=function(b){var d;return d=r.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(){r[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},o.declareGadgetKlass=function(a){function b(){var b,c,e;if(!p.hasOwnProperty(a)){b=function(){g.call(this)},b.ready_list=[],b.declareMethod=g.declareMethod,b.ready=g.ready,b.prototype=new g,b.prototype.constructor=b,b.prototype.path=a,b.template_element=(new d).parseFromString(j.responseText,"text/html"),e=o.parseGadgetHTMLDocument(b.template_element);for(c in e)e.hasOwnProperty(c)&&(b.prototype[c]=e[c]);p[a]=b}return p[a]}function e(c,d){function e(){var a;try{0===j.readyState?d(j):4===j.readyState&&(j.status<200||j.status>=300||!/^text\/html[;]?/.test(j.getResponseHeader("Content-Type")||"")?d(j):(a=b(),c(a)))}catch(e){d(e)}}j=new XMLHttpRequest,j.open("GET",a),j.onreadystatechange=e,j.setRequestHeader("Accept","text/html"),j.withCredentials=!0,j.send()}function h(){j!==f&&j.readyState!==j.DONE&&j.abort()}var i,j;return i=p.hasOwnProperty(a)?c.resolve(p[a]):new c.Promise(e,h)},o.clearGadgetKlassList=function(){p={},q={},r={}},o.parseGadgetHTMLDocument=function(a){var b,c,d={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");for(d.title=a.title,b=0;b<a.head.children.length;b+=1)c=a.head.children[b],null!==c.href&&("stylesheet"===c.rel?d.required_css_list.push(c.getAttribute("href")):"text/javascript"===c.type?d.required_js_list.push(c.getAttribute("src")):"http://www.renderjs.org/rel/interface"===c.rel&&d.interface_list.push(c.getAttribute("href")));return d},b.rJS=b.renderJS=o,b.RenderJSGadget=g,b.RenderJSEmbeddedGadget=h,b.RenderJSIframeGadget=j,l()}(document,window,RSVP,DOMParser,Channel);
\ No newline at end of file
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
RenderJSGadget.prototype.required_css_list = []; RenderJSGadget.prototype.required_css_list = [];
RenderJSGadget.prototype.required_js_list = []; RenderJSGadget.prototype.required_js_list = [];
RSVP.EventTarget.mixin(RenderJSGadget.prototype);
RenderJSGadget.ready_list = []; RenderJSGadget.ready_list = [];
RenderJSGadget.ready = function (callback) { RenderJSGadget.ready = function (callback) {
this.ready_list.push(callback); this.ready_list.push(callback);
...@@ -283,6 +285,9 @@ ...@@ -283,6 +285,9 @@
iframe_loading_deferred.reject(params); iframe_loading_deferred.reject(params);
return "OK"; return "OK";
}); });
gadget_instance.chan.bind("trigger", function (trans, params) {
return gadget_instance.trigger(params.event_name, params.options);
});
return RSVP.any([ return RSVP.any([
iframe_loading_deferred.promise, iframe_loading_deferred.promise,
// Timeout to prevent non renderJS embeddable gadget // Timeout to prevent non renderJS embeddable gadget
...@@ -589,6 +594,7 @@ ...@@ -589,6 +594,7 @@
embedded_channel, embedded_channel,
notifyReady, notifyReady,
notifyDeclareMethod, notifyDeclareMethod,
notifyTrigger,
gadget_ready = false; gadget_ready = false;
...@@ -672,6 +678,26 @@ ...@@ -672,6 +678,26 @@
notifyDeclareMethod(name); notifyDeclareMethod(name);
return result; return result;
}; };
notifyTrigger = function (eventName, options) {
embedded_channel.notify({
method: "trigger",
params: {
event_name: eventName,
options: options
}
});
};
// Surcharge trigger to inform parent window
tmp_constructor.prototype.trigger = function (eventName, options) {
var result = RenderJSGadget.prototype.trigger.apply(
this,
[eventName, options]
);
notifyTrigger(eventName, options);
return result;
};
} }
gadget_loading_klass = tmp_constructor; gadget_loading_klass = tmp_constructor;
......
This diff is collapsed.
{ {
"name": "renderjs", "name": "renderjs",
"version": "0.3.3", "version": "0.4.0",
"description": "RenderJs provides HTML5 gadgets", "description": "RenderJs provides HTML5 gadgets",
"main": "dist/renderjs-latest.js", "main": "dist/renderjs-latest.js",
"directories": { "directories": {
......
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
RenderJSGadget.prototype.required_css_list = []; RenderJSGadget.prototype.required_css_list = [];
RenderJSGadget.prototype.required_js_list = []; RenderJSGadget.prototype.required_js_list = [];
RSVP.EventTarget.mixin(RenderJSGadget.prototype);
RenderJSGadget.ready_list = []; RenderJSGadget.ready_list = [];
RenderJSGadget.ready = function (callback) { RenderJSGadget.ready = function (callback) {
this.ready_list.push(callback); this.ready_list.push(callback);
...@@ -283,6 +285,9 @@ ...@@ -283,6 +285,9 @@
iframe_loading_deferred.reject(params); iframe_loading_deferred.reject(params);
return "OK"; return "OK";
}); });
gadget_instance.chan.bind("trigger", function (trans, params) {
return gadget_instance.trigger(params.event_name, params.options);
});
return RSVP.any([ return RSVP.any([
iframe_loading_deferred.promise, iframe_loading_deferred.promise,
// Timeout to prevent non renderJS embeddable gadget // Timeout to prevent non renderJS embeddable gadget
...@@ -589,6 +594,7 @@ ...@@ -589,6 +594,7 @@
embedded_channel, embedded_channel,
notifyReady, notifyReady,
notifyDeclareMethod, notifyDeclareMethod,
notifyTrigger,
gadget_ready = false; gadget_ready = false;
...@@ -672,6 +678,26 @@ ...@@ -672,6 +678,26 @@
notifyDeclareMethod(name); notifyDeclareMethod(name);
return result; return result;
}; };
notifyTrigger = function (eventName, options) {
embedded_channel.notify({
method: "trigger",
params: {
event_name: eventName,
options: options
}
});
};
// Surcharge trigger to inform parent window
tmp_constructor.prototype.trigger = function (eventName, options) {
var result = RenderJSGadget.prototype.trigger.apply(
this,
[eventName, options]
);
notifyTrigger(eventName, options);
return result;
};
} }
gadget_loading_klass = tmp_constructor; gadget_loading_klass = tmp_constructor;
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
.declareMethod('triggerError', function (value) { .declareMethod('triggerError', function (value) {
throw new Error("Manually triggered embedded error"); throw new Error("Manually triggered embedded error");
}) })
.declareMethod('triggerEvent', function (value) {
return rJS(this).trigger('fooTrigger', 'barValue');
})
.declareMethod('setContent', function (value) { .declareMethod('setContent', function (value) {
rJS(this).embedded_property = value; rJS(this).embedded_property = value;
}) })
......
...@@ -410,6 +410,9 @@ ...@@ -410,6 +410,9 @@
ok(instance instanceof RenderJSGadget); ok(instance instanceof RenderJSGadget);
ok(instance instanceof Klass); ok(instance instanceof Klass);
ok(Klass !== RenderJSGadget); ok(Klass !== RenderJSGadget);
ok(instance.on !== undefined);
ok(instance.off !== undefined);
ok(instance.trigger !== undefined);
}) })
.fail(function (e) { .fail(function (e) {
ok(false, JSON.stringify(e)); ok(false, JSON.stringify(e));
...@@ -1339,6 +1342,9 @@ ...@@ -1339,6 +1342,9 @@
ok(gadget instanceof RenderJSGadget); ok(gadget instanceof RenderJSGadget);
ok(gadget instanceof RenderJSIframeGadget); ok(gadget instanceof RenderJSIframeGadget);
ok(RenderJSIframeGadget !== RenderJSGadget); ok(RenderJSIframeGadget !== RenderJSGadget);
ok(gadget.on !== undefined);
ok(gadget.off !== undefined);
ok(gadget.trigger !== undefined);
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1380,6 +1386,9 @@ ...@@ -1380,6 +1386,9 @@
ok(gadget instanceof RenderJSGadget); ok(gadget instanceof RenderJSGadget);
ok(gadget instanceof RenderJSEmbeddedGadget); ok(gadget instanceof RenderJSEmbeddedGadget);
ok(RenderJSEmbeddedGadget !== RenderJSGadget); ok(RenderJSEmbeddedGadget !== RenderJSGadget);
ok(gadget.on !== undefined);
ok(gadget.off !== undefined);
ok(gadget.trigger !== undefined);
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1901,6 +1910,30 @@ ...@@ -1901,6 +1910,30 @@
ok(false, "triggerError should fail"); ok(false, "triggerError should fail");
}, function (e) { }, function (e) {
equal(e, "Error: Manually triggered embedded error"); equal(e, "Error: Manually triggered embedded error");
})
// Events are propagated
.push(function () {
var waiting_event = RSVP.defer();
new_gadget.on("fooTrigger", function (param) {
waiting_event.resolve(param);
});
new_gadget.triggerEvent();
return RSVP.any([
waiting_event.promise,
RSVP.timeout(500)
])
.then(function (all_results) {
// RSVP return string inside event's detail property
equal(all_results.detail, "barValue");
})
.fail(function (e) {
ok(false, e);
})
.always(function () {
new_gadget.off("fooTrigger");
});
}); });
}) })
.fail(function () { .fail(function () {
...@@ -1957,6 +1990,9 @@ ...@@ -1957,6 +1990,9 @@
]); ]);
var html = root_gadget.constructor.template_element.outerHTML; var html = root_gadget.constructor.template_element.outerHTML;
ok(/^<div>\s*<h1 id="qunit-header">/.test(html), html); ok(/^<div>\s*<h1 id="qunit-header">/.test(html), html);
ok(root_gadget.on !== undefined);
ok(root_gadget.off !== undefined);
ok(root_gadget.trigger !== undefined);
ok(root_gadget instanceof RenderJSGadget); ok(root_gadget instanceof RenderJSGadget);
ok(root_gadget_klass, root_gadget.constructor); ok(root_gadget_klass, root_gadget.constructor);
}) })
......
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