diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 0557f903..f091a3f2 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -3845,77 +3845,6 @@ function rcube_calendar_ui(settings)
}
}));
- // format time string
- var formattime = function(hour, minutes, start) {
- var time, diff, unit, duration = '', d = new Date();
- d.setHours(hour);
- d.setMinutes(minutes);
- time = $.fullCalendar.formatDate(d, settings['time_format']);
- if (start) {
- diff = Math.floor((d.getTime() - start.getTime()) / 60000);
- if (diff > 0) {
- unit = 'm';
- if (diff >= 60) {
- unit = 'h';
- diff = Math.round(diff / 3) / 20;
- }
- duration = ' (' + diff + unit + ')';
- }
- }
- return [time, duration];
- };
-
- var autocomplete_times = function(p, callback) {
- /* Time completions */
- var result = [];
- var now = new Date();
- var st, start = (String(this.element.attr('id')).indexOf('endtime') > 0
- && (st = $('#edit-starttime').val())
- && $('#edit-startdate').val() == $('#edit-enddate').val())
- ? parse_datetime(st, '') : null;
- var full = p.term - 1 > 0 || p.term.length > 1;
- var hours = start ? start.getHours() :
- (full ? parse_datetime(p.term, '') : now).getHours();
- var step = 15;
- var minutes = hours * 60 + (full ? 0 : now.getMinutes());
- var min = Math.ceil(minutes / step) * step % 60;
- var hour = Math.floor(Math.ceil(minutes / step) * step / 60);
- // list hours from 0:00 till now
- for (var h = start ? start.getHours() : 0; h < hours; h++)
- result.push(formattime(h, 0, start));
- // list 15min steps for the next two hours
- for (; h < hour + 2 && h < 24; h++) {
- while (min < 60) {
- result.push(formattime(h, min, start));
- min += step;
- }
- min = 0;
- }
- // list the remaining hours till 23:00
- while (h < 24)
- result.push(formattime((h++), 0, start));
-
- return callback(result);
- };
-
- var autocomplete_open = function(event, ui) {
- // scroll to current time
- var $this = $(this);
- var widget = $this.autocomplete('widget');
- var menu = $this.data('ui-autocomplete').menu;
- var amregex = /^(.+)(a[.m]*)/i;
- var pmregex = /^(.+)(a[.m]*)/i;
- var val = $(this).val().replace(amregex, '0:$1').replace(pmregex, '1:$1');
- var li, html;
- widget.css('width', '10em');
- widget.children().each(function(){
- li = $(this);
- html = li.children().first().html().replace(/\s+\(.+\)$/, '').replace(amregex, '0:$1').replace(pmregex, '1:$1');
- if (html.indexOf(val) == 0)
- menu._scrollIntoView(li);
- });
- };
-
// if start date is changed, shift end date according to initial duration
var shift_enddate = function(dateText) {
var newstart = parse_datetime('0', dateText);
@@ -4016,30 +3945,12 @@ function rcube_calendar_ui(settings)
$('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); event_times_changed(); });
// configure drop-down menu on time input fields based on jquery UI autocomplete
- $('#edit-starttime, #edit-endtime, #eventedit input.edit-alarm-time')
- .attr('autocomplete', "off")
- .autocomplete({
- delay: 100,
- minLength: 1,
- appendTo: '#eventedit',
- source: autocomplete_times,
- open: autocomplete_open,
- change: event_times_changed,
- select: function(event, ui) {
- $(this).val(ui.item[0]).change();
- return false;
- }
- })
- .click(function() { // show drop-down upon clicks
- $(this).autocomplete('search', $(this).val() ? $(this).val().replace(/\D.*/, "") : " ");
- }).each(function(){
- $(this).data('ui-autocomplete')._renderItem = function(ul, item) {
- return $('
')
- .data('ui-autocomplete-item', item)
- .append('' + item[0] + item[1] + '')
- .appendTo(ul);
- };
+ $('#edit-starttime, #edit-endtime, #eventedit input.edit-alarm-time').each(function() {
+ me.init_time_autocomplete(this, {
+ container: '#eventedit',
+ change: event_times_changed
});
+ });
// adjust end time when changing start
$('#edit-starttime').change(function(e) {
diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js
index b4102b96..d428e719 100644
--- a/plugins/libcalendaring/libcalendaring.js
+++ b/plugins/libcalendaring/libcalendaring.js
@@ -438,6 +438,121 @@ function rcube_libcalendaring(settings)
return valarms;
};
+ // format time string
+ var time_autocomplete_format = function(hour, minutes, start) {
+ var time, diff, unit, duration = '', d = new Date();
+
+ d.setHours(hour);
+ d.setMinutes(minutes);
+ time = me.format_time(d);
+
+ if (start) {
+ diff = Math.floor((d.getTime() - start.getTime()) / 60000);
+ if (diff > 0) {
+ unit = 'm';
+ if (diff >= 60) {
+ unit = 'h';
+ diff = Math.round(diff / 3) / 20;
+ }
+ duration = ' (' + diff + unit + ')';
+ }
+ }
+
+ return [time, duration];
+ };
+
+ var time_autocomplete_list = function(p, callback) {
+ // Time completions
+ var st, h, step = 15, result = [], now = new Date(),
+ id = String(this.element.attr('id')),
+ m = id.match(/^(.*)-(starttime|endtime)$/),
+ start = (m && m[2] == 'endtime'
+ && (st = $('#' + m[1] + '-starttime').val())
+ && $('#' + m[1] + '-startdate').val() == $('#' + m[1] + '-enddate').val())
+ ? me.parse_datetime(st, '') : null,
+ full = p.term - 1 > 0 || p.term.length > 1,
+ hours = start ? start.getHours() : (full ? me.parse_datetime(p.term, '') : now).getHours(),
+ minutes = hours * 60 + (full ? 0 : now.getMinutes()),
+ min = Math.ceil(minutes / step) * step % 60,
+ hour = Math.floor(Math.ceil(minutes / step) * step / 60);
+
+ // list hours from 0:00 till now
+ for (h = start ? start.getHours() : 0; h < hours; h++)
+ result.push(time_autocomplete_format(h, 0, start));
+
+ // list 15min steps for the next two hours
+ for (; h < hour + 2 && h < 24; h++) {
+ while (min < 60) {
+ result.push(time_autocomplete_format(h, min, start));
+ min += step;
+ }
+ min = 0;
+ }
+
+ // list the remaining hours till 23:00
+ while (h < 24)
+ result.push(time_autocomplete_format((h++), 0, start));
+
+ return callback(result);
+ };
+
+ var time_autocomplete_open = function(event, ui) {
+ // scroll to current time
+ var $this = $(this),
+ widget = $this.autocomplete('widget')
+ menu = $this.data('ui-autocomplete').menu,
+ amregex = /^(.+)(a[.m]*)/i,
+ pmregex = /^(.+)(a[.m]*)/i,
+ val = $(this).val().replace(amregex, '0:$1').replace(pmregex, '1:$1');
+
+ widget.css('width', '10em');
+
+ if (val === '')
+ menu._scrollIntoView(widget.children('li:first'));
+ else
+ widget.children().each(function() {
+ var li = $(this),
+ html = li.children().first().html()
+ .replace(/\s+\(.+\)$/, '')
+ .replace(amregex, '0:$1')
+ .replace(pmregex, '1:$1');
+
+ if (html.indexOf(val) == 0)
+ menu._scrollIntoView(li);
+ });
+ };
+
+ /**
+ * Initializes time autocompletion
+ */
+ this.init_time_autocomplete = function(elem, props)
+ {
+ var default_props = {
+ delay: 100,
+ minLength: 1,
+ appendTo: props.container,
+ source: time_autocomplete_list,
+ open: time_autocomplete_open,
+ // change: time_autocomplete_change,
+ select: function(event, ui) {
+ $(this).val(ui.item[0]).change();
+ return false;
+ }
+ };
+
+ $(elem).attr('autocomplete', "off")
+ .autocomplete($.extend(default_props, props))
+ .click(function() { // show drop-down upon clicks
+ $(this).autocomplete('search', $(this).val() ? $(this).val().replace(/\D.*/, "") : " ");
+ });
+
+ $(elem).data('ui-autocomplete')._renderItem = function(ul, item) {
+ return $('')
+ .data('ui-autocomplete-item', item)
+ .append('' + item[0] + item[1] + '')
+ .appendTo(ul);
+ };
+ };
/***** Alarms handling *****/
@@ -1201,5 +1316,4 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.location_href(rcmail.env.attachment_download_url, window);
}, true);
}
-
});
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index a5a7a7fd..2d91908c 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -723,6 +723,11 @@ function rcube_tasklist_ui(settings)
$('#edit-attendees-invite').click();
return false;
});
+
+ // configure drop-down menu on time input fields based on jquery UI autocomplete
+ $('#taskedit-starttime, #taskedit-time, #taskedit input.edit-alarm-time').each(function() {
+ me.init_time_autocomplete(this, {container: '#taskedit'});
+ });
}
/**