Commit d5d68cec authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Reimplement DateTimeField

parent 5ad60e06
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" /> <meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 Floatfield</title> <title>ERP5 Datetimefield</title>
<!-- renderjs --> <!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script> <script src="rsvp.js" type="text/javascript"></script>
...@@ -13,6 +13,6 @@ ...@@ -13,6 +13,6 @@
</head> </head>
<body> <body>
<input type="date" /> <div class="datetimefield"></div>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
</item> </item>
<item> <item>
<key> <string>actor</string> </key> <key> <string>actor</string> </key>
<value> <string>romain</string> </value> <value> <string>zope</string> </value>
</item> </item>
<item> <item>
<key> <string>comment</string> </key> <key> <string>comment</string> </key>
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>940.50766.7916.31675</string> </value> <value> <string>954.44229.8719.22835</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -252,8 +252,8 @@ ...@@ -252,8 +252,8 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1423235572.23</float> <float>1476776016.7</float>
<string>GMT</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
</object> </object>
......
/*global window, rJS, RSVP, document, loopEventListener */ /*global window, rJS, RSVP*/
/*jslint indent: 2 */ /*jslint indent: 2, maxlen: 80 */
(function (window, rJS, RSVP, document, loopEventListener) { (function (window, rJS, RSVP) {
"use strict"; "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) 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) { .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, date,
tmp, tmp,
timezone, timezone,
...@@ -25,41 +72,85 @@ ...@@ -25,41 +72,85 @@
tmp_date, tmp_date,
tmp_hour, tmp_hour,
tmp_minute, tmp_minute,
select, leap_year,
time = "", time = "",
leapyear, last_month_date = [
i, [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
field_json = options.field_json || {}, [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
lastDateOfMonth = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], ],//leapyear
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]],//leapyear queue = new RSVP.Queue(),
select_options = ["GMT-12", "GMT-11", "GMT-10", "GMT-9", "GMT-8", "GMT-7", "GMT-6", promise_list,
"GMT-5", "GMT-4", "GMT-3", "GMT-2", "GMT-1", "GMT", "GMT+1", input_state = {
"GMT+2", "GMT+3", "GMT+4", "GMT+5", "GMT+6", "GMT+7", "GMT+8", name: gadget.state.key + '_input',
"GMT+9", "GMT+10", "GMT+11", "GMT+12"], editable: gadget.state.editable,
select_option, required: gadget.state.required,
value = field_json.value || field_json.default || ""; type: gadget.state.date_only ? "date" : "datetime-local"
this.props.field_json = field_json; },
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"
};
// Create or fetch sub gadgets
if (field_json.timezone_style) { if (modification_dict.hasOwnProperty('editable') ||
//change date to local modification_dict.hasOwnProperty('timezone_style')) {
select = document.createElement("select"); if (gadget.state.editable) {
for (i = 0; i < select_options.length; i += 1) { promise_list = [
select_option = document.createElement("option"); gadget.declareGadget('gadget_html5_input.html', {scope: 'INPUT'})
select_option.value = select_options[i]; ];
select_option.innerHTML = select_options[i]; if (gadget.state.timezone_style) {
select.appendChild(select_option); 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"); queue
select.selectedIndex = 12; .push(function () {
this.element.appendChild(select); return RSVP.all(promise_list);
} })
if (field_json.date_only === 0) { .push(function (result_list) {
input.setAttribute("type", "datetime-local"); // 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 //Change type to datetime/datetime local if configured in the field
if (value !== "") { if (gadget.state.value) {
tmp = new Date(value); tmp = new Date(gadget.state.value);
//get date without timezone //get date without timezone
tmp_date = tmp.getUTCDate(); tmp_date = tmp.getUTCDate();
tmp_month = tmp.getUTCMonth() + 1; tmp_month = tmp.getUTCMonth() + 1;
...@@ -70,12 +161,13 @@ ...@@ -70,12 +161,13 @@
//timezone required //timezone required
//convert time to GMT //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) { if (gadget.state.timezone_style) {
select.selectedIndex = timezone + 12; 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) { if (timezone !== 0) {
tmp_hour += timezone; tmp_hour += timezone;
if (tmp_hour < 0) { if (tmp_hour < 0) {
...@@ -87,12 +179,12 @@ ...@@ -87,12 +179,12 @@
tmp_month = 12; tmp_month = 12;
tmp_year -= 1; 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) { } else if (tmp_hour > 23) {
tmp_hour -= 24; tmp_hour -= 24;
tmp_date += 1; 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_date = 1;
tmp_month += 1; tmp_month += 1;
if (tmp_month > 12) { if (tmp_month > 12) {
...@@ -102,208 +194,162 @@ ...@@ -102,208 +194,162 @@
} }
} }
} }
if (field_json.date_only === 0) {
time = "T" + Math.floor(tmp_hour / 10) + tmp_hour % 10 + ":" if (!gadget.state.date_only) {
+ Math.floor(tmp_minute / 10) + (tmp_minute % 10) + ":00"; 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) + "-" date = tmp_year + "-" + Math.floor(tmp_month / 10) +
+ Math.floor(tmp_date / 10) + (tmp_date % 10); (tmp_month % 10) + "-" +
Math.floor(tmp_date / 10) + (tmp_date % 10);
input.setAttribute( input_state.value = date + time;
'value',
date + time
);
}
input.setAttribute('name', field_json.key);
input.setAttribute('title', field_json.title);
if (field_json.required === 1) {
input.setAttribute('required', 'required');
} }
if (field_json.editable !== 1) {
input.setAttribute('readonly', 'readonly'); // Render
input.setAttribute('data-wrapper-class', 'ui-state-disabled ui-state-readonly'); if (gadget.state.editable) {
input.setAttribute('disabled', 'disabled'); 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) { .declareMethod('getContent', function (options) {
var input = this.element.querySelector('input'), var gadget = this,
result = {}, result = {},
select, promise_list;
year, if (gadget.state.editable) {
month, promise_list = [gadget.getDeclaredGadget('INPUT')];
field_json = this.props.field_json, if (gadget.state.timezone_style) {
date, promise_list.push(gadget.getDeclaredGadget('SELECT'));
hour, }
minute, return new RSVP.Queue()
timezone, .push(function () {
zone_list = {"GMT-12": "-1200", "GMT-11": "-1100", return RSVP.all(promise_list);
"GMT-9": "-0900", "GMT-8": "-0800", })
"GMT-7": "-0700", "GMT-6": "-0600", .push(function (result_list) {
"GMT-5": "-0500", "GMT-4": "-0400", var i;
"GMT-3": "-0300", "GMT-2": "-0200", promise_list = [];
"GMT-1": "-0100", "GMT": "+0000", for (i = 0; i < result_list.length; i += 1) {
"GMT+1": "+0100", "GMT+2": "+0200", promise_list.push(result_list[i].getContent());
"GMT+3": "+0300", "GMT+4": "+0400", }
"GMT+5": "+0500", "GMT+6": "+0600", return RSVP.all(promise_list);
"GMT+7": "+0700", "GMT+8": "+0800", })
"GMT+9": "+0900", "GMT+10": "+1000", .push(function (result_list) {
"GMT+11": "+1100", "GMT+12": "+1200"}, var value = result_list[0][gadget.state.key + '_input'],
value = input.value; timezone = "+0000",
if (options === undefined || options.format === "erp5") { year,
if (value !== "") { month,
if (field_json.date_only === 0) { date,
value += "+0000"; hour,
} minute,
value = new Date(value); j;
year = value.getUTCFullYear(); if (gadget.state.timezone_style) {
month = value.getUTCMonth() + 1; timezone = result_list[1][gadget.state.key + '_select'];
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();
} }
if (field_json.ampm_time_style === 1) {
if (hour > 12) { if (options === undefined || options.format === "erp5") {
result[field_json.subfield_ampm_key] = "pm"; if (value !== "") {
hour -= 12; 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 { } 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; if (gadget.state.date_only) {
result[field_json.subfield_minute_key] = minute; value += "T00:00";
}
if (field_json.hidden_day_is_last_day === 1) {
if (month === 12) {
year += 1;
month = 1;
} else {
month += 1;
} }
} result[gadget.state.key] = value + timezone;
result[field_json.subfield_year_key] = year; return result;
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";
} }
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; return result;
}) })
.declareMethod('checkValidity', function () {
var gadget = this, .declareMethod('getTextContent', function () {
valide = true, return this.state.value || "";
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;
});
}) })
.declareService(function () {
////////////////////////////////////
// Inform when the field input is invalid
////////////////////////////////////
var field_gadget = this;
function notifyInvalid(evt) { .declareMethod('checkValidity', function () {
return field_gadget.notifyInvalid(evt.target.validationMessage); var gadget = this;
if (gadget.state.editable) {
return gadget.getDeclaredGadget('INPUT')
.push(function (result) {
return result.checkValidity();
});
} }
return true;
// Listen to input change
return loopEventListener(
field_gadget.element.querySelector('input'),
'invalid',
false,
notifyInvalid
);
}); });
}(window, rJS, RSVP, document, loopEventListener)); }(window, rJS, RSVP));
\ No newline at end of file \ No newline at end of file
...@@ -224,7 +224,7 @@ ...@@ -224,7 +224,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>952.4467.13140.25890</string> </value> <value> <string>954.44614.5572.28040</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1466755364.27</float> <float>1476799333.29</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -1025,6 +1025,18 @@ div[data-gadget-scope='header'] .ui-header ul a { ...@@ -1025,6 +1025,18 @@ div[data-gadget-scope='header'] .ui-header ul a {
background-color: #2b2b2b; 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 * Listbox
**********************************************/ **********************************************/
div[data-gadget-scope='erp5_searchfield'] .ui-input-text { div[data-gadget-scope='erp5_searchfield'] .ui-input-text {
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>954.22971.45413.40994</string> </value> <value> <string>954.44246.45584.9130</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1475501272.94</float> <float>1476777160.07</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -1197,6 +1197,19 @@ div[data-gadget-scope='header'] .ui-header { ...@@ -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 * Listbox
**********************************************/ **********************************************/
......
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