Using HTML5 input field for mobile browsers to get there native UI for date/time entry

This commit is contained in:
Ralf Becker 2016-02-08 17:23:54 +00:00
parent 915ca69e86
commit 88ea87fedb

View File

@ -26,6 +26,9 @@
* Dates are passed to the server in ISO8601 format ("Y-m-d\TH:i:sP"), and data_format is * Dates are passed to the server in ISO8601 format ("Y-m-d\TH:i:sP"), and data_format is
* handled server-side. * handled server-side.
* *
* Widgets uses jQuery date- and time-picker for desktop browsers and
* HTML5 input fields for mobile devices to get their native UI for date/time entry.
*
* @augments et2_inputWidget * @augments et2_inputWidget
*/ */
var et2_date = et2_inputWidget.extend( var et2_date = et2_inputWidget.extend(
@ -87,7 +90,8 @@ String: A string in the user\'s date format, or a relative date. Relative dates
* *
* @memberOf et2_date * @memberOf et2_date
*/ */
init: function() { init: function()
{
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.date = new Date(); this.date = new Date();
@ -95,12 +99,15 @@ String: A string in the user\'s date format, or a relative date. Relative dates
this.date.setMinutes(0); this.date.setMinutes(0);
this.date.setSeconds(0); this.date.setSeconds(0);
this.input = null; this.input = null;
this.is_mobile = egwIsMobile();
this.dateFormat = this.is_mobile ? 'yy-mm-dd' : this.egw().dateTimeFormat(this.egw().preference("dateformat"));
this.timeFormat = this.is_mobile ? 'HH:mm' : this.egw().preference("timeformat") == 12 ? "h:mmtt" : "HH:mm";
this.createInputWidget(); this.createInputWidget();
}, },
createInputWidget: function() { createInputWidget: function()
{
this.span = $j(document.createElement(this.options.inline ? 'div' : "span")).addClass("et2_date"); this.span = $j(document.createElement(this.options.inline ? 'div' : "span")).addClass("et2_date");
this.input_date = $j(document.createElement(this.options.inline ? "div" : "input")); this.input_date = $j(document.createElement(this.options.inline ? "div" : "input"));
@ -111,38 +118,57 @@ String: A string in the user\'s date format, or a relative date. Relative dates
this.setDOMNode(this.span[0]); this.setDOMNode(this.span[0]);
// jQuery-UI date picker if (this.is_mobile)
if(this._type != 'date-timeonly')
{ {
this.egw().calendar(this.input_date, this._type == "date-time"); switch(this._type)
{
case 'date':
this.input_date.attr('type', 'date');
break;
case 'date-time':
this.input_date.attr('type', 'datetime-local');
break;
case 'date-timeonly':
this.input_date.addClass("et2_time");
this.input_date.attr('type', 'time');
break;
}
} }
else else
{ {
this.input_date.addClass("et2_time"); // jQuery-UI date picker
this.egw().time(this.input_date); if(this._type != 'date-timeonly')
{
this.egw().calendar(this.input_date, this._type == "date-time");
}
else
{
this.input_date.addClass("et2_time");
this.egw().time(this.input_date);
}
// Avoid collision of datepicker dialog with input field
this.input_date.datepicker('option', 'beforeShow', function(input, inst){
var cal = inst.dpDiv;
setTimeout(function () {
var $input = jQuery(input);
var inputOffset = $input.offset();
// position the datepicker in freespace zone
// avoid datepicker calendar collision with input field
if (cal.height() + inputOffset.top > window.innerHeight)
{
cal.position({
my: "left center",
at: 'right bottom',
collision: 'flip fit',
of: input
});
}
},0);
});
} }
// Avoid collision of datepicker dialog with input field
this.input_date.datepicker('option', 'beforeShow', function(input, inst){
var cal = inst.dpDiv;
setTimeout(function () {
var $input = jQuery(input);
var inputOffset = $input.offset();
// position the datepicker in freespace zone
// avoid datepicker calendar collision with input field
if (cal.height() + inputOffset.top > window.innerHeight)
{
cal.position({
my: "left center",
at: 'right bottom',
collision: 'flip fit',
of: input,
});
}
},0);
});
// Update internal value when changed // Update internal value when changed
var self = this; var self = this;
this.input_date.bind('change', function(e){ this.input_date.bind('change', function(e){
@ -297,7 +323,7 @@ String: A string in the user\'s date format, or a relative date. Relative dates
*/ */
set_year_range: function(_value) set_year_range: function(_value)
{ {
if(this.input_date && this._type == 'date') if(this.input_date && this._type == 'date' && !this.is_mobile)
{ {
this.input_date.datepicker('option','yearRange',_value); this.input_date.datepicker('option','yearRange',_value);
} }
@ -319,10 +345,18 @@ String: A string in the user\'s date format, or a relative date. Relative dates
* days from today. * days from today.
* @param {Date|Number|String} _value * @param {Date|Number|String} _value
*/ */
set_min: function(_value) { set_min: function(_value)
{
if(this.input_date) if(this.input_date)
{ {
this.input_date.datepicker('option','minDate',_value); if (this.is_mobile)
{
this.input_date.attr('min', _value);
}
else
{
this.input_date.datepicker('option','minDate',_value);
}
} }
this.options.min = _value; this.options.min = _value;
}, },
@ -342,10 +376,18 @@ String: A string in the user\'s date format, or a relative date. Relative dates
* days from today. * days from today.
* @param {Date|Number|String} _value * @param {Date|Number|String} _value
*/ */
set_max: function(_value) { set_max: function(_value)
{
if(this.input_date) if(this.input_date)
{ {
this.input_date.datepicker('option','maxDate',_value); if (this.is_mobile)
{
this.input_date.attr('max', _value);
}
else
{
this.input_date.datepicker('option','maxDate',_value);
}
} }
this.options.max = _value; this.options.max = _value;
}, },
@ -359,7 +401,8 @@ String: A string in the user\'s date format, or a relative date. Relative dates
* - string or number with timestamp in usertime like server-side uses it * - string or number with timestamp in usertime like server-side uses it
* - string starting with + or - to add/substract given number of seconds from current value, "+600" to add 10 minutes * - string starting with + or - to add/substract given number of seconds from current value, "+600" to add 10 minutes
*/ */
set_value: function(_value) { set_value: function(_value)
{
var old_value = this._oldValue; var old_value = this._oldValue;
if(_value === null || _value === "" || _value === undefined || if(_value === null || _value === "" || _value === undefined ||
// allow 0 as empty-value for date and date-time widgets, as that is used a lot eg. in InfoLog // allow 0 as empty-value for date and date-time widgets, as that is used a lot eg. in InfoLog
@ -406,7 +449,7 @@ String: A string in the user\'s date format, or a relative date. Relative dates
switch(this._type) switch(this._type)
{ {
case "date-timeonly": case "date-timeonly":
var parsed = jQuery.datepicker.parseTime(this.input_date.datepicker('option', 'timeFormat'), _value); var parsed = jQuery.datepicker.parseTime(this.timeFormat, _value);
if (!parsed) // parseTime returns false if (!parsed) // parseTime returns false
{ {
this.set_validation_error(this.egw().lang("'%1' has an invalid format !!!",_value)); this.set_validation_error(this.egw().lang("'%1' has an invalid format !!!",_value));
@ -448,8 +491,8 @@ String: A string in the user\'s date format, or a relative date. Relative dates
} }
else // Parse other date widgets date with timepicker date/time format to date onject else // Parse other date widgets date with timepicker date/time format to date onject
{ {
var parsed = jQuery.datepicker.parseDateTime(this.input_date.datepicker('option', 'dateFormat'), var parsed = jQuery.datepicker.parseDateTime(this.dateFormat,
this.input_date.datepicker('option', 'timeFormat'), _value); this.timeFormat, _value.replace('T', ' '));
if(!parsed) if(!parsed)
{ {
this.set_validation_error(this.egw().lang("%1' han an invalid format !!!",_value)); this.set_validation_error(this.egw().lang("%1' han an invalid format !!!",_value));
@ -486,15 +529,13 @@ String: A string in the user\'s date format, or a relative date. Relative dates
var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000); var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
if(this._type != 'date-timeonly') if(this._type != 'date-timeonly')
{ {
_value = jQuery.datepicker.formatDate(this.input_date.datepicker("option","dateFormat"), _value = jQuery.datepicker.formatDate(this.dateFormat, formatDate);
formatDate
);
} }
if(this._type != 'date') if(this._type != 'date')
{ {
if(this._type != 'date-timeonly') _value += ' '; if(this._type != 'date-timeonly') _value += this.is_mobile ? 'T' : ' ';
_value += jQuery.datepicker.formatTime(this.input_date.datepicker("option","timeFormat"),{ _value += jQuery.datepicker.formatTime(this.timeFormat, {
hour: formatDate.getHours(), hour: formatDate.getHours(),
minute: formatDate.getMinutes(), minute: formatDate.getMinutes(),
seconds: 0, seconds: 0,