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(
modification_dict.value
);
chart.on("finished", function onFinished() {
gadget.changeState({ chartRendered: true });
chart.off("finish", onFinished);
});
chart.setOption(graph_data_and_parameter);
gadget.changeState({ chartRendered: false });
this.listenToClickEventOnTheChart(chart); return new RSVP.Queue(RSVP.all([
promiseChartEventListener(chart, 'finished'),
chart.setOption(getGraphDataAndParameterFromConfiguration(
modification_dict.value
))
]))
.push(function () {
gadget.listenToWindowResize(chart);
gadget.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,171 +160,183 @@ ...@@ -160,171 +160,183 @@
</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>
<list> <key> <string>_log</string> </key>
<dictionary> <value>
<item> <list>
<key> <string>action</string> </key> <dictionary>
<value> <string>publish_alive</string> </value> <item>
</item> <key> <string>action</string> </key>
<item> <value> <string>publish_alive</string> </value>
<key> <string>actor</string> </key> </item>
<value> <string>zope</string> </value> <item>
</item> <key> <string>actor</string> </key>
<item> <value> <string>zope</string> </value>
<key> <string>comment</string> </key> </item>
<value> <string></string> </value> <item>
</item> <key> <string>comment</string> </key>
<item> <value> <string></string> </value>
<key> <string>error_message</string> </key> </item>
<value> <string></string> </value> <item>
</item> <key> <string>error_message</string> </key>
<item> <value> <string></string> </value>
<key> <string>time</string> </key> </item>
<value> <item>
<object> <key> <string>time</string> </key>
<klass> <value>
<global name="DateTime" module="DateTime.DateTime"/> <object>
</klass> <klass>
<tuple> <global name="DateTime" module="DateTime.DateTime"/>
<none/> </klass>
</tuple> <tuple>
<state> <none/>
<tuple> </tuple>
<float>1501592140.25</float> <state>
<string>UTC</string> <tuple>
</tuple> <float>1501592140.25</float>
</state> <string>UTC</string>
</object> </tuple>
</value> </state>
</item> </object>
<item> </value>
<key> <string>validation_state</string> </key> </item>
<value> <string>published_alive</string> </value> <item>
</item> <key> <string>validation_state</string> </key>
</dictionary> <value> <string>published_alive</string> </value>
</list> </item>
</tuple> </dictionary>
</list>
</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>
<list> <key> <string>_log</string> </key>
<dictionary> <value>
<item> <list>
<key> <string>action</string> </key> <dictionary>
<value> <string>edit</string> </value> <item>
</item> <key> <string>action</string> </key>
<item> <value> <string>edit</string> </value>
<key> <string>actor</string> </key> </item>
<value> <string>ERP5TypeTestCase</string> </value> <item>
</item> <key> <string>actor</string> </key>
<item> <value> <string>zope</string> </value>
<key> <string>comment</string> </key> </item>
<value> <item>
<none/> <key> <string>comment</string> </key>
</value> <value>
</item> <none/>
<item> </value>
<key> <string>error_message</string> </key> </item>
<value> <string></string> </value> <item>
</item> <key> <string>error_message</string> </key>
<item> <value> <string></string> </value>
<key> <string>serial</string> </key> </item>
<value> <string>970.25488.14039.8704</string> </value> <item>
</item> <key> <string>serial</string> </key>
<item> <value> <string>983.46019.14276.42427</string> </value>
<key> <string>state</string> </key> </item>
<value> <string>current</string> </value> <item>
</item> <key> <string>state</string> </key>
<item> <value> <string>current</string> </value>
<key> <string>time</string> </key> </item>
<value> <item>
<object> <key> <string>time</string> </key>
<klass> <value>
<global name="DateTime" module="DateTime.DateTime"/> <object>
</klass> <klass>
<tuple> <global name="DateTime" module="DateTime.DateTime"/>
<none/> </klass>
</tuple> <tuple>
<state> <none/>
<tuple> </tuple>
<float>1538645846.68</float> <state>
<string>GMT+9</string> <tuple>
</tuple> <float>1588756120.87</float>
</state> <string>UTC</string>
</object> </tuple>
</value> </state>
</item> </object>
</dictionary> </value>
</list> </item>
</tuple> </dictionary>
</list>
</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>
<list> <key> <string>_log</string> </key>
<dictionary> <value>
<item> <list>
<key> <string>action</string> </key> <dictionary>
<value> <string>detect_converted_file</string> </value> <item>
</item> <key> <string>action</string> </key>
<item> <value> <string>detect_converted_file</string> </value>
<key> <string>actor</string> </key> </item>
<value> <string>zope</string> </value> <item>
</item> <key> <string>actor</string> </key>
<item> <value> <string>zope</string> </value>
<key> <string>comment</string> </key> </item>
<value> <string></string> </value> <item>
</item> <key> <string>comment</string> </key>
<item> <value> <string></string> </value>
<key> <string>error_message</string> </key> </item>
<value> <string></string> </value> <item>
</item> <key> <string>error_message</string> </key>
<item> <value> <string></string> </value>
<key> <string>external_processing_state</string> </key> </item>
<value> <string>converted</string> </value> <item>
</item> <key> <string>external_processing_state</string> </key>
<item> <value> <string>converted</string> </value>
<key> <string>serial</string> </key> </item>
<value> <string>0.0.0.0</string> </value> <item>
</item> <key> <string>serial</string> </key>
<item> <value> <string>0.0.0.0</string> </value>
<key> <string>time</string> </key> </item>
<value> <item>
<object> <key> <string>time</string> </key>
<klass> <value>
<global name="DateTime" module="DateTime.DateTime"/> <object>
</klass> <klass>
<tuple> <global name="DateTime" module="DateTime.DateTime"/>
<none/> </klass>
</tuple> <tuple>
<state> <none/>
<tuple> </tuple>
<float>1501508426.52</float> <state>
<string>UTC</string> <tuple>
</tuple> <float>1501508426.52</float>
</state> <string>UTC</string>
</object> </tuple>
</value> </state>
</item> </object>
</dictionary> </value>
</list> </item>
</tuple> </dictionary>
</list>
</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