Commit d5d68cec authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Reimplement DateTimeField

parent 5ad60e06
......@@ -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
......@@ -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>
......
/*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
......@@ -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>
......
......@@ -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 {
......
......@@ -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>
......
......@@ -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
**********************************************/
......
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