From 15d4b9dd53ca5b5eb782d9854f2f99e996a0e287 Mon Sep 17 00:00:00 2001
From: Tomas Peterka <tomas.peterka@nexedi.com>
Date: Mon, 20 Nov 2017 11:06:22 +0100
Subject: [PATCH] [renderjs_ui] Float Field respects formatting + test

-  Revert changes which led to lost of formatting.
-  Implement decimal precision for non-editable mode
-  Implement thousands separator
-  Add test for FloadField from original XHTML interface

/reviewed-on https://lab.nexedi.com/nexedi/erp5/merge_requests/500
---
 .../rjs_gadget_erp5_floatfield_js.js          |  42 ++++--
 .../rjs_gadget_erp5_floatfield_js.xml         |   4 +-
 .../renderjs_ui_float_field_zuite.xml         |  26 ++++
 .../testFloatField.xml                        |  58 +++++++++
 .../testFloatField.zpt                        |  53 ++++++++
 .../test.erp5.testFunctionalRJSFloatField.py  |  48 +++++++
 .../test.erp5.testFunctionalRJSFloatField.xml | 123 ++++++++++++++++++
 .../bt/template_path_list                     |   2 +
 .../bt/template_test_id_list                  |   1 +
 9 files changed, 347 insertions(+), 10 deletions(-)
 create mode 100644 bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite.xml
 create mode 100644 bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.xml
 create mode 100644 bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.zpt
 create mode 100644 bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.py
 create mode 100644 bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.xml

diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.js
index ca3699cd70..6239ff8375 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.js
@@ -3,12 +3,31 @@
 (function (window, rJS, Math) {
   "use strict";
 
+  var separator_re = /\d([\., \-_])?\d\d\d/,
+    input_format_re = /(-?)(\d+)(\.\d+)?/;
+
+  /** Slice any slice-able parameter into triplets **/
+  function toTriplets(sliceable) {
+    var parts = [],
+      i = sliceable.length;
+    for (i = sliceable.length; i > 3; i -= 3) {
+      parts.unshift(sliceable.slice(i - 3, i));
+    }
+    parts.unshift(sliceable.slice(0, i));
+    return parts;
+  }
+
   rJS(window)
+    .setState({
+      tag: 'p',  // important for CSS styles - noneditable element must be <p>
+      type: "number"
+    })
     .declareMethod('render', function (options) {
       var field_json = options.field_json || {},
-        percentage = (field_json.input_style || "").endsWith("%"),
+        input_style = (field_json.input_style || ""),
+        percentage = input_style.endsWith("%"),
+        thousand_sep = separator_re.test(input_style) ? (separator_re.exec(input_style)[1] || "") : "",
         state_dict = {
-          type: "number",
           editable: field_json.editable,
           required: field_json.required,
           hidden: field_json.hidden,
@@ -23,21 +42,28 @@
           step: "any",
           // `append` is a string to display next to the field ("%", "EUR"...)
           append: ''
-        };
-      if (!window.isNaN(state_dict.value)) {
-        state_dict.text_content = state_dict.value.toString();
-      }
+        },
+        tmp;
+
       if (!window.isNaN(state_dict.precision)) {
         state_dict.step = Math.pow(10, -state_dict.precision);
         state_dict.value = state_dict.value.toFixed(state_dict.precision);
       }
       if (percentage) {
-        // ERP5 always devides the value by 100 if it is set to pe percentages
+        // ERP5 always devides the value by 100 if it is set to percentages
         // thus we have to mitigate that in javascript here
         state_dict.value *= 100.0;
         state_dict.append = "%";
       }
-
+      if (!window.isNaN(state_dict.value)) {
+        state_dict.text_content = state_dict.value.toString();
+        if (state_dict.text_content !== "" && thousand_sep !== "") {
+          tmp = input_format_re.exec(state_dict.text_content);
+          // tmp == [full-number, sign, integer-part, .decimal-part, ...]
+          state_dict.text_content = tmp[1] + toTriplets(tmp[2]).join(thousand_sep) + tmp[3];
+          tmp = undefined;
+        }
+      }
       return this.changeState(state_dict);
     })
 
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.xml
index 9e831e95ef..9fe964333f 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_floatfield_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>962.14347.57208.52667</string> </value>
+                <value> <string>963.37747.27048.56217</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1507102119.32</float>
+                        <float>1511321647.29</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite.xml b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite.xml
new file mode 100644
index 0000000000..2460fefb02
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Zuite" module="Products.Zelenium.zuite"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_objects</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>renderjs_ui_float_field_zuite</string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>Float Field</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.xml b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.xml
new file mode 100644
index 0000000000..1d885b60b3
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>text/html</string> </value>
+        </item>
+        <item>
+            <key> <string>expand</string> </key>
+            <value> <int>0</int> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>testFloatField</string> </value>
+        </item>
+        <item>
+            <key> <string>output_encoding</string> </key>
+            <value> <string>utf-8</string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <unicode></unicode> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.zpt b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.zpt
new file mode 100644
index 0000000000..f35975a22a
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_float_field_zuite/testFloatField.zpt
@@ -0,0 +1,53 @@
+<html xmlns:tal="http://xml.zope.org/namespaces/tal"
+      xmlns:metal="http://xml.zope.org/namespaces/metal">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Test Float Value with Float Fields</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">Test basic functionality and decimal precision in both modes (non/editable)</td></tr>
+</thead><tbody>
+<tal:block metal:use-macro="here/PTZuite_CommonTemplate/macros/init" />
+
+<!-- Shortcut for full renderjs url -->
+<tr><td>store</td>
+    <td>${base_url}/web_site_module/renderjs_runner</td>
+    <td>renderjs_url</td></tr>
+<tr><td>open</td>
+    <td>${renderjs_url}/#/foo_module/1?editable=1</td><td></td></tr>
+<tr><td>waitForElementPresent</td>
+    <td>//input[@name="field_my_quantity"]</td><td></td></tr>
+
+<tr><td>assertText</td>
+    <td>//div[@data-gadget-scope="field_my_quantity_read_only"]//p</td>
+    <td>0.0</td></tr>
+<tr><td>assertValue</td>
+    <td>//input[@name="field_my_quantity"]</td>
+    <td>0.0</td></tr>
+
+<tr><td>type</td>
+    <td>field_my_quantity</td>
+    <td>1.00</td></tr>
+<tr><td>click</td>
+    <td>//div[@data-gadget-scope='header']//button[@data-i18n='Save']</td><td></td></tr>
+<tr><td>waitForElementPresent</td>
+    <td>//button[text()="Input data has errors."]</td><td></td></tr>
+<tr><td>waitForElementPresent</td>
+    <td>//div[@data-gadget-scope="field_my_quantity"]//span[text()='The number you input has too large precision.']</td><td></td></tr>
+<tr><td>type</td>
+    <td>field_my_quantity</td>
+    <td>1000000000000.0</td></tr>
+<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
+
+<tr><td>verifyValue</td>
+    <td>field_my_quantity</td>
+    <td>1000000000000.0</td></tr>
+<tr><td>verifyText</td>
+    <td>//div[@data-gadget-scope="field_my_quantity_read_only"]//p</td>
+    <td>1 000 000 000 000.0</td></tr>
+
+</tbody></table>
+</body>
+</html>
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.py b/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.py
new file mode 100644
index 0000000000..b4c7e7a9c9
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.py
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2011 Nexedi SARL and Contributors. All Rights Reserved.
+#                     Kazuhiko <kazuhiko@nexedi.com>
+#                     Rafael Monnerat <rafael@nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+import unittest
+
+from Products.ERP5Type.tests.ERP5TypeFunctionalTestCase import ERP5TypeFunctionalTestCase
+
+class TestRenderJSUIFloatField(ERP5TypeFunctionalTestCase):
+  foreground = 0
+  run_only = "renderjs_ui_float_field_zuite"
+
+  def getBusinessTemplateList(self):
+    return (
+      'erp5_web_renderjs_ui',
+      'erp5_web_renderjs_ui_test',
+      'erp5_ui_test_core',
+      'erp5_test_result',
+    )
+
+def test_suite():
+  suite = unittest.TestSuite()
+  suite.addTest(unittest.makeSuite(TestRenderJSUIFloatField))
+  return suite
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.xml b/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.xml
new file mode 100644
index 0000000000..f3b26d84ae
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalRJSFloatField.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Test Component" module="erp5.portal_type"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_recorded_property_dict</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+            </value>
+        </item>
+        <item>
+            <key> <string>default_reference</string> </key>
+            <value> <string>testFunctionalRJSFloatField</string> </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>test.erp5.testFunctionalRJSFloatField</string> </value>
+        </item>
+        <item>
+            <key> <string>portal_type</string> </key>
+            <value> <string>Test Component</string> </value>
+        </item>
+        <item>
+            <key> <string>sid</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_error_message</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_warning_message</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>version</string> </key>
+            <value> <string>erp5</string> </value>
+        </item>
+        <item>
+            <key> <string>workflow_history</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary/>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="3" aka="AAAAAAAAAAM=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>component_validation_workflow</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
+                    </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="4" aka="AAAAAAAAAAQ=">
+    <pickle>
+      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
+    </pickle>
+    <pickle>
+      <tuple>
+        <none/>
+        <list>
+          <dictionary>
+            <item>
+                <key> <string>action</string> </key>
+                <value> <string>validate</string> </value>
+            </item>
+            <item>
+                <key> <string>validation_state</string> </key>
+                <value> <string>validated</string> </value>
+            </item>
+          </dictionary>
+        </list>
+      </tuple>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui_test/bt/template_path_list b/bt5/erp5_web_renderjs_ui_test/bt/template_path_list
index 0d8cb39179..81af60c000 100644
--- a/bt5/erp5_web_renderjs_ui_test/bt/template_path_list
+++ b/bt5/erp5_web_renderjs_ui_test/bt/template_path_list
@@ -2,6 +2,8 @@ portal_tests/renderjs_ui_check_box_field_zuite
 portal_tests/renderjs_ui_check_box_field_zuite/**
 portal_tests/renderjs_ui_date_time_field_zuite
 portal_tests/renderjs_ui_date_time_field_zuite/**
+portal_tests/renderjs_ui_float_field_zuite
+portal_tests/renderjs_ui_float_field_zuite/**
 portal_tests/renderjs_ui_form_box_zuite
 portal_tests/renderjs_ui_form_box_zuite/**
 portal_tests/renderjs_ui_lines_field_zuite
diff --git a/bt5/erp5_web_renderjs_ui_test/bt/template_test_id_list b/bt5/erp5_web_renderjs_ui_test/bt/template_test_id_list
index 552d4d433a..8802bff85e 100644
--- a/bt5/erp5_web_renderjs_ui_test/bt/template_test_id_list
+++ b/bt5/erp5_web_renderjs_ui_test/bt/template_test_id_list
@@ -1,5 +1,6 @@
 test.erp5.testFunctionalRJSCore
 test.erp5.testFunctionalRJSCheckBoxField
+test.erp5.testFunctionalRJSFloatField
 test.erp5.testFunctionalRJSLinesField
 test.erp5.testFunctionalRJSListField
 test.erp5.testFunctionalRJSMultiCheckBoxField
-- 
2.30.9