Large diffs are not rendered by default.

@@ -1,3 +1,10 @@
// The implement of events is completely changing therefore these tests are no longer directly
// relevant. Leaving them around commented out so we can ensure the functionality is replicated.
// For example:
// TODO: In the old implementation the Enter key select's today's date when the <input> has
// focus and is empty. Do we want to replicate this behavior in the rewrite?
/*
(function( $ ) {
module( "datepicker: events" );
@@ -18,12 +25,6 @@ test( "select", function() {
expect( 0 );
});
// The implement of events is completely changing therefore these tests are no longer directly
// relevant. Leaving them around commented out so we can ensure the functionality is replicated.
// For example:
// TODO: In the old implementation the Enter key select's today's date when the <input> has
// focus and is empty. Do we want to replicate this behavior in the rewrite?
/*
var selectedThis = null,
selectedDate = null,
selectedInst = null;
@@ -40,110 +41,110 @@ function callback2(year, month, inst) {
selectedInst = inst;
}
test("events", function() {
test( "events", function() {
expect( 26 );
var dateStr, newMonthYear, inp2,
inp = TestHelpers.datepicker.init("#inp", {onSelect: callback}),
inp = TestHelpers.datepicker.init( "#inp", {onSelect: callback}),
date = new Date();
// onSelect
inp.val("").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
equal(selectedThis, inp[0], "Callback selected this");
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback selected inst");
equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
"Callback selected date");
inp.val("").datepicker("show").
simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
inp.val( "" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ENTER});
equal(selectedThis, inp[0], "Callback selected this" );
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback selected inst" );
equal(selectedDate, $.datepicker.formatDate( "mm/dd/yy", date),
"Callback selected date" );
inp.val( "" ).datepicker( "show" ).
simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
simulate( "keydown", {keyCode: $.ui.keyCode.ENTER});
date.setDate(date.getDate() + 7);
equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
"Callback selected date - ctrl+down");
inp.val("").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
"Callback selected date - esc");
equal(selectedDate, $.datepicker.formatDate( "mm/dd/yy", date),
"Callback selected date - ctrl+down" );
inp.val( "" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedDate, $.datepicker.formatDate( "mm/dd/yy", date),
"Callback selected date - esc" );
dateStr = "02/04/2008";
inp.val(dateStr).datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
inp.val(dateStr).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ENTER});
equal(dateStr, selectedDate,
"onSelect is called after enter keydown");
"onSelect is called after enter keydown" );
// onChangeMonthYear
inp.datepicker("option", {onChangeMonthYear: callback2, onSelect: null}).
val("").datepicker("show");
inp.datepicker( "option", {onChangeMonthYear: callback2, onSelect: null}).
val( "" ).datepicker( "show" );
newMonthYear = function(date) {
return date.getFullYear() + "/" + (date.getMonth() + 1);
};
date = new Date();
date.setDate(1);
inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
inp.simulate( "keydown", {keyCode: $.ui.keyCode.PAGE_UP});
date.setMonth(date.getMonth() - 1);
equal(selectedThis, inp[0], "Callback change month/year this");
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback change month/year inst");
equal(selectedThis, inp[0], "Callback change month/year this" );
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback change month/year inst" );
equal(selectedDate, newMonthYear(date),
"Callback change month/year date - pgup");
inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
"Callback change month/year date - pgup" );
inp.simulate( "keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
date.setMonth(date.getMonth() + 1);
equal(selectedDate, newMonthYear(date),
"Callback change month/year date - pgdn");
inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
"Callback change month/year date - pgdn" );
inp.simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
date.setFullYear(date.getFullYear() - 1);
equal(selectedDate, newMonthYear(date),
"Callback change month/year date - ctrl+pgup");
inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME});
"Callback change month/year date - ctrl+pgup" );
inp.simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME});
date.setFullYear(date.getFullYear() + 1);
equal(selectedDate, newMonthYear(date),
"Callback change month/year date - ctrl+home");
inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
"Callback change month/year date - ctrl+home" );
inp.simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
date.setFullYear(date.getFullYear() + 1);
equal(selectedDate, newMonthYear(date),
"Callback change month/year date - ctrl+pgdn");
inp.datepicker("setDate", new Date(2007, 1 - 1, 26));
equal(selectedDate, "2007/1", "Callback change month/year date - setDate");
"Callback change month/year date - ctrl+pgdn" );
inp.datepicker( "setDate", new Date(2007, 1 - 1, 26));
equal(selectedDate, "2007/1", "Callback change month/year date - setDate" );
selectedDate = null;
inp.datepicker("setDate", new Date(2007, 1 - 1, 12));
ok(selectedDate == null, "Callback change month/year date - setDate no change");
inp.datepicker( "setDate", new Date(2007, 1 - 1, 12));
ok(selectedDate == null, "Callback change month/year date - setDate no change" );
// onChangeMonthYear step by 2
inp.datepicker("option", {stepMonths: 2}).
datepicker("hide").val("").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
inp.datepicker( "option", {stepMonths: 2}).
datepicker( "hide" ).val( "" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.PAGE_UP});
date.setMonth(date.getMonth() - 14);
equal(selectedDate, newMonthYear(date),
"Callback change month/year by 2 date - pgup");
inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
"Callback change month/year by 2 date - pgup" );
inp.simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
date.setMonth(date.getMonth() - 12);
equal(selectedDate, newMonthYear(date),
"Callback change month/year by 2 date - ctrl+pgup");
inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
"Callback change month/year by 2 date - ctrl+pgup" );
inp.simulate( "keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
date.setMonth(date.getMonth() + 2);
equal(selectedDate, newMonthYear(date),
"Callback change month/year by 2 date - pgdn");
inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
"Callback change month/year by 2 date - pgdn" );
inp.simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
date.setMonth(date.getMonth() + 12);
equal(selectedDate, newMonthYear(date),
"Callback change month/year by 2 date - ctrl+pgdn");
"Callback change month/year by 2 date - ctrl+pgdn" );
// onClose
inp.datepicker("option", {onClose: callback, onChangeMonthYear: null, stepMonths: 1}).
val("").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedThis, inp[0], "Callback close this");
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback close inst");
equal(selectedDate, "", "Callback close date - esc");
inp.val("").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", new Date()),
"Callback close date - enter");
inp.val("02/04/2008").datepicker("show").
simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedDate, "02/04/2008", "Callback close date - preset");
inp.val("02/04/2008").datepicker("show").
simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
equal(selectedDate, "", "Callback close date - ctrl+end");
inp.datepicker( "option", {onClose: callback, onChangeMonthYear: null, stepMonths: 1}).
val( "" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedThis, inp[0], "Callback close this" );
equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback close inst" );
equal(selectedDate, "", "Callback close date - esc" );
inp.val( "" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ENTER});
equal(selectedDate, $.datepicker.formatDate( "mm/dd/yy", new Date()),
"Callback close date - enter" );
inp.val( "02/04/2008" ).datepicker( "show" ).
simulate( "keydown", {keyCode: $.ui.keyCode.ESCAPE});
equal(selectedDate, "02/04/2008", "Callback close date - preset" );
inp.val( "02/04/2008" ).datepicker( "show" ).
simulate( "keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
equal(selectedDate, "", "Callback close date - ctrl+end" );
inp2 = TestHelpers.datepicker.init("#inp2");
inp2.datepicker().datepicker("option", {onClose: callback}).datepicker("show");
inp.datepicker("show");
equal(selectedThis, inp2[0], "Callback close this");
inp2 = TestHelpers.datepicker.init( "#inp2" );
inp2.datepicker().datepicker( "option", {onClose: callback}).datepicker( "show" );
inp.datepicker( "show" );
equal(selectedThis, inp2[0], "Callback close this" );
});
*/
})( jQuery );
*/
@@ -51,7 +51,7 @@ test( "enable / disable", function() {
test( "widget", function() {
expect( 1 );
var actual = $( "#datepicker" ).datepicker().datepicker( "widget" );
deepEqual( $("body > .ui-front" )[ 0 ], actual[ 0 ] );
deepEqual( $( "body > .ui-front" )[ 0 ], actual[ 0 ] );
actual.remove();
});

Large diffs are not rendered by default.

@@ -1,18 +1,18 @@
TestHelpers.datepicker = {
addMonths: function(date, offset) {
var maxDay = 32 - new Date(date.getFullYear(), date.getMonth() + offset, 32).getDate();
date.setDate(Math.min(date.getDate(), maxDay));
date.setMonth(date.getMonth() + offset);
addMonths: function( date, offset ) {
var maxDay = 32 - new Date( date.getFullYear(), date.getMonth() + offset, 32 ).getDate();
date.setDate( Math.min( date.getDate(), maxDay ) );
date.setMonth( date.getMonth() + offset );
return date;
},
equalsDate: function(d1, d2, message) {
if (!d1 || !d2) {
ok(false, message + " - missing date");
equalsDate: function( d1, d2, message ) {
if ( !d1 || !d2 ) {
ok( false, message + " - missing date" );
return;
}
d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
d2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
equal(d1.toString(), d2.toString(), message);
d1 = new Date( d1.getFullYear(), d1.getMonth(), d1.getDate() );
d2 = new Date( d2.getFullYear(), d2.getMonth(), d2.getDate() );
equal( d1.toString(), d2.toString(), message );
},
init: function( id, options ) {
options = $.extend( { show: false }, options || {} );
@@ -52,6 +52,7 @@ return $.widget( "ui.datepicker", {
open: null,
select: null
},

_create: function() {
this.options.dateFormat = this.options.dateFormat || { date: "short" };
this.date = $.date( null, this.options.dateFormat );
@@ -103,6 +104,7 @@ return $.widget( "ui.datepicker", {

this._createTmpl();
},

_handleKeydown: function( event ) {
if ( jQuery.inArray( event.keyCode, [ 13, 33, 34, 35, 36, 37, 38, 39, 40 ] ) === -1 ) {
//only interested navigation keys
@@ -154,7 +156,7 @@ return $.widget( "ui.datepicker", {
}
else {
newId = this.id + "-" + this.date.day();
newCell = $("#" + newId);
newCell = $( "#" + newId );

// TODO unnecessary optimization? is it really needed?
if ( !newCell.length ) {
@@ -166,6 +168,7 @@ return $.widget( "ui.datepicker", {
newCell.children( "a" ).addClass( "ui-state-focus" );
}
},

_createPicker: function() {
this.picker = $( "<div>" )
.addClass( "ui-front" )
@@ -199,10 +202,10 @@ return $.widget( "ui.datepicker", {
case $.ui.keyCode.DOWN:
case $.ui.keyCode.UP:
clearTimeout( this.closeTimer );
this._delay(function() {
this._delay( function() {
this.open( event );
this.grid.focus( 1 );
}, 1);
}, 1 );
break;
case $.ui.keyCode.HOME:
if ( event.ctrlKey ) {
@@ -251,7 +254,7 @@ return $.widget( "ui.datepicker", {
}
this._delay( function() {
suppressExpandOnFocus = false;
}, 100);
}, 100 );
},
blur: function() {
suppressExpandOnFocus = false;
@@ -265,7 +268,7 @@ return $.widget( "ui.datepicker", {
// also allows tabbing inside the calendar without it closing
this.closeTimer = this._delay( function() {
this.close( event );
}, 150);
}, 150 );
},
focusin: function() {
clearTimeout( this.closeTimer );
@@ -290,6 +293,7 @@ return $.widget( "ui.datepicker", {
}
});
},

_appendTo: function() {
var element = this.options.appendTo;

@@ -304,7 +308,7 @@ return $.widget( "ui.datepicker", {
}

if ( !element.length ) {
element = this.document[0].body;
element = this.document[ 0 ].body;
}

return element;
@@ -357,10 +361,10 @@ return $.widget( "ui.datepicker", {

html += "<div class='ui-datepicker-group'>" +
"<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix " + headerClass + "'>";
if ( months[i].first ) {
if ( months[ i ].first ) {
html += this._buildPreviousLink();
}
if ( months[i].last ) {
if ( months[ i ].last ) {
html += this._buildNextLink();
}

@@ -374,42 +378,51 @@ return $.widget( "ui.datepicker", {
html += this._buildButtons();

this.date = currentDate;

return html;
},

_buildHeader: function() {
return "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix ui-corner-all'>" +
this._buildPreviousLink() +
this._buildNextLink() +
this._buildTitlebar() +
"</div>";
},

_buildPreviousLink: function() {
var labels = Globalize.translate( "datepicker" );

return "<button class='ui-datepicker-prev ui-corner-all' " +
"title='" + labels.prevText + "'>" +
"<span class='ui-icon ui-icon-circle-triangle-w'>" +
labels.prevText +
"</span>" +
"</button>";
},

_buildNextLink: function() {
var labels = Globalize.translate( "datepicker" );

return "<button class='ui-datepicker-next ui-corner-all' " +
"title='" + labels.nextText + "'>" +
"<span class='ui-icon ui-icon-circle-triangle-e'>" +
labels.nextText +
"</span>" +
"</button>";
},

_buildTitlebar: function() {
var labels = Globalize.translate( "datepicker" );

return "<div role='header' id='" + this.id + "-title'>" +
"<div id='" + this.id + "-month-lbl' class='ui-datepicker-title'>" +
this._buildTitle() +
"</div>" +
"<span class='ui-helper-hidden-accessible'>, " + labels.datePickerRole + "</span>" +
"</div>";
},

_buildTitle: function() {
return "<span class='ui-datepicker-month'>" +
this.date.monthName() +
@@ -418,13 +431,15 @@ return $.widget( "ui.datepicker", {
this.date.year() +
"</span>";
},

_buildGrid: function() {
return "<table class='ui-datepicker-calendar' role='grid' aria-readonly='true' " +
"aria-labelledby='" + this.id + "-month-lbl' tabindex='0' aria-activedescendant='" + this.id + "-" + this.date.day() + "'>" +
this._buildGridHeading() +
this._buildGridBody() +
"</table>";
},

_buildGridHeading: function() {
var cells = "",
i = 0,
@@ -436,27 +451,33 @@ return $.widget( "ui.datepicker", {
for ( i; i < this.date.weekdays().length; i++ ) {
cells += this._buildGridHeaderCell( this.date.weekdays()[i] );
}

return "<thead role='presentation'>" +
"<tr role='row'>" + cells + "</tr>" +
"</thead>";
},

_buildGridHeaderCell: function( day ) {
return "<th role='columnheader' abbr='" + day.fullname + "' aria-label='" + day.fullname + "'>" +
"<span title='" + day.fullname + "'>" +
day.shortname +
"</span>" +
"</th>";
},

_buildGridBody: function() {
// this.date.days() is not cached, and it has O(n^2) complexity. It is run O(n) times. So, it equals O(n^3). Not good at all. Caching.
var days = this.date.days(),
i = 0,
rows = "";

for ( i; i < days.length; i++ ) {
rows += this._buildWeekRow( days[i] );
rows += this._buildWeekRow( days[ i ] );
}

return "<tbody role='presentation'>" + rows + "</tbody>";
},

_buildWeekRow: function( week ) {
var cells = "",
i = 0;
@@ -469,6 +490,7 @@ return $.widget( "ui.datepicker", {
}
return "<tr role='row'>" + cells + "</tr>";
},

_buildDayCell: function( day ) {
var contents = "",
idAttribute = day.render ? ( "id=" + this.id + "-" + day.date ) : "",
@@ -487,6 +509,7 @@ return $.widget( "ui.datepicker", {
contents +
"</td>";
},

_buildDayLink: function( day ) {
var link,
classes = [ "ui-state-default" ],
@@ -510,10 +533,13 @@ return $.widget( "ui.datepicker", {
if ( day.today ) {
link += "<span class='ui-helper-hidden-accessible'>, " + labels.currentText + "</span>";
}

return link;
},

_buildDayDisplay: function( day ) {
var classes = [];

if ( day.current ) {
classes.push( "ui-state-active" );
}
@@ -524,20 +550,23 @@ return $.widget( "ui.datepicker", {
classes.push( day.extraClasses.split( " " ) );
}

return "<span class='" + classes.join( "" ) + "'>" +
day.date + "</span>";
return "<span class='" + classes.join( "" ) + "'>" + day.date + "</span>";
},

_buildButtons: function() {
var labels = Globalize.translate( "datepicker" );

return "<div class='ui-datepicker-buttonpane ui-widget-content'>" +
"<button class='ui-datepicker-current'>" + labels.currentText + "</button>" +
"<button class='ui-datepicker-close'>" + labels.closeText + "</button>" +
"</div>";
},

_focusTrigger: function() {
suppressExpandOnFocus = true;
this.element.focus();
},

// Refreshing the entire datepicker during interaction confuses screen readers, specifically
// because the grid heading is marked up as a live region and will often not update if it's
// destroyed and recreated instead of just having its text change. Additionally, interacting
@@ -554,6 +583,7 @@ return $.widget( "ui.datepicker", {
this._refreshMultiplePicker();
}
},

_refreshMultiplePicker: function() {
var i = 0;

@@ -568,6 +598,7 @@ return $.widget( "ui.datepicker", {
// to maintain the currently focused grid and base queries like this off of it.
$( this.picker ).find( ".ui-state-focus" ).not( ":first" ).removeClass( "ui-state-focus" );
},

open: function( event ) {
if ( this.inline || this.isOpen ) {
return;
@@ -598,6 +629,7 @@ return $.widget( "ui.datepicker", {

this._trigger( "open", event );
},

close: function( event ) {
if ( this.inline ) {
return;
@@ -611,16 +643,19 @@ return $.widget( "ui.datepicker", {
this.isOpen = false;
this._trigger( "close", event );
},

_setHiddenPicker: function() {
this.picker
.attr( "aria-hidden", "true" )
.attr( "aria-expanded", "false" );
},

_buildPosition: function() {
return $.extend( {}, {
of: this.element
}, this.options.position );
},

select: function( event, time ) {
this.date.setTime( time ).select();
this.refresh();
@@ -634,33 +669,39 @@ return $.widget( "ui.datepicker", {
date: this.date.format()
});
},

_value: function( value ) {
this.date.setTime( value ).select();
if ( !this.inline ) {
this.element.val( this.date.format() );
}
this.refresh();
},

value: function( value ) {
if ( arguments.length ) {
this._value( value );
} else {
return this.isValid() ? this.date.format() : this.element.val();
}
},

valueAsDate: function( value ) {
if ( arguments.length ) {
this._value( value );
} else {
return this.isValid() ? this.date.date() : null;
}
},

isValid: function() {
if ( this.inline ) {
return true;
}

return Globalize.parseDate( this.element.val(), this.options.dateFormat ) !== null;
},

_destroy: function() {
if ( this.inline ) {
this.picker.empty();
@@ -671,9 +712,11 @@ return $.widget( "ui.datepicker", {
.removeAttr( "aria-owns" );
}
},

widget: function() {
return this.picker;
},

_setOption: function( key, value ) {
this._super( key, value );