From c9402a2f553b760efa2fa691bbe0917cd71a5a4d Mon Sep 17 00:00:00 2001 From: Romain Courteaud <romain@nexedi.com> Date: Thu, 20 Oct 2016 15:27:24 +0000 Subject: [PATCH] [erp5_web_renderjs_ui] Listbox: Reduce number of DOM modification Try to reduce possible errors when 2 functions tries to update the listbox DOM --- .../rjs_gadget_erp5_listbox_html.html | 2 - .../rjs_gadget_erp5_listbox_html.xml | 4 +- .../rjs_gadget_erp5_listbox_js.js | 471 +++++++++--------- .../rjs_gadget_erp5_listbox_js.xml | 4 +- 4 files changed, 247 insertions(+), 234 deletions(-) diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html index 7fd716b1f7..9c8356cad4 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html @@ -10,8 +10,6 @@ <script src="renderjs.js" type="text/javascript"></script> <script src="jiodev.js" type="text/javascript"></script> <script src="handlebars.js" type="text/javascript"></script> - - <!-- custom script --> <script src="gadget_erp5_field_listbox.js" type="text/javascript"></script> diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml index 9f166a3bfa..0ab97364b2 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml @@ -234,7 +234,7 @@ </item> <item> <key> <string>serial</string> </key> - <value> <string>954.45675.44850.53452</string> </value> + <value> <string>954.47421.47694.22459</string> </value> </item> <item> <key> <string>state</string> </key> @@ -252,7 +252,7 @@ </tuple> <state> <tuple> - <float>1476956055.1</float> + <float>1476967547.86</float> <string>UTC</string> </tuple> </state> diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js index 3154609ce3..627dfa7ed2 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js @@ -39,21 +39,15 @@ error_message_template = Handlebars.compile(error_message_source); - function renderListboxThead(gadget, template) { - if (template === undefined) { - template = listbox_hidden_thead_template; - } - return gadget.translateHtml(template( - { - "head_value": gadget.props.head_value, - "show_anchor": gadget.props.field_json.show_anchor, - "line_icon": gadget.props.field_json.line_icon - } - )); + function renderListboxThead(gadget, template, head_value) { + return gadget.translateHtml(template({ + head_value: gadget.props.head_value, + show_anchor: gadget.state.show_anchor, + line_icon: gadget.state.line_icon + })); } - function renderEditableField(gadget, element) { var i, promise_list = [], @@ -67,7 +61,7 @@ function renderSubCell(element, sub_field_json) { var options = {}, queue; - sub_field_json.editable = sub_field_json.editable && gadget.props.field_json.editable; // XXX + sub_field_json.editable = sub_field_json.editable && gadget.state.editable; // XXX queue = gadget.getFieldTypeGadgetUrl(sub_field_json.type); queue .push(function (gadget_url) { @@ -120,22 +114,20 @@ } } promise_list.push(renderSubCell(element_list[i], - gadget.props.result.data.rows[line].value[gadget.props.field_json.column_list[column][0]] || "")); + gadget.props.result.data.rows[line].value[gadget.state.column_list[column][0]] || "")); } return RSVP.all(promise_list); } + function renderListboxTbody(gadget, template) { var tmp; - if (template === undefined) { - template = listbox_hidden_tbody_template; - } return gadget.translateHtml(template( { "body_value": gadget.props.body_value, - "show_anchor": gadget.props.field_json.show_anchor, - "column_list": gadget.props.field_json.column_list + "show_anchor": gadget.state.show_anchor, + "column_list": gadget.state.column_list } )) .push(function (my_html) { @@ -144,13 +136,14 @@ return renderEditableField(gadget, tmp); }) .push(function () { - var table = gadget.props.element.querySelector("table"), + var table = gadget.element.querySelector("table"), tbody = table.querySelector("tbody"); table.removeChild(tbody); table.appendChild(tmp); }); } + function renderListboxTfoot(gadget) { return gadget.translateHtml(listbox_tfoot_template( { @@ -164,55 +157,18 @@ )); } - - function renderListbox(gadget) { - return gadget.translateHtml(listbox_template( - { - "hide_class": gadget.props.hide_class, - "hide_sort": gadget.props.hide_sort, - "title": gadget.props.field_json.title - } - )); - } - - - function renderErrorMessage(gadget) { - var options = {}; - options.extended_search = undefined; - options[gadget.props.field_json.key + "_sort_list:json"] = undefined; - return gadget.getUrlFor({ - command: 'store_and_change', - options: options - }) - .push(function (url) { - return gadget.translateHtml(error_message_template( - { - 'reset_url' : url - } - )); - }); - } - rJS(window) ///////////////////////////////////////////////////////////////// // ready ///////////////////////////////////////////////////////////////// // Init local properties - .ready(function (g) { - g.props = { + .ready(function () { + this.props = { cell_gadget_list: [], listbox_uid_dict: {} }; }) - // Assign the element to a variable - .ready(function (g) { - return g.getElement() - .push(function (element) { - g.props.element = element; - }); - }) - ////////////////////////////////////////////// // acquired method ////////////////////////////////////////////// @@ -224,28 +180,20 @@ .declareAcquiredMethod("renderEditorPanel", "renderEditorPanel") .declareAcquiredMethod("redirect", "redirect") .declareAcquiredMethod("translate", "translate") + ////////////////////////////////////////////// // initialize the gadget content ////////////////////////////////////////////// .declareMethod('render', function (options) { var gadget = this, field_json = options.field_json, - head_value = [], - class_value, - tmp, i, - j; - - gadget.props.field_json = field_json; - gadget.props.field_id = options.field_id; - gadget.props.extended_search = options.extended_search; - gadget.props.hide_class = options.hide_enabled ? "" : "ui-disabled"; - gadget.props.sort_list = []; - gadget.props.command = field_json.command || 'index'; + sort_column_list = [], + search_column_list = []; //only display which is in listbox's column list if (field_json.sort_column_list.length) { - field_json.sort_column_list = field_json.sort_column_list.filter(function (n) { + sort_column_list = field_json.sort_column_list.filter(function (n) { for (i = 0; i < field_json.column_list.length; i += 1) { if (field_json.column_list[i][0] === n[0] && field_json.column_list[i][1] === n[1]) { return true; @@ -254,10 +202,9 @@ return false; }); } - gadget.props.hide_sort = field_json.sort_column_list.length ? "" : "ui-disabled"; if (field_json.search_column_list.length) { - field_json.search_column_list = field_json.search_column_list.filter(function (n) { + search_column_list = field_json.search_column_list.filter(function (n) { for (i = 0; i < field_json.column_list.length; i += 1) { if (field_json.column_list[i][0] === n[0] && field_json.column_list[i][1] === n[1]) { return true; @@ -266,62 +213,107 @@ return false; }); } - field_json.search_column_list.push(["searchable_text", "Searchable Text"]); + search_column_list.push(["searchable_text", "Searchable Text"]); - // Cancel previous line rendering to not conflict with the asynchronous render for now - gadget.renderContent(true); - return new RSVP.Queue() + return RSVP.Queue() .push(function () { - return renderListbox(gadget); + // Cancel previous line rendering to not conflict with the asynchronous render for now + return gadget.renderContent(true); }) - .push(function (my_html) { - gadget.props.element.querySelector(".document_table").innerHTML = my_html; + .push(function () { // XXX Fix in case of multiple listboxes return RSVP.all([ gadget.getUrlParameter(field_json.key + '_begin_from'), gadget.getUrlParameter(field_json.key + '_sort_list:json') ]); }) - .push(function (all_result) { - var result = all_result[0]; - gadget.props.sort_list = all_result[1] || []; - if (result === undefined) { - result = '0'; - } - for (i = 0; i < gadget.props.field_json.column_list.length; i += 1) { - class_value = ""; - for (j = 0; j < gadget.props.sort_list.length; j += 1) { - tmp = gadget.props.sort_list[j]; - if (tmp[0] === gadget.props.field_json.column_list[i][0]) { - if (tmp[1] === "ascending") { - class_value = "ui-icon ui-icon-arrow-up"; - } else { - class_value = "ui-icon ui-icon-arrow-down"; - } - break; - } + .push(function (result_list) { + return gadget.changeState({ + key: field_json.key, + title: field_json.title, + editable: field_json.editable, + + begin_from: parseInt(result_list[0] || '0', 10) || 0, + sort_list: result_list[1] || [], + + show_anchor: field_json.show_anchor, + line_icon: field_json.line_icon, + query: field_json.query, + lines: field_json.lines, + list_method: field_json.list_method, + list_method_template: field_json.list_method_template, + + column_list: field_json.column_list, + sort_column_list: sort_column_list, + search_column_list: search_column_list, + hide_sort: field_json.sort_column_list.length ? "" : "ui-disabled", + + field_id: options.field_id, + extended_search: options.extended_search, + hide_class: options.hide_enabled ? "" : "ui-disabled", + command: field_json.command || 'index' + }); + }) + .push(function () { + // Force line calculation in any case + return gadget.renderContent(); + }); + }) + + .onStateChange(function () { + var gadget = this, + head_value = [], + class_value, + tmp, + i, + j; + + for (i = 0; i < gadget.state.column_list.length; i += 1) { + class_value = ""; + for (j = 0; j < gadget.state.sort_list.length; j += 1) { + tmp = gadget.state.sort_list[j]; + if (tmp[0] === gadget.state.column_list[i][0]) { + if (tmp[1] === "ascending") { + class_value = "ui-icon ui-icon-arrow-up"; + } else { + class_value = "ui-icon ui-icon-arrow-down"; } - head_value.push({ - "data-i18n": field_json.column_list[i][1], - "class_value": class_value, - "text": field_json.column_list[i][1] - }); + break; } - gadget.props.head_value = head_value; - gadget.props.begin_from = parseInt(result, 10) || 0; - return renderListboxThead(gadget); + } + head_value.push({ + "data-i18n": gadget.state.column_list[i][1], + "class_value": class_value, + "text": gadget.state.column_list[i][1] + }); + } + + gadget.props.head_value = head_value; + return new RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.translateHtml(listbox_template({ + hide_class: gadget.state.hide_class, + hide_sort: gadget.state.hide_sort, + title: gadget.state.title + })), + renderListboxThead(gadget, listbox_hidden_thead_template) + ]); }) - .push(function (my_html) { - gadget.props.element.querySelector(".thead").innerHTML = my_html; - gadget.renderContent(); + .push(function (result_list) { + gadget.element.querySelector(".document_table").innerHTML = result_list[0]; + gadget.element.querySelector(".thead").innerHTML = result_list[1]; }); }) + .declareMethod('getListboxInfo', function () { //XXXXX search column list is used for search editor to //construct search panel //hardcoded begin_from key to define search position - return { "search_column_list": this.props.field_json.search_column_list, - "begin_from": this.props.field_json.key + "_begin_from"}; + return { + search_column_list: this.state.search_column_list, + begin_from: this.state.key + "_begin_from" + }; }) ////////////////////////////////////////////// @@ -329,31 +321,32 @@ ////////////////////////////////////////////// .declareJob('renderContent', function (only_cancel) { var gadget = this, - props = gadget.props, - field_json = props.field_json, - begin_from = props.begin_from, - url_query = props.extended_search, - query_string = new URI(field_json.query).query(true).query, - lines = field_json.lines, +// props = gadget.props, +// field_json = props.field_json, + begin_from = this.state.begin_from, + url_query = this.state.extended_search, + query_string, + lines = this.state.lines, select_list = [], dataset, counter, limit_options, - queue, i; if (only_cancel) { return; } - if (field_json.query === undefined) { - gadget.props.element.querySelector('tfoot').textContent = "Unsupported list method: '" + field_json.list_method + "'"; + if (this.state.query === undefined) { + gadget.element.querySelector('tfoot').textContent = + "Unsupported list method: '" + this.state.list_method + "'"; return; } // function buildQueryString(previous, next) { // return previous + next[0] + ':= "' + url_query + '" OR '; // } + query_string = new URI(this.state.query).query(true).query; if (url_query) { //query_string = field_json.column_list.reduce(buildQueryString, ' AND (').replace(new RegExp("OR " + '$'), ')'); if (query_string) { @@ -363,34 +356,26 @@ } } - for (i = 0; i < field_json.column_list.length; i += 1) { - select_list.push(field_json.column_list[i][0]); + for (i = 0; i < this.state.column_list.length; i += 1) { + select_list.push(this.state.column_list[i][0]); } select_list.push("uid"); + if (lines === 0) { limit_options = undefined; } else { limit_options = [begin_from, lines + 1]; } - queue = gadget.jio_allDocs({ + + return gadget.jio_allDocs({ // XXX Not jIO compatible, but until a better api is found... - "list_method_template": field_json.list_method_template, + "list_method_template": this.state.list_method_template, "query": query_string, "limit": limit_options, "select_list": select_list, - "sort_on": gadget.props.sort_list - }); - queue - .push(undefined, function (error) { - //XXXXX hack to not crash interface - //this will catch all error, not only search criteria invalid error - console.warn(error); - return renderErrorMessage(gadget) - .push(function (error_html) { - gadget.props.element.querySelector(".document_table").innerHTML = error_html; - queue.cancel(); - }); - }) + "sort_on": gadget.state.sort_list + }) + .push(function (result) { var promise_list = [result]; if (lines === 0) { @@ -402,103 +387,132 @@ for (i = 0; i < counter; i += 1) { promise_list.push( gadget.getUrlFor({ - command: gadget.props.command, + command: gadget.state.command, options: { jio_key: result.data.rows[i].id, uid: result.data.rows[i].value.uid, selection_index: begin_from + i, query: query_string, - list_method_template: field_json.list_method_template, - "sort_list:json": gadget.props.sort_list + list_method_template: gadget.state.list_method_template, + "sort_list:json": gadget.state.sort_list } }) ); } - return RSVP.all(promise_list); - - }).push(function (result_list) { - var j, - result = result_list[0], - value, - body_value = [], - tr_value = [], - tmp_url; - dataset = result; - for (i = 0; i < counter; i += 1) { - tmp_url = result_list[i + 1]; - tr_value = []; - for (j = 0; j < field_json.column_list.length; j += 1) { - value = result.data.rows[i].value[field_json.column_list[j][0]] || ""; - tr_value.push({ - "type": value.type, - "editable": value.editable && field_json.editable, - "href": tmp_url, - "text": value, - "line": i, - "column": j - }); - } - body_value.push({ - "value": result.data.rows[i].value.uid, - "jump": tmp_url, - "tr_value": tr_value, - "line_icon": field_json.line_icon + return new RSVP.Queue() + .push(function () { + return RSVP.all(promise_list); + }) + .push(function (result_list) { + var j, + allDocs_result = result_list[0], + value, + body_value = [], + tr_value = [], + tmp_url; + dataset = allDocs_result; + for (i = 0; i < counter; i += 1) { + tmp_url = result_list[i + 1]; + tr_value = []; + for (j = 0; j < gadget.state.column_list.length; j += 1) { + value = allDocs_result.data.rows[i].value[gadget.state.column_list[j][0]] || ""; + tr_value.push({ + "type": value.type, + "editable": value.editable && gadget.state.editable, + "href": tmp_url, + "text": value, + "line": i, + "column": j + }); + } + body_value.push({ + "value": allDocs_result.data.rows[i].value.uid, + "jump": tmp_url, + "tr_value": tr_value, + "line_icon": gadget.state.line_icon + }); + } + gadget.props.body_value = body_value; + gadget.props.result = result; + return renderListboxTbody(gadget, listbox_hidden_tbody_template); + }) + .push(function () { + var prev_param = {}, + next_param = {}; + function setNext() { + if (dataset.data.rows.length > lines) { + next_param[gadget.state.key + '_begin_from'] = begin_from + lines; + } + } + + if (begin_from === 0) { + setNext(); + } else { + prev_param[gadget.state.key + '_begin_from'] = begin_from - lines; + setNext(); + } + return RSVP.all([ + gadget.getUrlFor({command: 'change', options: prev_param}), + gadget.getUrlFor({command: 'change', options: next_param}) + ]); + + }) + .push(function (url_list) { + var foot = {}; + foot.colspan = gadget.state.column_list.length + gadget.state.show_anchor + + (gadget.state.line_icon ? 1 : 0); + foot.default_colspan = foot.colspan; + foot.previous_classname = "ui-btn ui-icon-carat-l ui-btn-icon-left responsive ui-first-child"; + foot.previous_url = url_list[0]; + foot.next_classname = "ui-btn ui-icon-carat-r ui-btn-icon-right responsive ui-last-child"; + foot.next_url = url_list[1]; + if ((begin_from === 0) && (counter === 0)) { + foot.record = "No records"; + } else if ((dataset.data.rows.length <= lines) && (begin_from === 0)) { + foot.record = counter + " Records"; + } else { + foot.record = "Records " + (((begin_from + lines) / lines - 1) * lines + 1) + " - " + (((begin_from + lines) / lines - 1) * lines + counter); + } + + if (begin_from === 0) { + foot.previous_classname += " ui-disabled"; + } + if (dataset.data.rows.length <= lines) { + foot.next_classname += " ui-disabled"; + } + gadget.props.foot = foot; + return renderListboxTfoot(gadget); + }) + .push(function (my_html) { + gadget.element.querySelector(".tfoot").innerHTML = my_html; }); - } - gadget.props.body_value = body_value; - gadget.props.result = result; - return renderListboxTbody(gadget); - }).push(function () { - var prev_param = {}, - next_param = {}; - function setNext() { - if (dataset.data.rows.length > lines) { - next_param[gadget.props.field_json.key + '_begin_from'] = begin_from + lines; - } - } - if (begin_from === 0) { - setNext(); - } else { - prev_param[gadget.props.field_json.key + '_begin_from'] = begin_from - lines; - setNext(); - } - return RSVP.all([ - gadget.getUrlFor({command: 'change', options: prev_param}), - gadget.getUrlFor({command: 'change', options: next_param}) - ]); - }).push(function (url_list) { - var foot = {}; - foot.colspan = field_json.column_list.length + field_json.show_anchor + - (field_json.line_icon ? 1 : 0); - foot.default_colspan = foot.colspan; - foot.previous_classname = "ui-btn ui-icon-carat-l ui-btn-icon-left responsive ui-first-child"; - foot.previous_url = url_list[0]; - foot.next_classname = "ui-btn ui-icon-carat-r ui-btn-icon-right responsive ui-last-child"; - foot.next_url = url_list[1]; - if ((begin_from === 0) && (counter === 0)) { - foot.record = "No records"; - } else if ((dataset.data.rows.length <= lines) && (begin_from === 0)) { - foot.record = counter + " Records"; - } else { - foot.record = "Records " + (((begin_from + lines) / lines - 1) * lines + 1) + " - " + (((begin_from + lines) / lines - 1) * lines + counter); + }, function (error) { + if (error instanceof RSVP.CancellationError) { + throw error; } - if (begin_from === 0) { - foot.previous_classname += " ui-disabled"; - } - if (dataset.data.rows.length <= lines) { - foot.next_classname += " ui-disabled"; - } - gadget.props.foot = foot; - return renderListboxTfoot(gadget); - }).push(function (my_html) { - gadget.props.element.querySelector(".tfoot").innerHTML = my_html; + // do not crash interface if allDocs fails + //this will catch all error, not only search criteria invalid error + console.warn(error); + var options = {extended_search: undefined}; + options[gadget.state.key + "_sort_list:json"] = undefined; + return gadget.getUrlFor({ + command: 'store_and_change', + options: options + }) + .push(function (url) { + return gadget.translateHtml(error_message_template({ + reset_url: url + })); + }) + .push(function (html) { + gadget.element.querySelector(".document_table").innerHTML = html; + }); }); - return queue; - }) + }) .declareMethod("getContent", function (options) { var form_gadget = this, @@ -532,18 +546,19 @@ return data; }); }) + .onEvent('click', function (evt) { var gadget = this, - sort_button = gadget.props.element.querySelector('button[name="Sort"]'), - hide_button = gadget.props.element.querySelector('button[name="Hide"]'), + sort_button = gadget.element.querySelector('button[name="Sort"]'), + hide_button = gadget.element.querySelector('button[name="Hide"]'), url, options = {}; if (evt.target === sort_button) { evt.preventDefault(); url = "gadget_erp5_sort_editor.html"; - options.sort_column_list = gadget.props.field_json.sort_column_list; - options.sort_list = gadget.props.sort_list; - options.key = gadget.props.field_json.key + "_sort_list:json"; + options.sort_column_list = gadget.state.sort_column_list; + options.sort_list = gadget.state.sort_list; + options.key = gadget.state.key + "_sort_list:json"; return gadget.renderEditorPanel(url, options); } if (evt.target === hide_button) { @@ -566,7 +581,7 @@ } else { //hide closed //maybe submit - all_hide_elements = gadget.props.element.querySelectorAll(".hide_element"); + all_hide_elements = gadget.element.querySelectorAll(".hide_element"); for (i = 0; i < all_hide_elements.length; i += 1) { if (!all_hide_elements[i].checked) { hide_elements.push(all_hide_elements[i]); @@ -581,8 +596,8 @@ value: hide_elements[i].getAttribute("value") })); } - if (gadget.props.extended_search) { - search_query = QueryFactory.create(gadget.props.extended_search); + if (gadget.state.extended_search) { + search_query = QueryFactory.create(gadget.state.extended_search); } if (search_query) { query_list.push(search_query); @@ -618,8 +633,8 @@ .push(function (all_innerHTML) { //change hide button's text hide_button.innerHTML = all_innerHTML[3]; - gadget.props.element.querySelector(".thead").innerHTML = all_innerHTML[0]; - gadget.props.element.querySelector(".tfoot").innerHTML = all_innerHTML[2]; + gadget.element.querySelector(".thead").innerHTML = all_innerHTML[0]; + gadget.element.querySelector(".tfoot").innerHTML = all_innerHTML[2]; }); }); } diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml index bb13dcc0ca..ea2ef2dd19 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml @@ -236,7 +236,7 @@ </item> <item> <key> <string>serial</string> </key> - <value> <string>954.46086.29232.63761</string> </value> + <value> <string>954.47559.38051.59921</string> </value> </item> <item> <key> <string>state</string> </key> @@ -254,7 +254,7 @@ </tuple> <state> <tuple> - <float>1476887535.66</float> + <float>1476976330.15</float> <string>UTC</string> </tuple> </state> -- 2.30.9