From d5d68cecfb9a6647267e70b9ac7a733a6f4eca1e Mon Sep 17 00:00:00 2001
From: Romain Courteaud <romain@nexedi.com>
Date: Tue, 18 Oct 2016 14:04:51 +0000
Subject: [PATCH] [erp5_web_renderjs_ui] Reimplement DateTimeField

---
 .../rjs_gadget_erp5_datetimefield_html.html   |   4 +-
 .../rjs_gadget_erp5_datetimefield_html.xml    |   8 +-
 .../rjs_gadget_erp5_datetimefield_js.js       | 520 ++++++++++--------
 .../rjs_gadget_erp5_datetimefield_js.xml      |   4 +-
 .../rjs_gadget_erp5_nojqm_css.css             |  12 +
 .../rjs_gadget_erp5_nojqm_css.xml             |   4 +-
 .../erp5_web_renderjs_ui/erp5css.less.txt     |  13 +
 7 files changed, 318 insertions(+), 247 deletions(-)

diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.html
index ba33bd1417..b95cb5b2e1 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.html
@@ -3,7 +3,7 @@
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
-    <title>ERP5 Floatfield</title>
+    <title>ERP5 Datetimefield</title>
 
     <!-- renderjs -->
     <script src="rsvp.js" type="text/javascript"></script>
@@ -13,6 +13,6 @@
 
   </head>
   <body>
-    <input type="date" />
+    <div class="datetimefield"></div>
   </body>
 </html>
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.xml
index 943cf7babd..9d24506e3c 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_html.xml
@@ -220,7 +220,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>romain</string> </value>
+                <value> <string>zope</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>940.50766.7916.31675</string> </value>
+                <value> <string>954.44229.8719.22835</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,8 +252,8 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1423235572.23</float>
-                        <string>GMT</string>
+                        <float>1476776016.7</float>
+                        <string>UTC</string>
                       </tuple>
                     </state>
                   </object>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.js
index 3ac39746ea..fe63f12057 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.js
@@ -1,22 +1,69 @@
-/*global window, rJS, RSVP, document, loopEventListener */
-/*jslint indent: 2 */
-(function (window, rJS, RSVP, document, loopEventListener) {
+/*global window, rJS, RSVP*/
+/*jslint indent: 2, maxlen: 80 */
+(function (window, rJS, RSVP) {
   "use strict";
+
+  var ZONE_LIST = [
+    ["GMT-12", "-1200"],
+    ["GMT-11", "-1100"],
+    ["GMT-10", "-1000"],
+    ["GMT-9", "-0900"],
+    ["GMT-8", "-0800"],
+    ["GMT-7", "-0700"],
+    ["GMT-6", "-0600"],
+    ["GMT-5", "-0500"],
+    ["GMT-4", "-0400"],
+    ["GMT-3", "-0300"],
+    ["GMT-2", "-0200"],
+    ["GMT-1", "-0100"],
+    ["GMT", "+0000"],
+    ["GMT+1", "+0100"],
+    ["GMT+2", "+0200"],
+    ["GMT+3", "+0300"],
+    ["GMT+4", "+0400"],
+    ["GMT+5", "+0500"],
+    ["GMT+6", "+0600"],
+    ["GMT+7", "+0700"],
+    ["GMT+8", "+0800"],
+    ["GMT+9", "+0900"],
+    ["GMT+10", "+1000"],
+    ["GMT+11", "+1100"],
+    ["GMT+12", "+1200"]
+  ];
+
   rJS(window)
-    .ready(function (gadget) {
-      return gadget.getElement()
-        .push(function (element) {
-          gadget.element = element;
-          gadget.props = {};
-        });
-    })
-    .declareAcquiredMethod("notifyInvalid", "notifyInvalid")
-    .declareAcquiredMethod("notifyValid", "notifyValid")
-    .declareMethod('getTextContent', function () {
-      return this.element.querySelector('input').getAttribute('value') || "";
-    })
+
     .declareMethod('render', function (options) {
-      var input = this.element.querySelector('input'),
+      var field_json = options.field_json || {},
+        state_dict = {
+          value: field_json.value || field_json.default || "",
+          editable: field_json.editable,
+          required: field_json.required,
+          name: field_json.key,
+          key: field_json.key,
+          title: field_json.title,
+          timezone_style: field_json.timezone_style,
+          date_only: field_json.date_only,
+          hide_day: field_json.hide_day,
+          allow_empty_time: field_json.allow_empty_time,
+          ampm_time_style: field_json.ampm_time_style,
+          subfield_ampm_key: field_json.subfield_ampm_key,
+          subfield_hour_key: field_json.subfield_hour_key,
+          subfield_minute_key: field_json.subfield_minute_key,
+          hidden_day_is_last_day: field_json.hidden_day_is_last_day,
+          subfield_year_key: field_json.subfield_year_key,
+          subfield_month_key: field_json.subfield_month_key,
+          subfield_day_key: field_json.subfield_day_key,
+          subfield_timezone_key: field_json.subfield_timezone_key,
+          start_datetime: field_json.start_datetime,
+          end_datetime: field_json.end_datetime
+        };
+      return this.changeState(state_dict);
+    })
+
+    .onStateChange(function (modification_dict) {
+      var element = this.element.querySelector('.datetimefield'),
+        gadget = this,
         date,
         tmp,
         timezone,
@@ -25,41 +72,85 @@
         tmp_date,
         tmp_hour,
         tmp_minute,
-        select,
+        leap_year,
         time = "",
-        leapyear,
-        i,
-        field_json = options.field_json || {},
-        lastDateOfMonth = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
-                           [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]],//leapyear
-        select_options = ["GMT-12", "GMT-11", "GMT-10", "GMT-9", "GMT-8", "GMT-7", "GMT-6",
-                   "GMT-5", "GMT-4", "GMT-3", "GMT-2", "GMT-1", "GMT", "GMT+1",
-                   "GMT+2", "GMT+3", "GMT+4", "GMT+5", "GMT+6", "GMT+7", "GMT+8",
-                   "GMT+9", "GMT+10", "GMT+11", "GMT+12"],
-        select_option,
-        value = field_json.value || field_json.default || "";
-      this.props.field_json = field_json;
+        last_month_date = [
+          [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+          [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+        ],//leapyear
+        queue = new RSVP.Queue(),
+        promise_list,
+        input_state = {
+          name: gadget.state.key + '_input',
+          editable: gadget.state.editable,
+          required: gadget.state.required,
+          type: gadget.state.date_only ? "date" : "datetime-local"
+        },
+        select_state = {
+          name: gadget.state.key + '_select',
+          value: "+0000",
+          item_list: ZONE_LIST,
+          editable: gadget.state.editable,
+          required: gadget.state.required
+              // name: field_json.key,
+              // title: field_json.title
+        },
+        p_state = {
+          tag: "p"
+        };
 
-
-      if (field_json.timezone_style) {
-        //change date to local
-        select = document.createElement("select");
-        for (i = 0; i < select_options.length; i += 1) {
-          select_option = document.createElement("option");
-          select_option.value = select_options[i];
-          select_option.innerHTML = select_options[i];
-          select.appendChild(select_option);
+      // Create or fetch sub gadgets
+      if (modification_dict.hasOwnProperty('editable') ||
+          modification_dict.hasOwnProperty('timezone_style')) {
+        if (gadget.state.editable) {
+          promise_list = [
+            gadget.declareGadget('gadget_html5_input.html', {scope: 'INPUT'})
+          ];
+          if (gadget.state.timezone_style) {
+            promise_list.push(gadget.declareGadget('gadget_html5_select.html',
+                                                   {scope: 'SELECT'}));
+          }
+        } else {
+          promise_list = [
+            gadget.declareGadget('gadget_html5_element.html', {scope: 'P'})
+          ];
         }
-        select.setAttribute("class", "gmt_select");
-        select.selectedIndex = 12;
-        this.element.appendChild(select);
-      }
-      if (field_json.date_only === 0) {
-        input.setAttribute("type", "datetime-local");
+        queue
+          .push(function () {
+            return RSVP.all(promise_list);
+          })
+          .push(function (result_list) {
+            // Clear first to DOM, append after to reduce flickering/manip
+            while (element.firstChild) {
+              element.removeChild(element.firstChild);
+            }
+            var i;
+            for (i = 0; i < result_list.length; i += 1) {
+              element.appendChild(result_list[i].element);
+            }
+            return result_list;
+          });
+      } else {
+        if (gadget.state.editable) {
+          promise_list = [
+            gadget.getDeclaredGadget('INPUT')
+          ];
+          if (gadget.state.timezone_style) {
+            promise_list.push(gadget.getDeclaredGadget('SELECT'));
+          }
+        } else {
+          promise_list = [gadget.getDeclaredGadget('P')];
+        }
+        queue
+          .push(function () {
+            return RSVP.all(promise_list);
+          });
       }
+
+      // Calculate sub gadget states
       //Change type to datetime/datetime local if configured in the field
-      if (value !== "") {
-        tmp = new Date(value);
+      if (gadget.state.value) {
+        tmp = new Date(gadget.state.value);
         //get date without timezone
         tmp_date = tmp.getUTCDate();
         tmp_month = tmp.getUTCMonth() + 1;
@@ -70,12 +161,13 @@
 
         //timezone required
         //convert time to GMT
-        timezone = parseInt(value.slice(-5), 10) / 100;
+        timezone = parseInt(gadget.state.value.slice(-5), 10) / 100;
 
-        if (field_json.timezone_style) {
-          select.selectedIndex = timezone + 12;
+        if (gadget.state.timezone_style) {
+          select_state.value = ZONE_LIST[timezone + 12][1];
         }
-        leapyear = (tmp_year % 4 === 0 && tmp_year % 100 !== 0) ? 1 : 0;
+
+        leap_year = (tmp_year % 4 === 0 && tmp_year % 100 !== 0) ? 1 : 0;
         if (timezone !== 0) {
           tmp_hour += timezone;
           if (tmp_hour < 0) {
@@ -87,12 +179,12 @@
                 tmp_month = 12;
                 tmp_year -= 1;
               }
-              tmp_date = lastDateOfMonth[leapyear][tmp_month - 1];
+              tmp_date = last_month_date[leap_year][tmp_month - 1];
             }
           } else if (tmp_hour > 23) {
             tmp_hour -= 24;
             tmp_date += 1;
-            if (tmp_date > lastDateOfMonth[leapyear][tmp_month - 1]) {
+            if (tmp_date > last_month_date[leap_year][tmp_month - 1]) {
               tmp_date = 1;
               tmp_month += 1;
               if (tmp_month > 12) {
@@ -102,208 +194,162 @@
             }
           }
         }
-        if (field_json.date_only === 0) {
-          time = "T" + Math.floor(tmp_hour / 10) + tmp_hour % 10 + ":"
-              + Math.floor(tmp_minute / 10) +  (tmp_minute % 10) + ":00";
+
+        if (!gadget.state.date_only) {
+          time = "T" + Math.floor(tmp_hour / 10) + tmp_hour % 10 + ":" +
+                 Math.floor(tmp_minute / 10) +  (tmp_minute % 10) + ":00";
         }
-        date = tmp_year + "-" + Math.floor(tmp_month / 10) + (tmp_month % 10) + "-"
-               +  Math.floor(tmp_date / 10) + (tmp_date % 10);
+        date = tmp_year + "-" + Math.floor(tmp_month / 10) +
+          (tmp_month % 10) + "-" +
+          Math.floor(tmp_date / 10) + (tmp_date % 10);
 
-        input.setAttribute(
-          'value',
-          date + time
-        );
-      }
-      input.setAttribute('name', field_json.key);
-      input.setAttribute('title', field_json.title);
-      if (field_json.required === 1) {
-        input.setAttribute('required', 'required');
+        input_state.value = date + time;
       }
-      if (field_json.editable !== 1) {
-        input.setAttribute('readonly', 'readonly');
-        input.setAttribute('data-wrapper-class', 'ui-state-disabled ui-state-readonly');
-        input.setAttribute('disabled', 'disabled');
+
+      // Render
+      if (gadget.state.editable) {
+        queue
+          .push(function (gadget_list) {
+            promise_list = [
+              gadget_list[0].render(input_state)
+            ];
+            if (gadget.state.timezone_style) {
+              promise_list.push(gadget_list[1].render(select_state));
+            }
+            return RSVP.all(promise_list);
+          });
+      } else {
+        queue
+          .push(function (gadget_list) {
+            p_state.text_content = gadget.state.value;
+            return gadget_list[0].render(p_state);
+          });
       }
+      return queue;
     })
+
     .declareMethod('getContent', function (options) {
-      var input = this.element.querySelector('input'),
+      var gadget = this,
         result = {},
-        select,
-        year,
-        month,
-        field_json = this.props.field_json,
-        date,
-        hour,
-        minute,
-        timezone,
-        zone_list = {"GMT-12": "-1200", "GMT-11": "-1100",
-                   "GMT-9": "-0900", "GMT-8": "-0800",
-                   "GMT-7": "-0700", "GMT-6": "-0600",
-                   "GMT-5": "-0500", "GMT-4": "-0400",
-                   "GMT-3": "-0300", "GMT-2": "-0200",
-                   "GMT-1": "-0100", "GMT": "+0000",
-                   "GMT+1": "+0100", "GMT+2": "+0200",
-                   "GMT+3": "+0300", "GMT+4": "+0400",
-                   "GMT+5": "+0500", "GMT+6": "+0600",
-                   "GMT+7": "+0700", "GMT+8": "+0800",
-                   "GMT+9": "+0900", "GMT+10": "+1000",
-                   "GMT+11": "+1100", "GMT+12": "+1200"},
-        value = input.value;
-      if (options === undefined || options.format === "erp5") {
-        if (value !== "") {
-          if (field_json.date_only === 0) {
-            value += "+0000";
-          }
-          value = new Date(value);
-          year = value.getUTCFullYear();
-          month = value.getUTCMonth() + 1;
-          date = value.getUTCDate();
-          if (field_json.hide_day === 1) {
-            date = 1;
-          }
-          //get time
-          if (field_json.date_only === 0) {
-            if (field_json.allow_empty_time === 1) {
-              hour = 0;
-              minute = 0;
-            } else {
-              hour = value.getUTCHours();
-              minute = value.getUTCMinutes();
+        promise_list;
+      if (gadget.state.editable) {
+        promise_list = [gadget.getDeclaredGadget('INPUT')];
+        if (gadget.state.timezone_style) {
+          promise_list.push(gadget.getDeclaredGadget('SELECT'));
+        }
+        return new RSVP.Queue()
+          .push(function () {
+            return RSVP.all(promise_list);
+          })
+          .push(function (result_list) {
+            var i;
+            promise_list = [];
+            for (i = 0; i < result_list.length; i += 1) {
+              promise_list.push(result_list[i].getContent());
+            }
+            return RSVP.all(promise_list);
+          })
+          .push(function (result_list) {
+            var value = result_list[0][gadget.state.key + '_input'],
+              timezone = "+0000",
+              year,
+              month,
+              date,
+              hour,
+              minute,
+              j;
+            if (gadget.state.timezone_style) {
+              timezone = result_list[1][gadget.state.key + '_select'];
             }
-            if (field_json.ampm_time_style === 1) {
-              if (hour > 12) {
-                result[field_json.subfield_ampm_key] = "pm";
-                hour -= 12;
+
+            if (options === undefined || options.format === "erp5") {
+              if (value !== "") {
+                if (gadget.state.date_only === 0) {
+                  value += "+0000";
+                }
+                value = new Date(value);
+                year = value.getUTCFullYear();
+                month = value.getUTCMonth() + 1;
+                date = value.getUTCDate();
+                if (gadget.state.hide_day === 1) {
+                  date = 1;
+                }
+                //get time
+                if (gadget.state.date_only === 0) {
+                  if (gadget.state.allow_empty_time === 1) {
+                    hour = 0;
+                    minute = 0;
+                  } else {
+                    hour = value.getUTCHours();
+                    minute = value.getUTCMinutes();
+                  }
+                  if (gadget.state.ampm_time_style === 1) {
+                    if (hour > 12) {
+                      result[gadget.state.subfield_ampm_key] = "pm";
+                      hour -= 12;
+                    } else {
+                      result[gadget.state.subfield_ampm_key] = "am";
+                    }
+                  }
+                  result[gadget.state.subfield_hour_key] = hour;
+                  result[gadget.state.subfield_minute_key] = minute;
+                }
+
+                if (gadget.state.hidden_day_is_last_day === 1) {
+                  if (month === 12) {
+                    year += 1;
+                    month = 1;
+                  } else {
+                    month += 1;
+                  }
+                }
+                result[gadget.state.subfield_year_key] = year;
+                result[gadget.state.subfield_month_key] = month;
+                result[gadget.state.subfield_day_key] = date;
+                if (gadget.state.timezone_style) {
+                  //set timezone
+                  for (j = 0; j < ZONE_LIST.length; j += 1) {
+                    if (timezone === ZONE_LIST[j][1]) {
+                      result[gadget.state.subfield_timezone_key] =
+                        ZONE_LIST[j][0];
+                    }
+                  }
+                }
               } else {
-                result[field_json.subfield_ampm_key] = "am";
+                //if no value, return empty data
+                if (gadget.state.date_only === 0) {
+                  result[gadget.state.subfield_hour_key] = "";
+                  result[gadget.state.subfield_minute_key] = "";
+                }
+                result[gadget.state.subfield_year_key] = "";
+                result[gadget.state.subfield_month_key] = "";
+                result[gadget.state.subfield_day_key] = "";
               }
+              return result;
             }
-            result[field_json.subfield_hour_key] = hour;
-            result[field_json.subfield_minute_key] = minute;
-          }
-
-          if (field_json.hidden_day_is_last_day === 1) {
-            if (month === 12) {
-              year += 1;
-              month = 1;
-            } else {
-              month += 1;
+            if (gadget.state.date_only) {
+              value += "T00:00";
             }
-          }
-          result[field_json.subfield_year_key] = year;
-          result[field_json.subfield_month_key] = month;
-          result[field_json.subfield_day_key] = date;
-          if (field_json.timezone_style) {
-            //set timezone
-            select = this.element.querySelector("select");
-            result[field_json.subfield_timezone_key] = select.options[select.selectedIndex].value;
-          }
-        } else {
-          //if no value, return empty data
-          if (field_json.date_only === 0) {
-            result[field_json.subfield_hour_key] = "";
-            result[field_json.subfield_minute_key] = "";
-          }
-          result[field_json.subfield_year_key] = "";
-          result[field_json.subfield_month_key] = "";
-          result[field_json.subfield_day_key] = "";
-        }
-        return result;
-      }
-      if (field_json.date_only) {
-        value += "T00:00";
+            result[gadget.state.key] = value + timezone;
+            return result;
+          });
       }
-      if (field_json.timezone_style) {
-        //set timezone
-        select = this.element.querySelector("select");
-        timezone = select.options[select.selectedIndex].value;
-      } else {
-        timezone = "GMT";
-      }
-      result[field_json.key] = value + zone_list[timezone];
       return result;
     })
-    .declareMethod('checkValidity', function () {
-      var gadget = this,
-        valide = true,
-        start_datetime = false,
-        end_datetime = false,
-        datetime_string,
-        select = gadget.element.querySelector("select"),
-        datetime,
-        input = gadget.element.querySelector('input'),
-        field_json = gadget.props.field_json;
-      if (!input.checkValidity()) {
-        return false;
-      }
-      return new RSVP.Queue()
-        .push(function () {
-          return gadget.notifyValid();
-        })
-        .push(function () {
-          return gadget.getContent();
-        })
-        .push(function (result) {
-          datetime_string = result[field_json.subfield_month_key];
-          datetime_string += "," + result[field_json.subfield_day_key];
-          datetime_string += "," + result[field_json.subfield_year_key];
-          if (field_json.date_only === 0) {
-            if (result[field_json.subfield_ampm_key] === "pm") {
-              result[field_json.subfield_hour_key] += 12;
-            }
-            datetime_string += " " + result[field_json.subfield_hour_key];
-            datetime_string += ":" + result[field_json.subfield_minute_key] + ":00";
-            datetime_string += "+0000";
-          }
-          if (datetime_string.indexOf("NaN") !== -1) {
-            valide = false;
-            return gadget.notifyInvalid("Invalide DateTime");
-          }
-          if (field_json.start_datetime) {
-            start_datetime = Date.parse(field_json.start_datetime);
-          }
-          if (field_json.end_datetime) {
-            end_datetime = Date.parse(field_json.end_datetime);
-          }
-          if ((start_datetime === false) && (end_datetime === false)) {
-            return;
-          }
-          datetime = Date.parse(datetime_string);
-          datetime -= (select.selectedIndex - 12) * 60 * 60 * 1000;
-          if (start_datetime) {
-            if (start_datetime > datetime) {
-              valide = false;
-              return gadget.notifyInvalid("The date and time you entered earlier than the start time");
-            }
-          }
-          if (end_datetime) {
-            if (end_datetime <= datetime) {
-              valide = false;
-              return gadget.notifyInvalid("The date and time you entered later than the end time");
-            }
-          }
-        })
-        .push(function () {
-          return valide;
-        });
+
+    .declareMethod('getTextContent', function () {
+      return this.state.value || "";
     })
-     .declareService(function () {
-      ////////////////////////////////////
-      // Inform when the field input is invalid
-      ////////////////////////////////////
-      var field_gadget = this;
 
-      function notifyInvalid(evt) {
-        return field_gadget.notifyInvalid(evt.target.validationMessage);
+    .declareMethod('checkValidity', function () {
+      var gadget = this;
+      if (gadget.state.editable) {
+        return gadget.getDeclaredGadget('INPUT')
+          .push(function (result) {
+            return result.checkValidity();
+          });
       }
-
-      // Listen to input change
-      return loopEventListener(
-        field_gadget.element.querySelector('input'),
-        'invalid',
-        false,
-        notifyInvalid
-      );
+      return true;
     });
 
-}(window, rJS, RSVP, document, loopEventListener));
\ No newline at end of file
+}(window, rJS, RSVP));
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.xml
index 3ec5953858..88df139072 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_datetimefield_js.xml
@@ -224,7 +224,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.4467.13140.25890</string> </value>
+                <value> <string>954.44614.5572.28040</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -242,7 +242,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1466755364.27</float>
+                        <float>1476799333.29</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css
index 2a1541e6c4..665dfd5778 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css
@@ -1025,6 +1025,18 @@ div[data-gadget-scope='header'] .ui-header ul a {
   background-color: #2b2b2b;
 }
 /**********************************************
+* Gadget: datetime field
+**********************************************/
+.datetimefield {
+  display: flex;
+}
+.datetimefield div[data-gadget-scope=INPUT] {
+  flex: 2;
+}
+.datetimefield div[data-gadget-scope=SELECT] {
+  flex: 1;
+}
+/**********************************************
 * Listbox
 **********************************************/
 div[data-gadget-scope='erp5_searchfield'] .ui-input-text {
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.xml
index 6d820c45a6..5730053993 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.22971.45413.40994</string> </value>
+                <value> <string>954.44246.45584.9130</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1475501272.94</float>
+                        <float>1476777160.07</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt
index 76cf13d717..2472443253 100644
--- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt
@@ -1197,6 +1197,19 @@ div[data-gadget-scope='header'] .ui-header {
   }
 }
 
+/**********************************************
+* Gadget: datetime field
+**********************************************/
+.datetimefield {
+  display: flex;
+  div[data-gadget-scope=INPUT] {
+    flex: 2;
+  }
+  div[data-gadget-scope=SELECT] {
+    flex: 1;
+  }
+}
+
 /**********************************************
 * Listbox
 **********************************************/
-- 
2.30.9