Commit a4994f47 authored by Romain Courteaud's avatar Romain Courteaud

erp5_officejs: fix egraph gadget promise usage

Always check the promise result to catch error
parent d2751ee5
/*global window, rJS, RSVP, echarts, loopEventListener */ /*global window, rJS, RSVP, echarts, loopEventListener */
/*jslint nomen: true, indent: 2 */ /*jslint nomen: true, indent: 2, unparam: true */
(function (window, rJS, RSVP, echarts, loopEventListener) { (function (window, rJS, RSVP, echarts, loopEventListener) {
"use strict"; "use strict";
...@@ -143,6 +143,77 @@ ...@@ -143,6 +143,77 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// some methods // some methods
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
function promiseChartEventListener(chart, type) {
//////////////////////////
// Resolve the promise as soon as the event is triggered
// eventListener is removed when promise is cancelled/resolved/rejected
//////////////////////////
var handle_event_callback;
function canceller() {
chart.off(type, handle_event_callback);
}
function resolver(resolve) {
handle_event_callback = function (params) {
canceller();
resolve(params);
return false;
};
chart.on(type, handle_event_callback);
}
return new RSVP.Promise(resolver, canceller);
}
function loopChartEventListener(chart, type, callback) {
//////////////////////////
// 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) {
chart.off(type, handle_event_callback);
}
cancelResolver();
}
function itsANonResolvableTrap(resolve, reject) {
var result;
handle_event_callback = function handleEventCallback(params) {
cancelResolver();
try {
result = callback(params);
} catch (e) {
return reject(e);
}
callback_promise = new RSVP.Queue(result)
.push(undefined, function handleEventCallbackError(error) {
// Prevent rejecting the loop, if the result cancelled itself
if (!(error instanceof RSVP.CancellationError)) {
canceller();
reject(error);
}
});
};
chart.on(type, handle_event_callback);
}
return new RSVP.Promise(itsANonResolvableTrap, canceller);
}
gadget_klass gadget_klass
.declareAcquiredMethod("chartItemClick", "chartItemClick") .declareAcquiredMethod("chartItemClick", "chartItemClick")
...@@ -162,68 +233,63 @@ ...@@ -162,68 +233,63 @@
// declared methods // declared methods
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
.declareMethod("render", function (option_dict) { .declareMethod("render", function (option_dict) {
var gadget = this;
//delegate rendering to onStateChange to avoid redrawing the graph //delegate rendering to onStateChange to avoid redrawing the graph
//every time render is called (a form might call render every time //every time render is called (a form might call render every time
//some other fields needs update) //some other fields needs update)
gadget.changeState({ value: option_dict.value }); return this.changeState({
value: option_dict.value,
clickHandlerReady: false
});
}) })
.onStateChange(function (modification_dict) { .onStateChange(function (modification_dict) {
var gadget = this, var gadget = this,
graph_data_and_parameter,
chart; chart;
// the gadget is ready when both the graph is rendered and the click handler is attached. // the gadget is ready when both the graph is rendered and the click handler is attached.
if ( if (modification_dict.hasOwnProperty("clickHandlerReady")) {
modification_dict.hasOwnProperty("clickHandlerReady") || if (gadget.state.clickHandlerReady) {
modification_dict.hasOwnProperty("chartRendered")
) {
if (gadget.state.clickHandlerReady && gadget.state.chartRendered) {
gadget.element.querySelector(".graph-content").removeAttribute("disabled"); gadget.element.querySelector(".graph-content").removeAttribute("disabled");
} else { } else {
gadget.element.querySelector(".graph-content").setAttribute("disabled"); gadget.element.querySelector(".graph-content").setAttribute("disabled", "disabled");
} }
} }
if (modification_dict.hasOwnProperty("value")) { if (modification_dict.hasOwnProperty("value")) {
chart = echarts.getInstanceByDom( chart = echarts.init(
gadget.element.querySelector(".graph-content") gadget.element.querySelector(".graph-content")
); );
graph_data_and_parameter = getGraphDataAndParameterFromConfiguration(
return new RSVP.Queue(RSVP.all([
promiseChartEventListener(chart, 'finished'),
chart.setOption(getGraphDataAndParameterFromConfiguration(
modification_dict.value modification_dict.value
); ))
chart.on("finished", function onFinished() { ]))
gadget.changeState({ chartRendered: true }); .push(function () {
chart.off("finish", onFinished); gadget.listenToWindowResize(chart);
gadget.listenToClickEventOnTheChart(chart);
}); });
chart.setOption(graph_data_and_parameter);
gadget.changeState({ chartRendered: false });
this.listenToClickEventOnTheChart(chart);
} }
}) })
.declareService(function () { .declareJob("listenToWindowResize", function (chart) {
var gadget = this,
chart = echarts.init(gadget.element.querySelector(".graph-content"));
return loopEventListener( return loopEventListener(
window, window,
"resize", "resize",
{ passive: true }, { passive: true },
function () { function () {
chart.resize(); return chart.resize();
}, },
false false
); );
}) })
.declareJob("listenToClickEventOnTheChart", function (chart) { .declareJob("listenToClickEventOnTheChart", function (chart) {
var gadget = this, var gadget = this;
defer = RSVP.defer(); return RSVP.all([
// XXX https://lab.nexedi.com/nexedi/renderjs/blob/master/renderjs.js#L25 loopChartEventListener(chart, "click", function (params) {
chart.on("click", function (params) { return gadget.chartItemClick([params.name, params.seriesName]);
return gadget }),
.chartItemClick([params.name, params.seriesName]) gadget.changeState({clickHandlerReady: true})
.push(undefined, defer.reject); ]);
});
gadget.changeState({ clickHandlerReady: true });
return defer.promise;
}); });
}(window, rJS, RSVP, echarts, loopEventListener)); }(window, rJS, RSVP, echarts, loopEventListener));
...@@ -160,11 +160,13 @@ ...@@ -160,11 +160,13 @@
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
<pickle> <pickle>
<tuple> <dictionary>
<none/> <item>
<key> <string>_log</string> </key>
<value>
<list> <list>
<dictionary> <dictionary>
<item> <item>
...@@ -208,16 +210,20 @@ ...@@ -208,16 +210,20 @@
</item> </item>
</dictionary> </dictionary>
</list> </list>
</tuple> </value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="4" aka="AAAAAAAAAAQ=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
<pickle> <pickle>
<tuple> <dictionary>
<none/> <item>
<key> <string>_log</string> </key>
<value>
<list> <list>
<dictionary> <dictionary>
<item> <item>
...@@ -226,7 +232,7 @@ ...@@ -226,7 +232,7 @@
</item> </item>
<item> <item>
<key> <string>actor</string> </key> <key> <string>actor</string> </key>
<value> <string>ERP5TypeTestCase</string> </value> <value> <string>zope</string> </value>
</item> </item>
<item> <item>
<key> <string>comment</string> </key> <key> <string>comment</string> </key>
...@@ -240,7 +246,7 @@ ...@@ -240,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>970.25488.14039.8704</string> </value> <value> <string>983.46019.14276.42427</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -258,8 +264,8 @@ ...@@ -258,8 +264,8 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1538645846.68</float> <float>1588756120.87</float>
<string>GMT+9</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
</object> </object>
...@@ -267,16 +273,20 @@ ...@@ -267,16 +273,20 @@
</item> </item>
</dictionary> </dictionary>
</list> </list>
</tuple> </value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
<record id="5" aka="AAAAAAAAAAU="> <record id="5" aka="AAAAAAAAAAU=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
<pickle> <pickle>
<tuple> <dictionary>
<none/> <item>
<key> <string>_log</string> </key>
<value>
<list> <list>
<dictionary> <dictionary>
<item> <item>
...@@ -324,7 +334,9 @@ ...@@ -324,7 +334,9 @@
</item> </item>
</dictionary> </dictionary>
</list> </list>
</tuple> </value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
</ZopeData> </ZopeData>
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