From 49f9b849b9c5023f138e8932510b11bfc9765814 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Sun, 21 Oct 2012 18:50:03 -0700 Subject: Remove trailing whitespace and add final newlines --- ui/jquery.ui.datepicker.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'ui/jquery.ui.datepicker.js') diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js index 4643af2eb..7dacbc7c1 100644 --- a/ui/jquery.ui.datepicker.js +++ b/ui/jquery.ui.datepicker.js @@ -116,7 +116,7 @@ function Datepicker() { $.extend(Datepicker.prototype, { /* Class name added to elements to indicate already configured with a date picker. */ markerClassName: 'hasDatepicker', - + //Keep track of the maximum number of rows displayed (see #7043) maxRows: 4, @@ -125,7 +125,7 @@ $.extend(Datepicker.prototype, { if (this.debug) console.log.apply('', arguments); }, - + // TODO rename to "widget" when switching to widget factory _widgetDatepicker: function() { return this.dpDiv; @@ -235,7 +235,7 @@ $.extend(Datepicker.prototype, { if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) $.datepicker._hideDatepicker(); else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) { - $.datepicker._hideDatepicker(); + $.datepicker._hideDatepicker(); $.datepicker._showDatepicker(input[0]); } else $.datepicker._showDatepicker(input[0]); @@ -531,7 +531,7 @@ $.extend(Datepicker.prototype, { case 9: $.datepicker._hideDatepicker(); handled = false; break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + + case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + $.datepicker._currentClass + ')', inst.dpDiv); if (sel[0]) $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); @@ -629,7 +629,7 @@ $.extend(Datepicker.prototype, { }, /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. + If false returned from beforeShow event handler do not show. @param input element - the input field attached to the date picker or event - if triggered by focus */ _showDatepicker: function(input) { @@ -733,7 +733,7 @@ $.extend(Datepicker.prototype, { // this breaks the change event in IE inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) inst.input.focus(); - // deffered render of the years select (to avoid flashes on Firefox) + // deffered render of the years select (to avoid flashes on Firefox) if( inst.yearshtml ){ var origyearshtml = inst.yearshtml; setTimeout(function(){ @@ -1442,7 +1442,7 @@ $.extend(Datepicker.prototype, { $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]); }); }, - + /* Generate the HTML for the current state of the date picker. */ _generateHTML: function(inst) { var today = new Date(); @@ -1599,7 +1599,7 @@ $.extend(Datepicker.prototype, { drawMonth = 0; drawYear++; } - calender += '' + (isMultiMonth ? '' + + calender += '' + (isMultiMonth ? '' + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
' : '') : ''); group += calender; } @@ -1663,7 +1663,7 @@ $.extend(Datepicker.prototype, { '>' + year + ''; } inst.yearshtml += ''; - + html += inst.yearshtml; inst.yearshtml = null; } @@ -1774,7 +1774,7 @@ $.extend(Datepicker.prototype, { * Bind hover events for datepicker elements. * Done via delegate so the binding only occurs once in the lifetime of the parent div. * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ + */ function bindHover(dpDiv) { var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; return dpDiv.delegate(selector, 'mouseout', function() { @@ -1806,12 +1806,12 @@ function extendRemove(target, props) { Object - settings for attaching new datepicker functionality @return jQuery object */ $.fn.datepicker = function(options){ - + /* Verify an empty collection wasn't passed - Fixes #6976 */ if ( !this.length ) { return this; } - + /* Initialise the date picker. */ if (!$.datepicker.initialized) { $(document).mousedown($.datepicker._checkExternalClick). -- cgit v1.2.3 From b8e0de2444f38e69ad229f404651c9e331a9ac17 Mon Sep 17 00:00:00 2001 From: Jörn Zaefferer Date: Thu, 25 Oct 2012 09:25:40 -0400 Subject: Effects: Remove deprecated $.effects[]. Fixes #7115 - Effects: Remove support for effects in $.effects[]. --- tests/unit/effects/effects.html | 3 --- ui/jquery.ui.datepicker.js | 3 +-- ui/jquery.ui.effect.js | 34 +++++----------------------------- ui/jquery.ui.widget.js | 2 +- 4 files changed, 7 insertions(+), 35 deletions(-) (limited to 'ui/jquery.ui.datepicker.js') diff --git a/tests/unit/effects/effects.html b/tests/unit/effects/effects.html index 9305fcd21..c283eabff 100644 --- a/tests/unit/effects/effects.html +++ b/tests/unit/effects/effects.html @@ -5,9 +5,6 @@ jQuery UI Effects Test Suite - diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js index 7dacbc7c1..97a45139f 100644 --- a/ui/jquery.ui.datepicker.js +++ b/ui/jquery.ui.datepicker.js @@ -693,8 +693,7 @@ $.extend(Datepicker.prototype, { inst.dpDiv.zIndex($(input).zIndex()+1); $.datepicker._datepickerShowing = true; - // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) + if ( $.effects && $.effects.effect[ showAnim ] ) inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); else inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); diff --git a/ui/jquery.ui.effect.js b/ui/jquery.ui.effect.js index 37ca48795..5cd33886f 100644 --- a/ui/jquery.ui.effect.js +++ b/ui/jquery.ui.effect.js @@ -10,9 +10,7 @@ */ ;(jQuery.effects || (function($, undefined) { -var backCompat = $.uiBackCompat !== false, - // prefix used for storing data on .data() - dataSpace = "ui-effects-"; +var dataSpace = "ui-effects-"; $.effects = { effect: {} @@ -1099,15 +1097,7 @@ function standardSpeed( speed ) { } // invalid strings - treat as "normal" speed - if ( typeof speed === "string" && !$.effects.effect[ speed ] ) { - // TODO: remove in 2.0 (#7115) - if ( backCompat && $.effects[ speed ] ) { - return false; - } - return true; - } - - return false; + return typeof speed === "string" && !$.effects.effect[ speed ]; } $.fn.extend({ @@ -1115,12 +1105,9 @@ $.fn.extend({ var args = _normalizeArguments.apply( this, arguments ), mode = args.mode, queue = args.queue, - effectMethod = $.effects.effect[ args.effect ], + effectMethod = $.effects.effect[ args.effect ]; - // DEPRECATED: remove in 2.0 (#7115) - oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ]; - - if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) { + if ( $.fx.off || !effectMethod ) { // delegate to the original method (e.g., .show()) if possible if ( mode ) { return this[ mode ]( args.duration, args.complete ); @@ -1156,18 +1143,7 @@ $.fn.extend({ } } - // TODO: remove this check in 2.0, effectMethod will always be true - if ( effectMethod ) { - return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); - } else { - // DEPRECATED: remove in 2.0 (#7115) - return oldEffectMethod.call(this, { - options: args, - duration: args.duration, - callback: args.complete, - mode: args.mode - }); - } + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); }, _show: $.fn.show, diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js index 6e8150be7..00f36fe67 100644 --- a/ui/jquery.ui.widget.js +++ b/ui/jquery.ui.widget.js @@ -491,7 +491,7 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { if ( options.delay ) { element.delay( options.delay ); } - if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) { + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); -- cgit v1.2.3 From 5bd19650a30cbfc2e7f75135e0ebf1788c4b9767 Mon Sep 17 00:00:00 2001 From: Scott González Date: Fri, 26 Oct 2012 15:59:29 -0400 Subject: Datepicker: Removed iframe cover for IE6. --- tests/unit/datepicker/datepicker_core.js | 17 +++++++---------- themes/base/jquery.ui.datepicker.css | 11 ----------- ui/jquery.ui.datepicker.js | 21 +++------------------ 3 files changed, 10 insertions(+), 39 deletions(-) (limited to 'ui/jquery.ui.datepicker.js') diff --git a/tests/unit/datepicker/datepicker_core.js b/tests/unit/datepicker/datepicker_core.js index 4abdfd106..1a7d8cc82 100644 --- a/tests/unit/datepicker/datepicker_core.js +++ b/tests/unit/datepicker/datepicker_core.js @@ -43,15 +43,14 @@ test("widget method", function() { }); test('baseStructure', function() { - expect( 59 ); + expect( 58 ); var header, title, table, thead, week, panel, inl, child, inp = init('#inp').focus(), - dp = $('#ui-datepicker-div'), - iframe = ($.ui.ie6); + dp = $('#ui-datepicker-div'); ok(dp.is(':visible'), 'Structure - datepicker visible'); ok(!dp.is('.ui-datepicker-rtl'), 'Structure - not right-to-left'); ok(!dp.is('.ui-datepicker-multi'), 'Structure - not multi-month'); - equal(dp.children().length, 2 + (iframe ? 1 : 0), 'Structure - child count'); + equal(dp.children().length, 2, 'Structure - child count'); header = dp.children(':first'); ok(header.is('div.ui-datepicker-header'), 'Structure - header division'); @@ -78,7 +77,6 @@ test('baseStructure', function() { equal(week.children().length, 7, 'Structure - week child count'); ok(week.children(':first').is('td.ui-datepicker-week-end'), 'Structure - month table first day cell'); ok(week.children(':last').is('td.ui-datepicker-week-end'), 'Structure - month table second day cell'); - ok(dp.children('iframe').length === (iframe ? 1 : 0), 'Structure - iframe'); inp.datepicker('hide').datepicker('destroy'); // Editable month/year and button panel @@ -100,7 +98,7 @@ test('baseStructure', function() { inp = init('#inp', {numberOfMonths: 2}); inp.focus(); ok(dp.is('.ui-datepicker-multi'), 'Structure multi [2] - multi-month'); - equal(dp.children().length, 3 + (iframe ? 1 : 0), 'Structure multi [2] - child count'); + equal(dp.children().length, 3, 'Structure multi [2] - child count'); child = dp.children(':first'); ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure multi [2] - first month division'); child = dp.children(':eq(1)'); @@ -121,7 +119,7 @@ test('baseStructure', function() { inp = init('#inp', {numberOfMonths: [2, 2]}); inp.focus(); ok(dp.is('.ui-datepicker-multi'), 'Structure multi - multi-month'); - equal(dp.children().length, 6 + (iframe ? 1 : 0), 'Structure multi [2,2] - child count'); + equal(dp.children().length, 6, 'Structure multi [2,2] - child count'); child = dp.children(':first'); ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure multi [2,2] - first month division'); child = dp.children(':eq(1)'); @@ -156,7 +154,7 @@ test('baseStructure', function() { inl = init('#inl', {numberOfMonths: 2}); dp = inl.children(); ok(dp.is('.ui-datepicker-inline') && dp.is('.ui-datepicker-multi'), 'Structure inline multi - main div'); - equal(dp.children().length, 3 + (iframe ? 1 : 0), 'Structure inline multi - child count'); + equal(dp.children().length, 3, 'Structure inline multi - child count'); child = dp.children(':first'); ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure inline multi - first month division'); child = dp.children(':eq(1)'); @@ -168,13 +166,12 @@ test('baseStructure', function() { test('customStructure', function() { expect( 20 ); - var iframe, header, panel, title, thead, + var header, panel, title, thead, dp = $('#ui-datepicker-div'), // Check right-to-left localisation inp = init('#inp', $.datepicker.regional.he); inp.data('showButtonPanel.datepicker',true); inp.focus(); - iframe = ($.ui.ie6); ok(dp.is('.ui-datepicker-rtl'), 'Structure RTL - right-to-left'); header = dp.children(':first'); ok(header.is('div.ui-datepicker-header'), 'Structure RTL - header division'); diff --git a/themes/base/jquery.ui.datepicker.css b/themes/base/jquery.ui.datepicker.css index c1f269999..e25d8ea56 100644 --- a/themes/base/jquery.ui.datepicker.css +++ b/themes/base/jquery.ui.datepicker.css @@ -54,14 +54,3 @@ .ui-datepicker-rtl .ui-datepicker-group { float:right; } .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -} \ No newline at end of file diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js index 97a45139f..f74cb3bf9 100644 --- a/ui/jquery.ui.datepicker.js +++ b/ui/jquery.ui.datepicker.js @@ -682,23 +682,13 @@ $.extend(Datepicker.prototype, { if (!inst.inline) { var showAnim = $.datepicker._get(inst, 'showAnim'); var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !! cover.length ){ - var borders = $.datepicker._getBorders(inst.dpDiv); - cover.css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - } - }; inst.dpDiv.zIndex($(input).zIndex()+1); $.datepicker._datepickerShowing = true; if ( $.effects && $.effects.effect[ showAnim ] ) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration); else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); + inst.dpDiv[showAnim || 'show'](showAnim ? duration : null); if (inst.input.is(':visible') && !inst.input.is(':disabled')) inst.input.focus(); $.datepicker._curInst = inst; @@ -712,10 +702,6 @@ $.extend(Datepicker.prototype, { instActive = inst; // for delegate hover events inst.dpDiv.empty().append(this._generateHTML(inst)); this._attachHandlers(inst); - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 - cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) - } inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); var numMonths = this._getNumberOfMonths(inst); var cols = numMonths[1]; @@ -1604,8 +1590,7 @@ $.extend(Datepicker.prototype, { } html += group; } - html += buttonPanel + ($.ui.ie6 && !inst.inline ? - '' : ''); + html += buttonPanel; inst._keyEvent = false; return html; }, -- cgit v1.2.3 From 254f2b3698265bdcb7daa85f8c7e2c27192cd090 Mon Sep 17 00:00:00 2001 From: Mike Sherov Date: Fri, 9 Nov 2012 16:27:45 -0500 Subject: Dev: fix the datepicker test suite and jshint everything. Fixes #8804 - Dev: re-enable the datepicker test suite --- build/tasks/testswarm.js | 2 +- grunt.js | 4 +- tests/unit/all-active.html | 2 +- tests/unit/datepicker/datepicker.html | 1 - tests/unit/datepicker/datepicker_events.js | 19 +++ tests/unit/datepicker/datepicker_options.js | 68 ++++++++- tests/unit/datepicker/datepicker_tickets.js | 88 ----------- ui/jquery.ui.datepicker.js | 228 +++++++++++++++------------- 8 files changed, 209 insertions(+), 203 deletions(-) delete mode 100644 tests/unit/datepicker/datepicker_tickets.js (limited to 'ui/jquery.ui.datepicker.js') diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 35838a14e..95dfaca6c 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -13,7 +13,7 @@ var versions = { "Autocomplete": "autocomplete/autocomplete.html", "Button": "button/button.html", "Core": "core/core.html", - //"Datepicker": "datepicker/datepicker.html", + "Datepicker": "datepicker/datepicker.html", "Dialog": "dialog/dialog.html", "Draggable": "draggable/draggable.html", "Droppable": "droppable/droppable.html", diff --git a/grunt.js b/grunt.js index 84b2b7e8d..f960e90bc 100644 --- a/grunt.js +++ b/grunt.js @@ -281,13 +281,13 @@ grunt.initConfig({ files: grunt.file.expandFiles( "tests/unit/**/*.html" ).filter(function( file ) { // disabling everything that doesn't (quite) work with PhantomJS for now // TODO except for all|index|test, try to include more as we go - return !( /(all|all-active|index|test|dialog|slider|datepicker|tabs|tooltip)\.html$/ ).test( file ); + return !( /(all|all-active|index|test|dialog|slider|tabs|tooltip)\.html$/ ).test( file ); }) }, lint: { ui: grunt.file.expandFiles( "ui/*.js" ).filter(function( file ) { // TODO remove items from this list once rewritten - return !( /(mouse|datepicker)\.js$/ ).test( file ); + return !( /(mouse)\.js$/ ).test( file ); }), grunt: [ "grunt.js", "build/**/*.js" ], tests: "tests/unit/**/*.js" diff --git a/tests/unit/all-active.html b/tests/unit/all-active.html index c32cde0fb..e9c343d00 100644 --- a/tests/unit/all-active.html +++ b/tests/unit/all-active.html @@ -20,7 +20,7 @@ "autocomplete/autocomplete.html", "button/button.html", "core/core.html", - //"datepicker/datepicker.html", + "datepicker/datepicker.html", "dialog/dialog.html", "draggable/draggable.html", "droppable/droppable.html", diff --git a/tests/unit/datepicker/datepicker.html b/tests/unit/datepicker/datepicker.html index c0c68979d..390d052c3 100644 --- a/tests/unit/datepicker/datepicker.html +++ b/tests/unit/datepicker/datepicker.html @@ -28,7 +28,6 @@ - diff --git a/tests/unit/datepicker/datepicker_events.js b/tests/unit/datepicker/datepicker_events.js index 81b152c66..5e8a35e0d 100644 --- a/tests/unit/datepicker/datepicker_events.js +++ b/tests/unit/datepicker/datepicker_events.js @@ -126,4 +126,23 @@ test('events', function() { equal(selectedThis, inp2[0], 'Callback close this'); }); +test('beforeShowDay-getDate', function() { + expect( 3 ); + var inp = TestHelpers.datepicker.init('#inp', {beforeShowDay: function() { inp.datepicker('getDate'); return [true, '']; }}), + dp = $('#ui-datepicker-div'); + inp.val('01/01/2010').datepicker('show'); + // contains non-breaking space + equal($('div.ui-datepicker-title').text(), 'January 2010', 'Initial month'); + $('a.ui-datepicker-next', dp).click(); + $('a.ui-datepicker-next', dp).click(); + // contains non-breaking space + equal($('div.ui-datepicker-title').text(), 'March 2010', 'After next clicks'); + inp.datepicker('hide').datepicker('show'); + $('a.ui-datepicker-prev', dp).click(); + $('a.ui-datepicker-prev', dp).click(); + // contains non-breaking space + equal($('div.ui-datepicker-title').text(), 'November 2009', 'After prev clicks'); + inp.datepicker('hide'); +}); + })(jQuery); diff --git a/tests/unit/datepicker/datepicker_options.js b/tests/unit/datepicker/datepicker_options.js index 00910469e..df108309f 100644 --- a/tests/unit/datepicker/datepicker_options.js +++ b/tests/unit/datepicker/datepicker_options.js @@ -810,6 +810,7 @@ test('parseDate', function() { gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset()); TestHelpers.datepicker.equalsDate($.datepicker.parseDate('@', '981158400000'), gmtDate, 'Parse date @'); TestHelpers.datepicker.equalsDate($.datepicker.parseDate('!', '631167552000000000'), gmtDate, 'Parse date !'); + fr = $.datepicker.regional.fr; settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames}; @@ -819,12 +820,11 @@ test('parseDate', function() { new Date(2001, 4 - 1, 9), 'Parse date d MM DD yy with settings'); TestHelpers.datepicker.equalsDate($.datepicker.parseDate('DD, MM d, yy', 'Lundi, Avril 9, 2001', settings), new Date(2001, 4 - 1, 9), 'Parse date DD, MM d, yy with settings'); - TestHelpers.datepicker.equalsDate($.datepicker.parseDate('\'jour\' d \'de\' MM (\'\'DD\'\'), yy', - 'jour 9 de Avril (\'Lundi\'), 2001', settings), new Date(2001, 4 - 1, 9), - 'Parse date \'jour\' d \'de\' MM (\'\'DD\'\'), yy with settings'); + TestHelpers.datepicker.equalsDate($.datepicker.parseDate("'jour' d 'de' MM (''DD''), yy", "jour 9 de Avril ('Lundi'), 2001", settings), + new Date(2001, 4 - 1, 9), "Parse date 'jour' d 'de' MM (''DD''), yy with settings"); zh = $.datepicker.regional['zh-CN']; - TestHelpers.datepicker.equalsDate($.datepicker.parseDate('yy M d', '2011 十一 22', zh), + TestHelpers.datepicker.equalsDate($.datepicker.parseDate('yy M d', '2011 十一月 22', zh), new Date(2011, 11 - 1, 22), 'Parse date yy M d with zh-CN'); }); @@ -881,6 +881,26 @@ test('parseDateErrors', function() { 'Lun. 9 Apr 01 - D d M y', 'Unknown name at position 7'); }); +test('Ticket #7244: date parser does not fail when too many numbers are passed into the date function', function() { + expect( 4 ); + var date; + try{ + date = $.datepicker.parseDate('dd/mm/yy', '18/04/19881'); + ok(false, "Did not properly detect an invalid date"); + }catch(e){ + ok("invalid date detected"); + } + + try { + date = $.datepicker.parseDate('dd/mm/yy', '18/04/1988 @ 2:43 pm'); + equal(date.getDate(), 18); + equal(date.getMonth(), 3); + equal(date.getFullYear(), 1988); + } catch(e) { + ok(false, "Did not properly parse date with extra text separated by whitespace"); + } +}); + test('formatDate', function() { expect( 16 ); TestHelpers.datepicker.init('#inp'); @@ -924,4 +944,44 @@ test('formatDate', function() { 'Format date \'jour\' d \'de\' MM (\'\'DD\'\'), yy with settings'); }); +test('Ticket 6827: formatDate day of year calculation is wrong during day lights savings time', function(){ + expect( 1 ); + var time = $.datepicker.formatDate("oo", new Date("2010/03/30 12:00:00 CDT")); + equal(time, "089"); +}); + +test('Ticket 7602: Stop datepicker from appearing with beforeShow event handler', function(){ + expect( 3 ); + var inp = TestHelpers.datepicker.init('#inp',{ + beforeShow: function(){ + return false; + } + }), + dp = $('#ui-datepicker-div'); + inp.datepicker('show'); + equal(dp.css('display'), 'none',"beforeShow returns false"); + inp.datepicker('destroy'); + + inp = TestHelpers.datepicker.init('#inp',{ + beforeShow: function(){ + } + }); + dp = $('#ui-datepicker-div'); + inp.datepicker('show'); + equal(dp.css('display'), 'block',"beforeShow returns nothing"); + inp.datepicker('hide'); + inp.datepicker('destroy'); + + inp = TestHelpers.datepicker.init('#inp',{ + beforeShow: function(){ + return true; + } + }); + dp = $('#ui-datepicker-div'); + inp.datepicker('show'); + equal(dp.css('display'), 'block',"beforeShow returns true"); + inp.datepicker('hide'); + inp.datepicker('destroy'); +}); + })(jQuery); diff --git a/tests/unit/datepicker/datepicker_tickets.js b/tests/unit/datepicker/datepicker_tickets.js deleted file mode 100644 index 4440992ae..000000000 --- a/tests/unit/datepicker/datepicker_tickets.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * datepicker_tickets.js - */ -(function($) { - -module("datepicker: tickets"); - -// http://forum.jquery.com/topic/several-breaking-changes-in-jquery-ui-1-8rc1 -test('beforeShowDay-getDate', function() { - expect( 3 ); - var inp = TestHelpers.datepicker.init('#inp', {beforeShowDay: function() { inp.datepicker('getDate'); return [true, '']; }}), - dp = $('#ui-datepicker-div'); - inp.val('01/01/2010').datepicker('show'); - // contains non-breaking space - equal($('div.ui-datepicker-title').text(), 'January 2010', 'Initial month'); - $('a.ui-datepicker-next', dp).click(); - $('a.ui-datepicker-next', dp).click(); - // contains non-breaking space - equal($('div.ui-datepicker-title').text(), 'March 2010', 'After next clicks'); - inp.datepicker('hide').datepicker('show'); - $('a.ui-datepicker-prev', dp).click(); - $('a.ui-datepicker-prev', dp).click(); - // contains non-breaking space - equal($('div.ui-datepicker-title').text(), 'November 2009', 'After prev clicks'); - inp.datepicker('hide'); -}); - -test('Ticket 7602: Stop datepicker from appearing with beforeShow event handler', function(){ - expect( 3 ); - var inp = TestHelpers.datepicker.init('#inp',{ - beforeShow: function(){ - return false; - } - }), - dp = $('#ui-datepicker-div'); - inp.datepicker('show'); - equal(dp.css('display'), 'none',"beforeShow returns false"); - inp.datepicker('destroy'); - - inp = TestHelpers.datepicker.init('#inp',{ - beforeShow: function(){ - } - }); - dp = $('#ui-datepicker-div'); - inp.datepicker('show'); - equal(dp.css('display'), 'block',"beforeShow returns nothing"); - inp.datepicker('hide'); - inp.datepicker('destroy'); - - inp = TestHelpers.datepicker.init('#inp',{ - beforeShow: function(){ - return true; - } - }); - dp = $('#ui-datepicker-div'); - inp.datepicker('show'); - equal(dp.css('display'), 'block',"beforeShow returns true"); - inp.datepicker('hide'); - inp.datepicker('destroy'); -}); - -test('Ticket 6827: formatDate day of year calculation is wrong during day lights savings time', function(){ - expect( 1 ); - var time = $.datepicker.formatDate("oo", new Date("2010/03/30 12:00:00 CDT")); - equal(time, "089"); -}); - -test('Ticket #7244: date parser does not fail when too many numbers are passed into the date function', function() { - expect( 4 ); - var date; - try{ - date = $.datepicker.parseDate('dd/mm/yy', '18/04/19881'); - ok(false, "Did not properly detect an invalid date"); - }catch(e){ - ok("invalid date detected"); - } - - try { - date = $.datepicker.parseDate('dd/mm/yy', '18/04/1988 @ 2:43 pm'); - equal(date.getDate(), 18); - equal(date.getMonth(), 3); - equal(date.getFullYear(), 1988); - } catch(e) { - ok(false, "Did not properly parse date with extra text separated by whitespace"); - } -}); - -})(jQuery); diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js index f74cb3bf9..c7ecafffb 100644 --- a/ui/jquery.ui.datepicker.js +++ b/ui/jquery.ui.datepicker.js @@ -13,6 +13,7 @@ */ (function( $, undefined ) { +/*jshint onevar: false, curly: false, eqeqeq: false, shadow: true, devel: true, evil: true */ $.extend($.ui, { datepicker: { version: "@VERSION" } }); var PROP_NAME = 'datepicker'; @@ -132,16 +133,18 @@ $.extend(Datepicker.prototype, { }, /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ setDefaults: function(settings) { extendRemove(this._defaults, settings || {}); return this; }, /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ _attachDatepicker: function(target, settings) { // check for settings on the control itself - in namespace 'date:' var inlineSettings = null; @@ -173,7 +176,7 @@ $.extend(Datepicker.prototype, { /* Create a new instance object. */ _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, '\\\\$1'); // escape jQuery meta chars return {id: id, input: target, // associated target selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection drawMonth: 0, drawYear: 0, // month being drawn @@ -228,7 +231,7 @@ $.extend(Datepicker.prototype, { $('').addClass(this._triggerClass). attr({ src: buttonImage, alt: buttonText, title: buttonText }) : $('').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('').attr( + html(!buttonImage ? buttonText : $('').attr( { src:buttonImage, alt:buttonText, title:buttonText }))); input[isRTL ? 'before' : 'after'](inst.trigger); inst.trigger.click(function() { @@ -295,14 +298,15 @@ $.extend(Datepicker.prototype, { }, /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ _dialogDatepicker: function(input, date, onSelect, settings, pos) { var inst = this._dialogInst; // internal instance if (!inst) { @@ -343,7 +347,8 @@ $.extend(Datepicker.prototype, { }, /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _destroyDatepicker: function(target) { var $target = $(target); var inst = $.data(target, PROP_NAME); @@ -365,7 +370,8 @@ $.extend(Datepicker.prototype, { }, /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _enableDatepicker: function(target) { var $target = $(target); var inst = $.data(target, PROP_NAME); @@ -390,7 +396,8 @@ $.extend(Datepicker.prototype, { }, /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _disableDatepicker: function(target) { var $target = $(target); var inst = $.data(target, PROP_NAME); @@ -416,8 +423,9 @@ $.extend(Datepicker.prototype, { }, /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ _isDisabledDatepicker: function(target) { if (!target) { return false; @@ -430,9 +438,10 @@ $.extend(Datepicker.prototype, { }, /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ _getInst: function(target) { try { return $.data(target, PROP_NAME); @@ -443,13 +452,14 @@ $.extend(Datepicker.prototype, { }, /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also 'all' for all instance settings or + * 'defaults' for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ _optionDatepicker: function(target, name, value) { var inst = this._getInst(target); if (arguments.length == 2 && typeof name == 'string') { @@ -471,9 +481,9 @@ $.extend(Datepicker.prototype, { var maxDate = this._getMinMaxDate(inst, 'max'); extendRemove(inst.settings, settings); // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) inst.settings.minDate = this._formatDate(inst, minDate); - if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) inst.settings.maxDate = this._formatDate(inst, maxDate); this._attachments($(target), inst); this._autoSize(inst); @@ -489,7 +499,8 @@ $.extend(Datepicker.prototype, { }, /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ + * @param target element - the target input field or division or span + */ _refreshDatepicker: function(target) { var inst = this._getInst(target); if (inst) { @@ -498,8 +509,9 @@ $.extend(Datepicker.prototype, { }, /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ + * @param target element - the target input field or division or span + * @param date Date - the new date + */ _setDateDatepicker: function(target, date) { var inst = this._getInst(target); if (inst) { @@ -510,9 +522,10 @@ $.extend(Datepicker.prototype, { }, /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ _getDateDatepicker: function(target, noDefault) { var inst = this._getInst(target); if (inst && !inst.inline) @@ -545,7 +558,6 @@ $.extend(Datepicker.prototype, { else $.datepicker._hideDatepicker(); return false; // don't submit the form - break; // select the value on enter case 27: $.datepicker._hideDatepicker(); break; // hide on escape case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? @@ -602,7 +614,7 @@ $.extend(Datepicker.prototype, { var inst = $.datepicker._getInst(event.target); if ($.datepicker._get(inst, 'constrainInput')) { var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + var chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); } }, @@ -629,9 +641,10 @@ $.extend(Datepicker.prototype, { }, /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ _showDatepicker: function(input) { input = input.target || input; if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger @@ -698,7 +711,6 @@ $.extend(Datepicker.prototype, { /* Generate the date picker content. */ _updateDatepicker: function(inst) { this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - var borders = $.datepicker._getBorders(inst.dpDiv); instActive = inst; // for delegate hover events inst.dpDiv.empty().append(this._generateHTML(inst)); this._attachHandlers(inst); @@ -732,8 +744,9 @@ $.extend(Datepicker.prototype, { }, /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ + * @param elem (jQuery object) the element of interest + * @return (number[2]) the left and top borders + */ _getBorders: function(elem) { var convert = function(value) { return {thin: 1, medium: 2, thick: 3}[value] || value; @@ -776,7 +789,8 @@ $.extend(Datepicker.prototype, { }, /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ + * @param input element - the input field attached to the date picker + */ _hideDatepicker: function(input) { var inst = this._curInst; if (!inst || (input && inst != $.data(input, PROP_NAME))) @@ -827,7 +841,7 @@ $.extend(Datepicker.prototype, { inst = $.datepicker._getInst($target[0]); if ( ( ( $target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && + $target.parents('#' + $.datepicker._mainDivId).length === 0 && !$target.hasClass($.datepicker.markerClassName) && !$target.closest("." + $.datepicker._triggerClass).length && $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || @@ -895,7 +909,6 @@ $.extend(Datepicker.prototype, { /* Erase the input field and hide the date picker. */ _clearDate: function(id) { var target = $(id); - var inst = this._getInst(target[0]); this._selectDate(target, ''); }, @@ -935,16 +948,18 @@ $.extend(Datepicker.prototype, { }, /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ noWeekends: function(date) { var day = date.getDay(); return [(day > 0 && day < 6), '']; }, /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ iso8601Week: function(date) { var checkDate = new Date(date.getTime()); // Find Thursday of this week starting on Monday @@ -956,22 +971,23 @@ $.extend(Datepicker.prototype, { }, /* Parse a string value into a date object. - See formatDate below for the possible formats. - - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ parseDate: function (format, value, settings) { if (format == null || value == null) throw 'Invalid arguments'; value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') + if (value === '') return null; var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : @@ -1126,32 +1142,33 @@ $.extend(Datepicker.prototype, { Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote - - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * '...' - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ formatDate: function (format, date, settings) { if (!date) return ''; @@ -1321,7 +1338,7 @@ $.extend(Datepicker.prototype, { var year = date.getFullYear(); var month = date.getMonth(); var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; var matches = pattern.exec(offset); while (matches) { switch (matches[2] || 'd') { @@ -1355,11 +1372,12 @@ $.extend(Datepicker.prototype, { }, /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ _daylightSavingAdjust: function(date) { if (!date) return null; date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); @@ -1385,7 +1403,7 @@ $.extend(Datepicker.prototype, { /* Retrieve the date(s) directly. */ _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === '') ? null : this._daylightSavingAdjust(new Date( inst.currentYear, inst.currentMonth, inst.currentDay))); return startDate; @@ -1494,14 +1512,12 @@ $.extend(Datepicker.prototype, { firstDay = (isNaN(firstDay) ? 0 : firstDay); var showWeek = this._get(inst, 'showWeek'); var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); var dayNamesMin = this._get(inst, 'dayNamesMin'); var monthNames = this._get(inst, 'monthNames'); var monthNamesShort = this._get(inst, 'monthNamesShort'); var beforeShowDay = this._get(inst, 'beforeShowDay'); var showOtherMonths = this._get(inst, 'showOtherMonths'); var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; var defaultDate = this._getDefaultDate(inst); var html = ''; for (var row = 0; row < numMonths[0]; row++) { @@ -1524,8 +1540,8 @@ $.extend(Datepicker.prototype, { calender += '">'; } calender += '
' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : '') + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers '
' + @@ -1631,8 +1647,8 @@ $.extend(Datepicker.prototype, { var years = this._get(inst, 'yearRange').split(':'); var thisYear = new Date().getFullYear(); var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : parseInt(value, 10))); return (isNaN(year) ? thisYear : year); }; @@ -1780,14 +1796,14 @@ function bindHover(dpDiv) { function extendRemove(target, props) { $.extend(target, props); for (var name in props) - if (props[name] == null || props[name] == undefined) + if (props[name] == null) target[name] = props[name]; return target; -}; +} /* Invoke the datepicker functionality. @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality + Object - settings for attaching new datepicker functionality @return jQuery object */ $.fn.datepicker = function(options){ -- cgit v1.2.3