Commit b54b55dd authored by Romain Courteaud's avatar Romain Courteaud

[erp5_xhtml_style] Do not crash the UI in case of gadget error

parent 48b1447b
/*global window, rJS, RSVP, document*/ /*global window, rJS, RSVP, document, console*/
/*jslint nomen: true, maxlen:80, indent:2*/ /*jslint nomen: true, maxlen:80, indent:2*/
(function (window, document, rJS, RSVP) { (function (window, rJS, RSVP, document, console) {
"use strict"; "use strict";
function promiseEventListener(target, type, useCapture) { function promiseEventListener(target, type, useCapture) {
////////////////////////// //////////////////////////
// Resolve the promise as soon as the event is triggered // Resolve the promise as soon as the event is triggered
...@@ -27,109 +28,124 @@ ...@@ -27,109 +28,124 @@
return new RSVP.Promise(resolver, canceller); return new RSVP.Promise(resolver, canceller);
} }
function displayFieldError(error) {
console.warn(error);
// Display the error message in the portal_status location
// As renderJS does not report which element is failing while loading
// a gadget
var error_element = document.getElementById('transition_message');
error_element.textContent = error + '. ' + error_element.textContent;
}
function getGadgetContent(gadget) {
return gadget.getContent()
.push(undefined, function (error) {
// Do not crash if gadget getContent is wrongly implemented,
// ie, UI should work even if one gadget does not
displayFieldError(error);
return {};
});
}
rJS(window) rJS(window)
///////////////////////////////////////////////////////////////// .setState({
// ready rejected_dict: {},
///////////////////////////////////////////////////////////////// field_list: [],
// Init local properties gadget_list: []
.ready(function (g) {
g.props = {};
}) })
// Assign the element to a variable .allowPublicAcquisition('reportGadgetDeclarationError',
.ready(function (g) { function (argument_list, scope) {
return g.getElement() // Do not crash the UI in case of wrongly configured gadget,
.push(function (element) { // bad network, loading bug.
g.props.element = element; this.state.rejected_dict[scope] = null;
}); return displayFieldError(argument_list[0]);
})
.allowPublicAcquisition('reportServiceError',
function (argument_list) {
// Do not crash the UI in case of gadget service error.
return displayFieldError(argument_list[0]);
}) })
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// declared methods // declared methods
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
.declareService(function () { .declareService(function () {
var g = this, // Call render on all gadget fields
i, var gadget = this,
list_gadget = document.querySelectorAll("[data-gadget-url]"), field_list = [],
all_gadget, i;
list = [],
gadget_attributes = [],
url,
form = g.props.element.querySelector("form"),
scope,
value,
key,
tmp;
for (i = 0; i < list_gadget.length; i += 1) {
url = list_gadget[i].getAttribute("data-gadget-url");
key = list_gadget[i].getAttribute("data-gadget-editable");
value = list_gadget[i].getAttribute("data-gadget-value");
//renderable
if (url !== undefined && url !== null) {
tmp = {};
scope = list_gadget[i].getAttribute("data-gadget-scope");
list.push(g.getDeclaredGadget(scope));
tmp.sandbox = list_gadget[i].getAttribute("data-gadget-sandbox");
tmp.editable = key;
tmp.key = key;
tmp.value = value;
gadget_attributes.push(tmp);
}
}
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return RSVP.all(list); var field_element_list =
}) gadget.element.querySelectorAll("[data-gadget-url]"),
.push(function (results) { field_element,
all_gadget = results; field_scope,
list = []; field_url,
for (i = 0; i < gadget_attributes.length; i += 1) { promise_list = [];
if (gadget_attributes[i].sandbox === "iframe") {
list.push(all_gadget[i].getElement()); for (i = 0; i < field_element_list.length; i += 1) {
field_element = field_element_list[i];
field_url = field_element.getAttribute("data-gadget-url");
field_scope = field_element.getAttribute("data-gadget-scope");
// Renderable
if ((field_url !== undefined) && (field_url !== null) &&
(field_scope !== null) &&
(!gadget.state.rejected_dict.hasOwnProperty(field_scope))) {
field_list.push({
sandbox: field_element.getAttribute("data-gadget-sandbox"),
editable: field_element.getAttribute("data-gadget-editable"),
key: field_element.getAttribute("data-gadget-editable"),
value: field_element.getAttribute("data-gadget-value")
});
promise_list.push(gadget.getDeclaredGadget(field_scope));
} }
} }
return RSVP.all(list); gadget.state.field_list = field_list;
return RSVP.all(promise_list);
}) })
.push(function (elements) { .push(function (result_list) {
gadget.state.gadget_list = result_list;
var iframe, var iframe,
j, sub_element,
sub_value, sub_value,
sub_key; sub_key,
list = []; promise_list = [];
for (i = 0, j = 0; i < gadget_attributes.length; i += 1) { for (i = 0; i < field_list.length; i += 1) {
if (all_gadget[i].render !== undefined) { if (result_list[i].render !== undefined) {
sub_value = gadget_attributes[i].value; sub_value = field_list[i].value;
sub_key = gadget_attributes[i].key; sub_key = field_list[i].key;
list.push( promise_list.push(
all_gadget[i].render( result_list[i].render({key: sub_key, value: sub_value})
{ .push(undefined, displayFieldError)
"key": sub_key, /* XXX Highlight the gadget element with a small colored
"value": sub_value
}
).push(undefined, function (error) {
/* TODO: Highlight the gadget element with a small colored
* error message. Clicking on the element could unroll * error message. Clicking on the element could unroll
* more information like the traceback. */ * more information like the traceback. */
console.log(error);
})
); );
} }
if (gadget_attributes[i].sandbox === "iframe") { if (field_list[i].sandbox === "iframe") {
iframe = elements[j].querySelector('iframe'); sub_element = result_list[i].element;
iframe = sub_element.querySelector('iframe');
//xxx input field //xxx input field
elements[j].parentNode.style.width = "100%"; sub_element.parentNode.style.width = "100%";
elements[j].parentNode.style.height = "100%"; sub_element.parentNode.style.height = "100%";
//xxx section div //xxx section div
elements[j].style.width = "100%"; sub_element.style.width = "100%";
elements[j].style.height = "100%"; sub_element.style.height = "100%";
iframe.style.width = "100%"; iframe.style.width = "100%";
iframe.style.height = "100%"; iframe.style.height = "100%";
iframe.allowFullscreen = true; iframe.allowFullscreen = true;
j += 1;
} }
} }
return RSVP.all(list); return RSVP.all(promise_list);
});
}) })
.push(function () {
.declareService(function () {
/*Do not use ajax call but submit an hidden form. /*Do not use ajax call but submit an hidden form.
So in this way, we can use form submit mecanisme So in this way, we can use form submit mecanisme
provided by browser. provided by browser.
...@@ -142,28 +158,37 @@ ...@@ -142,28 +158,37 @@
submit/image button. submit/image button.
After all, submit the form manually again. After all, submit the form manually again.
*/ */
var input_images =
g.props.element.querySelectorAll("input[type='image']"), var context = this,
input_submits = form = this.element.querySelector("form");
g.props.element.querySelectorAll("button[type='submit']");
list = []; return new RSVP.Queue()
if (input_images.length || input_submits.length) { .push(function () {
list.push(promiseEventListener(g.props.element, "submit", false)); var image_list = context.element
for (i = 0; i < input_images.length; i += 1) { .querySelectorAll("input[type='image']"),
list.push(promiseEventListener(input_images[i], "click", false)); submit_list = context.element
} .querySelectorAll("button[type='submit']"),
for (i = 0; i < input_submits.length; i += 1) { i,
list.push(promiseEventListener(input_submits[i], "click", false)); promise_list = [];
}
return RSVP.any(list); promise_list.push(promiseEventListener(context.element, "submit",
} false));
return promiseEventListener(g.props.element, "submit", false); for (i = 0; i < image_list.length; i += 1) {
promise_list.push(promiseEventListener(image_list[i], "click",
false));
}
for (i = 0; i < submit_list.length; i += 1) {
promise_list.push(promiseEventListener(submit_list[i], "click",
false));
}
return RSVP.any(promise_list);
}) })
.push(function (evt) { .push(function (evt) {
var input, var input,
hidden_button, hidden_button,
target; target,
list = []; i,
promise_list = [];
if (evt.type === "click") { if (evt.type === "click") {
input = document.createElement("input"); input = document.createElement("input");
input.setAttribute("type", "hidden"); input.setAttribute("type", "hidden");
...@@ -171,34 +196,34 @@ ...@@ -171,34 +196,34 @@
input.setAttribute("name", target.getAttribute("name")); input.setAttribute("name", target.getAttribute("name"));
form.appendChild(input); form.appendChild(input);
} else { } else {
hidden_button = g.props.element.querySelector(".hidden_button"); hidden_button = context.element.querySelector(".hidden_button");
hidden_button.setAttribute("type", "hidden"); hidden_button.setAttribute("type", "hidden");
} }
for (i = 0; i < all_gadget.length; i += 1) { for (i = 0; i < context.state.gadget_list.length; i += 1) {
if (all_gadget[i].getContent !== undefined && if (context.state.gadget_list[i].getContent !== undefined &&
gadget_attributes[i].editable !== null) { context.state.field_list[i].editable !== null) {
list.push(all_gadget[i].getContent()); promise_list.push(getGadgetContent(context.state.gadget_list[i]));
} }
} }
return RSVP.all(list); return RSVP.all(promise_list);
}) })
.push(function (all_content) { .push(function (content_list) {
var input, var input,
i,
name; name;
for (i = 0; i < all_content.length; i += 1) { for (i = 0; i < content_list.length; i += 1) {
for (name in all_content[i]) { for (name in content_list[i]) {
if (all_content[i].hasOwnProperty(name)) { if (content_list[i].hasOwnProperty(name)) {
input = document.createElement("input"); input = document.createElement("input");
input.setAttribute("type", "hidden"); input.setAttribute("type", "hidden");
input.setAttribute("name", name); input.setAttribute("name", name);
input.setAttribute("value", all_content[i][name]); input.setAttribute("value", content_list[i][name]);
form.appendChild(input); form.appendChild(input);
} }
} }
} }
}) return form.submit();
.push(function () {
form.submit();
}); });
}); });
}(window, document, rJS, RSVP));
\ No newline at end of file }(window, rJS, RSVP, document, console));
\ No newline at end of file
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