Commit f55764ba authored by Romain Courteaud's avatar Romain Courteaud

Add onEvent method.

This will declare a service to listen to a DOM event on the gadget element.
parent 7cda5337
...@@ -93,7 +93,8 @@ module.exports = function (grunt) { ...@@ -93,7 +93,8 @@ module.exports = function (grunt) {
'__RenderJSIframeGadget', '__RenderJSIframeGadget',
'__RenderJSEmbeddedGadget', '__RenderJSEmbeddedGadget',
'FileReader', 'FileReader',
'Blob' 'Blob',
'Event'
] ]
} }
} }
......
...@@ -22,6 +22,66 @@ ...@@ -22,6 +22,66 @@
}); });
} }
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) { function ajax(url) {
var xhr; var xhr;
function resolver(resolve, reject) { function resolver(resolve, reject) {
...@@ -394,6 +454,14 @@ ...@@ -394,6 +454,14 @@
this.__service_list.push(callback); this.__service_list.push(callback);
return this; 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 startService(gadget) { function startService(gadget) {
gadget.__monitor.monitor(new RSVP.Queue() gadget.__monitor.monitor(new RSVP.Queue()
...@@ -541,6 +609,8 @@ ...@@ -541,6 +609,8 @@
RenderJSGadget.ready; RenderJSGadget.ready;
RenderJSEmbeddedGadget.declareService = RenderJSEmbeddedGadget.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
RenderJSEmbeddedGadget.onEvent =
RenderJSGadget.onEvent;
RenderJSEmbeddedGadget.prototype = new RenderJSGadget(); RenderJSEmbeddedGadget.prototype = new RenderJSGadget();
RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget; RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget;
...@@ -616,6 +686,8 @@ ...@@ -616,6 +686,8 @@
RenderJSIframeGadget.__service_list = RenderJSGadget.__service_list.slice(); RenderJSIframeGadget.__service_list = RenderJSGadget.__service_list.slice();
RenderJSIframeGadget.declareService = RenderJSIframeGadget.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
RenderJSIframeGadget.onEvent =
RenderJSGadget.onEvent;
RenderJSIframeGadget.prototype = new RenderJSGadget(); RenderJSIframeGadget.prototype = new RenderJSGadget();
RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget; RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget;
...@@ -1008,6 +1080,8 @@ ...@@ -1008,6 +1080,8 @@
RenderJSGadget.ready; RenderJSGadget.ready;
tmp_constructor.declareService = tmp_constructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget(); tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
...@@ -1182,6 +1256,8 @@ ...@@ -1182,6 +1256,8 @@
tmp_constructor.__service_list = RenderJSGadget.__service_list.slice(); tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
tmp_constructor.declareService = tmp_constructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.prototype = new RenderJSGadget(); tmp_constructor.prototype = new RenderJSGadget();
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
...@@ -1304,6 +1380,8 @@ ...@@ -1304,6 +1380,8 @@
tmp_constructor.declareService = tmp_constructor.declareService =
RenderJSGadget.declareService; RenderJSGadget.declareService;
tmp_constructor.onEvent =
RenderJSGadget.onEvent;
tmp_constructor.declareAcquiredMethod = tmp_constructor.declareAcquiredMethod =
RenderJSGadget.declareAcquiredMethod; RenderJSGadget.declareAcquiredMethod;
tmp_constructor.allowPublicAcquisition = tmp_constructor.allowPublicAcquisition =
......
...@@ -4,13 +4,19 @@ ...@@ -4,13 +4,19 @@
var gk = rJS(window), var gk = rJS(window),
ready_called = false, ready_called = false,
service_started = false; service_started = false,
event_started = false;
gk.ready(function (g) { gk.ready(function (g) {
ready_called = true; ready_called = true;
}) })
.onEvent('bar', function () {
event_started = true;
})
.declareService(function () { .declareService(function () {
service_started = true; service_started = true;
var event = new Event("bar");
this.__element.dispatchEvent(event);
}) })
.declareMethod('wasReadyCalled', function () { .declareMethod('wasReadyCalled', function () {
return ready_called; return ready_called;
...@@ -18,6 +24,9 @@ ...@@ -18,6 +24,9 @@
.declareMethod('wasServiceStarted', function () { .declareMethod('wasServiceStarted', function () {
return service_started; return service_started;
}) })
.declareMethod('wasEventStarted', function () {
return event_started;
})
.declareMethod('canReportServiceError', function () { .declareMethod('canReportServiceError', function () {
return (this.aq_reportServiceError !== undefined); return (this.aq_reportServiceError !== undefined);
}) })
......
/*jslint nomen: true*/ /*jslint nomen: true*/
(function (document, renderJS, QUnit, sinon, URI, URL) { (function (document, renderJS, QUnit, sinon, URI, URL, Event) {
"use strict"; "use strict";
var test = QUnit.test, var test = QUnit.test,
stop = QUnit.stop, stop = QUnit.stop,
...@@ -2147,6 +2147,138 @@ ...@@ -2147,6 +2147,138 @@
}); });
}); });
/////////////////////////////////////////////////////////////////
// RenderJSGadgetKlass.onEvent
/////////////////////////////////////////////////////////////////
module("RenderJSGadgetKlass.onEvent", {
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('is chainable', function () {
// Check that declareService is chainable
// Subclass RenderJSGadget to not pollute its namespace
var Klass = function () {
RenderJSGadget.call(this);
}, result;
Klass.prototype = new RenderJSGadget();
Klass.prototype.constructor = Klass;
Klass.__service_list = [];
Klass.onEvent = RenderJSGadget.onEvent;
result = Klass.onEvent(function () {
return;
});
// onEvent is chainable
equal(result, Klass);
});
test('create callback in the service_list property', function () {
// Subclass RenderJSGadget to not pollute its namespace
var Klass = function () {
RenderJSGadget.call(this);
},
callback = function () {return; };
Klass.prototype = new RenderJSGadget();
Klass.prototype.constructor = Klass;
Klass.__service_list = [];
Klass.onEvent = RenderJSGadget.onEvent;
Klass.onEvent('foo', callback);
equal(Klass.__service_list.length, 1);
});
function declareEventToCheck(klass, service_status) {
service_status.start_count = 0;
service_status.stop_count = 0;
service_status.status = undefined;
klass.onEvent('bar', function (evt) {
service_status.start_count += 1;
return new RSVP.Queue()
.push(function () {
service_status.status = "started";
return RSVP.defer().promise;
})
.push(undefined, function (error) {
service_status.stop_count += 1;
if (error instanceof RSVP.CancellationError) {
service_status.status = "stopped";
} else {
service_status.status = "error";
}
throw error;
});
});
}
test('callback is triggered on event', function () {
var service1 = {},
gadget = new RenderJSGadget(),
html_url = 'https://example.org/files/qunittest/test599.html';
gadget.__sub_gadget_dict = {};
this.server.respondWith("GET", html_url, [200, {
"Content-Type": "text/html"
}, "<html><body></body></html>"]);
document.getElementById('qunit-fixture').innerHTML = "<div></div>";
stop();
renderJS.declareGadgetKlass(html_url)
.then(function (Klass) {
declareEventToCheck(Klass, service1);
return gadget.declareGadget(
html_url,
{element: document.getElementById('qunit-fixture')
.querySelector("div")}
);
})
.then(function (g) {
return RSVP.delay(50);
})
.then(function () {
equal(service1.start_count, 0);
equal(service1.stop_count, 0);
equal(service1.status, undefined);
var event = new Event("bar");
document.getElementById('qunit-fixture').querySelector("div")
.dispatchEvent(event);
return RSVP.delay(50);
})
.then(function () {
equal(service1.start_count, 1);
equal(service1.stop_count, 0);
equal(service1.status, "started");
var event = new Event("bar");
document.getElementById('qunit-fixture').querySelector("div")
.dispatchEvent(event);
return RSVP.delay(50);
})
.then(function () {
equal(service1.start_count, 2);
equal(service1.stop_count, 1);
equal(service1.status, "started");
})
.fail(function (e) {
ok(false, e);
})
.always(function () {
start();
});
});
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSIframeGadget // RenderJSIframeGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -3456,6 +3588,14 @@ ...@@ -3456,6 +3588,14 @@
equal(result, true); equal(result, true);
}) })
// Check that event are started
.push(function () {
return new_gadget.wasEventStarted();
})
.push(function (result) {
equal(result, true);
})
// Check that service error can be reported // Check that service error can be reported
.push(function () { .push(function () {
return new_gadget.canReportServiceError(); return new_gadget.canReportServiceError();
...@@ -4266,5 +4406,5 @@ ...@@ -4266,5 +4406,5 @@
}); });
}); });
}(document, renderJS, QUnit, sinon, URI, URL)); }(document, renderJS, QUnit, sinon, URI, URL, Event));
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