Calendar: Add min and max option.

Improve render day cell mechanism.
This commit is contained in:
Felix Nagel 2014-06-04 19:07:23 +02:00 committed by Scott González
parent 510ba08cff
commit f88a06352a
9 changed files with 273 additions and 63 deletions

View File

@ -16,7 +16,14 @@
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
$( "#calendar" ).calendar({ minDate: -20, maxDate: "+1M +10D" });
var now = new Date(),
dateMin = new Date( now.getFullYear(), now.getMonth(), now.getDay() + 1 ),
dateMax = new Date( now.getFullYear(), now.getMonth(), now.getDay() + 8 );
$( "#calendar" ).calendar({
min: dateMin,
max: dateMax
});
});
</script>
</head>
@ -25,7 +32,7 @@
<div id="calendar"></div>
<div class="demo-description">
<p>Restrict the range of selectable dates with the <code>minDate</code> and <code>maxDate</code> options. Set the beginning and end dates as actual dates (new Date(2009, 1 - 1, 26)), as a numeric offset from today (-20), or as a string of periods and units ('+1M +10D'). For the last, use 'D' for days, 'W' for weeks, 'M' for months, or 'Y' for years.</p>
<p>Restrict the range of selectable dates with the <code>min</code> and <code>max</code> options. Set the beginning and end dates as actual dates (new Date(2009, 1 - 1, 26)).</p>
</div>
</body>
</html>

View File

@ -3,6 +3,8 @@ TestHelpers.commonWidgetTests( "calendar", {
dateFormat: { date: "short" },
disabled: false,
eachDay: $.noop,
max: null,
min: null,
numberOfMonths: 1,
showWeek: false,
value: null,

View File

@ -49,9 +49,10 @@ test( "value", function() {
});
test( "valueAsDate", function() {
expect( 4 );
expect( 11 );
var element = $( "#calendar" ).calendar(),
var minDate, maxDate, dateAndTimeToSet, dateAndTimeClone,
element = $( "#calendar" ).calendar(),
date1 = new Date( 2008, 6 - 1, 4 ),
date2 = new Date();
@ -66,6 +67,68 @@ test( "valueAsDate", function() {
element.calendar( "valueAsDate", date1 );
TestHelpers.calendar.equalsDate(element.calendar( "valueAsDate" ), date1, "Set date - 2008-06-04" );
// With minimum/maximum
element = $( "#calendar" ).calendar();
date1 = new Date( 2008, 1 - 1, 4 );
date2 = new Date( 2008, 6 - 1, 4 );
minDate = new Date( 2008, 2 - 1, 29 );
maxDate = new Date( 2008, 3 - 1, 28 );
element
.calendar( "option", { min: minDate } )
.calendar( "valueAsDate", date2 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date2, "Set date min/max - value > min"
);
element.calendar( "valueAsDate", date1 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date2,
"Set date min/max - value < min"
);
element
.calendar( "option", { max: maxDate, min: null } )
.calendar( "valueAsDate", date1 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date1,
"Set date min/max - value < max"
);
element.calendar( "valueAsDate", date2 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date1,
"Set date min/max - value > max"
);
element
.calendar( "option", { min: minDate } )
.calendar( "valueAsDate", date1 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date1,
"Set date min/max - value < min"
);
element.calendar( "valueAsDate", date2 );
TestHelpers.calendar.equalsDate(
element.calendar( "valueAsDate" ),
date1, "Set date min/max - value > max"
);
dateAndTimeToSet = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
dateAndTimeClone = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
element.calendar( "valueAsDate", dateAndTimeToSet );
equal(
dateAndTimeToSet.getTime(),
dateAndTimeClone.getTime(),
"Date object passed should not be changed by valueAsDate"
);
});
})( jQuery );

View File

@ -83,8 +83,48 @@ test( "showWeek", function() {
});
test( "min / max", function() {
expect( 0 );
});
expect( 7 );
// With existing date
var element = $( "#calendar" ).calendar(),
minDate = new Date( 2008, 2 - 1, 29 ),
maxDate = new Date( 2008, 12 - 1, 7 );
element
.calendar( "option", { min: minDate } )
.calendar( "value", "6/4/08" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min" );
element
.calendar( "option", { min: minDate } )
.calendar( "value", "1/4/08" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < min" );
element
.calendar( "option", { min: null } )
.calendar( "value", "6/4/08" )
.calendar( "option", { max: maxDate } );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < max" );
element
.calendar( "option", { max: maxDate } )
.calendar( "value", "1/4/09" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - setDate > max" );
element
.calendar( "option", { min: minDate, max: maxDate } )
.calendar( "value", "1/4/08" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < min" );
element
.calendar( "option", { min: minDate, max: maxDate } )
.calendar( "value", "6/4/08" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min, < max" );
element
.calendar( "option", { min: minDate, max: maxDate } )
.calendar( "value", "1/4/09" );
TestHelpers.calendar.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > max" );});
/*
// TODO: Move this to $.date, Globalize or calendar widget

View File

@ -4,6 +4,8 @@ TestHelpers.commonWidgetTests( "datepicker", {
dateFormat: { date: "short" },
disabled: false,
eachDay: $.noop,
max: null,
min: null,
numberOfMonths: 1,
position: {
my: "left top",

View File

@ -58,11 +58,13 @@ test( "value", function() {
});
test( "valueAsDate", function() {
expect( 6 );
expect( 13 );
var input = TestHelpers.datepicker.init( "#datepicker" ),
var minDate, maxDate, dateAndTimeToSet, dateAndTimeClone,
input = TestHelpers.datepicker.init( "#datepicker" ),
picker = input.datepicker( "widget" ),
date1 = new Date( 2008, 6 - 1, 4 );
date1 = new Date( 2008, 6 - 1, 4 ),
date2 = new Date();
input.datepicker( "valueAsDate", new Date( 2014, 0, 1 ) );
equal( input.val(), "1/1/14", "Input's value set" );
@ -78,6 +80,36 @@ test( "valueAsDate", function() {
strictEqual( input.datepicker( "valueAsDate" ), null, "Set date - default" );
input.datepicker( "valueAsDate", date1 );
TestHelpers.datepicker.equalsDate( input.datepicker( "valueAsDate" ), date1, "Set date - 2008-06-04" );
// With minimum/maximum
input = TestHelpers.datepicker.init( "#datepicker" );
date1 = new Date( 2008, 1 - 1, 4 );
date2 = new Date( 2008, 6 - 1, 4 );
minDate = new Date( 2008, 2 - 1, 29 );
maxDate = new Date( 2008, 3 - 1, 28 );
input.val( "" ).datepicker( "option", { min: minDate } ).datepicker( "valueAsDate", date2 );
TestHelpers.datepicker.equalsDate( input.datepicker( "valueAsDate" ), date2, "Set date min/max - value > min" );
input.datepicker( "valueAsDate", date1 );
TestHelpers.datepicker.equalsDate( input.datepicker( "valueAsDate" ), date2, "Set date min/max - value < min" );
input.val( "" ).datepicker( "option", { max: maxDate, min: null } ).datepicker( "valueAsDate", date1 );
TestHelpers.datepicker.equalsDate( input.datepicker( "valueAsDate" ), date1, "Set date min/max - value < max" );
input.datepicker( "valueAsDate", date2 );
TestHelpers.datepicker.equalsDate( input.datepicker( "valueAsDate" ), date1, "Set date min/max - value > max" );
input.val( "" ).datepicker( "option", { min: minDate } ).datepicker( "valueAsDate", date1 );
ok( input.datepicker( "valueAsDate" ) === null, "Set date min/max - value < min" );
input.datepicker( "valueAsDate", date2 );
ok( input.datepicker( "valueAsDate" ) === null, "Set date min/max - value > max" );
dateAndTimeToSet = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
dateAndTimeClone = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
input.datepicker( "valueAsDate", dateAndTimeToSet );
equal( dateAndTimeToSet.getTime(), dateAndTimeClone.getTime(), "Date object passed should not be changed by valueAsDate" );
});
test( "isValid", function() {

View File

@ -149,6 +149,42 @@ test( "showWeek", function() {
input.datepicker( "option", "showWeek", true );
equal( container.find( "thead th" ).length, 8, "supports changing option after init" );
});
test( "min / max", function() {
expect( 14 );
var inp = TestHelpers.datepicker.init( "#datepicker" ),
minDate = new Date( 2008, 2 - 1, 29 ),
maxDate = new Date( 2008, 12 - 1, 7 );
inp.val( "6/4/08" ).datepicker( "option", { min: minDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min" );
ok( inp.datepicker( "isValid" ) );
inp.datepicker( "option", { min: null } ).val( "1/4/08" ).datepicker( "option", { min: minDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2008, 1 - 1, 4 ), "Min/max - value < min" );
ok( !inp.datepicker( "isValid" ) );
inp.datepicker( "option", { min: null } ).val( "6/4/08" ).datepicker( "option", { max: maxDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < max" );
ok( inp.datepicker( "isValid" ) );
inp.datepicker( "option", { max: null } ).val( "1/4/09" ).datepicker( "option", { max: maxDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2009, 1 - 1, 4 ), "Min/max - setDate > max" );
ok( !inp.datepicker( "isValid" ) );
inp.datepicker( "option", { max: null } ).val( "1/4/08" ).datepicker( "option", { min: minDate, max: maxDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2008, 1 - 1, 4 ), "Min/max - value < min" );
ok( !inp.datepicker( "isValid" ) );
inp.datepicker( "option", { max: null } ).val( "6/4/08" ).datepicker( "option", { min: minDate, max: maxDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min, < max" );
ok( inp.datepicker( "isValid" ) );
inp.datepicker( "option", { max: null } ).val( "1/4/09" ).datepicker( "option", { min: minDate, max: maxDate } );
TestHelpers.datepicker.equalsDate( inp.datepicker( "valueAsDate" ), new Date( 2009, 1 - 1, 4 ), "Min/max - value > max" );
ok( !inp.datepicker( "isValid" ) );
});
test( "Stop datepicker from appearing with beforeOpen event handler", function() {
expect( 3 );

View File

@ -31,6 +31,8 @@ return $.widget( "ui.calendar", {
options: {
dateFormat: { date: "short" },
eachDay: $.noop,
max: null,
min: null,
numberOfMonths: 1,
showWeek: false,
value: null,
@ -308,38 +310,33 @@ return $.widget( "ui.calendar", {
},
_buildDayCell: function( day ) {
var contents = "",
var content = "",
attributes = [
"aria-selected" + ( day.current ? "\"true\"" : "\"false\"" )
];
"role='gridcell'",
"aria-selected='" + day.current ? true : false + "'"
],
selectable = ( day.selectable && this._isValid( new Date( day.timestamp ) ) );
if ( day.render ) {
attributes.push( "id=\"" + this.id + "-" + day.date + "\"" );
}
attributes.push( "id='" + this.id + "-" + day.date + "'" );
if ( day.selectable ) {
attributes.push( "aria-disabled=\"true\"" );
}
if ( day.render ) {
if ( day.selectable ) {
contents = this._buildDayLink( day );
} else {
contents = this._buildDayDisplay( day );
if ( !selectable ) {
attributes.push( "aria-disabled='true'" );
attributes.push( "class='ui-state-disabled'" );
}
content = this._buildDayElement( day, selectable );
}
return "<td role='gridcell' " + attributes.join( " " ) + ">" +
contents +
"</td>";
return "<td " + attributes.join( " " ) + ">" + content + "</td>";
},
_buildDayLink: function( day ) {
var link,
classes = [ "ui-state-default" ],
labels = Globalize.translate( "datepicker" );
_buildDayElement: function( day, selectable ) {
var classes = [ "ui-state-default" ],
labels = Globalize.translate( "datepicker" ),
content = "";
if ( day === this.date ) {
if ( day === this.date && selectable ) {
classes.push( "ui-state-focus" );
}
if ( day.current ) {
@ -353,30 +350,18 @@ return $.widget( "ui.calendar", {
classes.push( day.extraClasses.split( " " ) );
}
link = "<a href='#' tabindex='-1' data-timestamp='" + day.timestamp +
"' class='" + classes.join( " " ) + "'>" + day.date + "</a>";
classes = " class='" + classes.join( " " ) + "'";
if ( selectable ) {
content = "<a href='#' tabindex='-1' data-timestamp='" + day.timestamp + "'" + classes + ">" + day.date + "</a>";
} else {
content = "<span" + classes + ">" + day.date + "</span>";
}
if ( day.today ) {
link += "<span class='ui-helper-hidden-accessible'>, " +
labels.currentText + "</span>";
content += "<span class='ui-helper-hidden-accessible'>, " + labels.currentText + "</span>";
}
return link;
},
_buildDayDisplay: function( day ) {
var classes = [];
if ( day.current ) {
classes.push( "ui-state-active" );
}
if ( day.today ) {
classes.push( "ui-state-highlight" );
}
if ( day.extraClasses ) {
classes.push( day.extraClasses.split( " " ) );
}
return "<span class='" + classes.join( " " ) + "'>" + day.date + "</span>";
return content;
},
_buildButtons: function() {
@ -452,6 +437,26 @@ return $.widget( "ui.calendar", {
}
},
_isValid: function( value ) {
if ( $.type( value ) !== "date" ) {
return false;
}
if ( $.type( this.options.max ) === "date" ) {
if ( value > this.options.max ) {
return false;
}
}
if ( $.type( this.options.min ) === "date" ) {
if ( value < this.options.min ) {
return false;
}
}
return true;
},
_destroy: function() {
this.element
.off( ".calendar" )
@ -471,21 +476,29 @@ return $.widget( "ui.calendar", {
_setOption: function( key, value ) {
if ( key === "value" ) {
if ( $.type( value ) === "date" ) {
if ( this._isValid( value ) ) {
this.date.setTime( value.getTime() ).select();
this.refresh();
}
}
if ( key === "max" || key === "min" ) {
if ( $.type( value ) === "date" || value === null ) {
this._super( key, value );
this.refresh();
}
return;
}
this._super( key, value );
if ( key === "eachDay" ) {
this.date.eachDay = this.options.eachDay;
this.date.eachDay = value;
this.refresh();
}
if ( key === "dateFormat" ) {
this.date.setFormat( this.options.dateFormat );
this.date.setFormat( value );
}
if ( key === "showWeek" ) {

View File

@ -43,6 +43,8 @@ $.widget( "ui.datepicker", {
dateFormat: { date: "short" },
// TODO Review
eachDay: $.noop,
max: null,
min: null,
numberOfMonths: 1,
position: {
my: "left top",
@ -63,6 +65,22 @@ $.widget( "ui.datepicker", {
this._createCalendar();
},
_getCreateOptions: function() {
var max = this.element.attr( "max" ),
min = this.element.attr( "min" ),
options = {};
if ( max !== undefined ) {
options.max = Globalize.parseDate( max, { pattern: "yyyy-MM-dd" } );
}
if ( min !== undefined ) {
options.min = Globalize.parseDate( min, { pattern: "yyyy-MM-dd" } );
}
return options;
},
_createCalendar: function() {
var that = this;
@ -75,6 +93,8 @@ $.widget( "ui.datepicker", {
.calendar({
dateFormat: this.options.dateFormat,
eachDay: this.options.eachDay,
max: this.options.max,
min: this.options.min,
numberOfMonths: this.options.numberOfMonths,
showWeek: this.options.showWeek,
value: this._getParsedValue(),
@ -284,11 +304,7 @@ $.widget( "ui.datepicker", {
value: function( value ) {
if ( arguments.length ) {
var date = Globalize.parseDate( value, this.options.dateFormat );
if ( $.type( date ) === "date" ) {
this.valueAsDate( date );
this.element.val( value );
}
this.valueAsDate( Globalize.parseDate( value , this.options.dateFormat ) );
} else {
return this._getParsedValue() ? this.element.val() : null;
}
@ -296,7 +312,7 @@ $.widget( "ui.datepicker", {
valueAsDate: function( value ) {
if ( arguments.length ) {
if ( $.type( value ) === "date" ) {
if ( this.calendarInstance._isValid( value ) ) {
this.calendarInstance.valueAsDate( value );
this.element.val( Globalize.format( value, this.options.dateFormat ) );
}
@ -306,7 +322,7 @@ $.widget( "ui.datepicker", {
},
isValid: function() {
return this._getParsedValue() !== null;
return this.calendarInstance._isValid( this._getParsedValue() );
},
_destroy: function() {
@ -345,5 +361,4 @@ $.widget( "ui.datepicker", {
}
}
});
}));