From b2034fdfec040a67988e543a911208ef2491ce7a Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Sun, 22 Feb 2015 12:58:46 +0100 Subject: New RoundCube Plugins Git folder --- jqueryui/js/jquery-ui-accessible-datepicker.js | 235 +++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 jqueryui/js/jquery-ui-accessible-datepicker.js (limited to 'jqueryui/js/jquery-ui-accessible-datepicker.js') diff --git a/jqueryui/js/jquery-ui-accessible-datepicker.js b/jqueryui/js/jquery-ui-accessible-datepicker.js new file mode 100644 index 0000000..ef7561c --- /dev/null +++ b/jqueryui/js/jquery-ui-accessible-datepicker.js @@ -0,0 +1,235 @@ +/*! jQuery UI Accessible Datepicker extension +* (to be appended to jquery-ui-*.custom.min.js) +* +* @licstart The following is the entire license notice for the +* JavaScript code in this page. +* +* Copyright 2014 Kolab Systems AG +* +* The JavaScript code in this page is free software: you can +* redistribute it and/or modify it under the terms of the GNU +* General Public License (GNU GPL) as published by the Free Software +* Foundation, either version 3 of the License, or (at your option) +* any later version. The code is distributed WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. +* +* As additional permission under GNU GPL version 3 section 7, you +* may distribute non-source (e.g., minimized or compacted) forms of +* that code without the copy of the GNU GPL normally required by +* section 4, provided you include this license notice and a URL +* through which recipients can access the Corresponding Source. +* +* @licend The above is the entire license notice +* for the JavaScript code in this page. +*/ + +(function($, undefined) { + +// references to super class methods +var __newInst = $.datepicker._newInst; +var __updateDatepicker = $.datepicker._updateDatepicker; +var __connectDatepicker = $.datepicker._connectDatepicker; +var __showDatepicker = $.datepicker._showDatepicker; +var __hideDatepicker = $.datepicker._hideDatepicker; + +// "extend" singleton instance methods +$.extend($.datepicker, { + + /* Create a new instance object */ + _newInst: function(target, inline) { + var that = this, inst = __newInst.call(this, target, inline); + + if (inst.inline) { + // attach keyboard event handler + inst.dpDiv.on('keydown.datepicker', '.ui-datepicker-calendar', function(event) { + // we're only interested navigation keys + if ($.inArray(event.keyCode, [ 13, 33, 34, 35, 36, 37, 38, 39, 40]) == -1) { + return; + } + event.stopPropagation(); + event.preventDefault(); + inst._hasfocus = true; + + var activeCell; + switch (event.keyCode) { + case $.ui.keyCode.ENTER: + if ((activeCell = $('.' + that._dayOverClass, inst.dpDiv).get(0) || $('.' + that._currentClass, inst.dpDiv).get(0))) { + that._selectDay(inst.input, inst.selectedMonth, inst.selectedYear, activeCell); + } + break; + + case $.ui.keyCode.PAGE_UP: + that._adjustDate(inst.input, -that._get(inst, 'stepMonths'), 'M'); + break; + case $.ui.keyCode.PAGE_DOWN: + that._adjustDate(inst.input, that._get(inst, 'stepMonths'), 'M'); + break; + + default: + return that._cursorKeydown(event, inst); + } + }) + .attr('role', 'region') + .attr('aria-labelledby', inst.id + '-dp-title'); + } + else { + var widgetId = inst.dpDiv.attr('id') || inst.id + '-dp-widget'; + inst.dpDiv.attr('id', widgetId) + .attr('aria-hidden', 'true') + .attr('aria-labelledby', inst.id + '-dp-title'); + + $(inst.input).attr('aria-haspopup', 'true') + .attr('aria-expanded', 'false') + .attr('aria-owns', widgetId); + } + + return inst; + }, + + /* Attach the date picker to an input field */ + _connectDatepicker: function(target, inst) { + __connectDatepicker.call(this, target, inst); + + var that = this; + + // register additional keyboard events to control date selection with cursor keys + $(target).unbind('keydown.datepicker-extended').bind('keydown.datepicker-extended', function(event) { + var inc = 1; + switch (event.keyCode) { + case 109: + case 173: + case 189: // "minus" + inc = -1; + case 61: + case 107: + case 187: // "plus" + // do nothing if the input does not contain full date string + if (this.value.length < that._formatDate(inst, inst.selectedDay, inst.selectedMonth, inst.selectedYear).length) { + return true; + } + that._adjustInstDate(inst, inc, 'D'); + that._selectDateRC(target, that._formatDate(inst, inst.selectedDay, inst.selectedMonth, inst.selectedYear)); + return false; + + case $.ui.keyCode.UP: + case $.ui.keyCode.DOWN: + // unfold datepicker if not visible + if ($.datepicker._lastInput !== target && !$.datepicker._isDisabledDatepicker(target)) { + that._showDatepicker(event); + event.stopPropagation(); + event.preventDefault(); + return false; + } + + default: + if (!$.datepicker._isDisabledDatepicker(target) && !event.ctrlKey && !event.metaKey) { + return that._cursorKeydown(event, inst); + } + } + }) + .attr('autocomplete', 'off'); + }, + + /* Handle keyboard event on datepicker widget */ + _cursorKeydown: function(event, inst) { + inst._keyEvent = true; + + var isRTL = inst.dpDiv.hasClass('ui-datepicker-rtl'); + + switch (event.keyCode) { + case $.ui.keyCode.LEFT: + this._adjustDate(inst.input, (isRTL ? +1 : -1), 'D'); + break; + case $.ui.keyCode.RIGHT: + this._adjustDate(inst.input, (isRTL ? -1 : +1), 'D'); + break; + case $.ui.keyCode.UP: + this._adjustDate(inst.input, -7, 'D'); + break; + case $.ui.keyCode.DOWN: + this._adjustDate(inst.input, +7, 'D'); + break; + case $.ui.keyCode.HOME: + // TODO: jump to first of month + break; + case $.ui.keyCode.END: + // TODO: jump to end of month + break; + } + + return true; + }, + + /* Pop-up the date picker for a given input field */ + _showDatepicker: function(input) { + input = input.target || input; + __showDatepicker.call(this, input); + + var inst = $.datepicker._getInst(input); + if (inst && $.datepicker._datepickerShowing) { + inst.dpDiv.attr('aria-hidden', 'false'); + $(input).attr('aria-expanded', 'true'); + } + }, + + /* Hide the date picker from view */ + _hideDatepicker: function(input) { + __hideDatepicker.call(this, input); + + var inst = this._curInst;; + if (inst && !$.datepicker._datepickerShowing) { + inst.dpDiv.attr('aria-hidden', 'true'); + $(inst.input).attr('aria-expanded', 'false'); + } + }, + + /* Render the date picker content */ + _updateDatepicker: function(inst) { + __updateDatepicker.call(this, inst); + + var activeCell = $('.' + this._dayOverClass, inst.dpDiv).get(0) || $('.' + this._currentClass, inst.dpDiv).get(0); + if (activeCell) { + activeCell = $(activeCell); + activeCell.attr('id', inst.id + '-day-' + activeCell.text()); + } + + // allow focus on main container only + inst.dpDiv.find('.ui-datepicker-calendar') + .attr('tabindex', inst.inline ? '0' : '-1') + .attr('role', 'grid') + .attr('aria-readonly', 'true') + .attr('aria-activedescendant', activeCell ? activeCell.attr('id') : '') + .find('td').attr('role', 'gridcell').attr('aria-selected', 'false') + .find('a').attr('tabindex', '-1'); + + $('.ui-datepicker-current-day', inst.dpDiv).attr('aria-selected', 'true'); + + inst.dpDiv.find('.ui-datepicker-title') + .attr('id', inst.id + '-dp-title') + + // set focus again after update + if (inst._hasfocus) { + inst.dpDiv.find('.ui-datepicker-calendar').focus(); + inst._hasfocus = false; + } + }, + + _selectDateRC: function(id, dateStr) { + var target = $(id), inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + if (inst.inline) { + this._updateDatepicker(inst); + } + } +}); + +}(jQuery)); -- cgit v1.2.3