[erp5_web_renderjs_ui] Reimplement DateTimeField
/*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 |