Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constrain dates #25

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions .jshintrc
@@ -0,0 +1,16 @@
{
"undef": "true",
"unused": "true",
"laxbreak": "true",
"laxcomma": "true",
"es5": "true",
"supernew": "false",
"globals": {
"console": false,
"describe": false,
"exports": false,
"it": false,
"module": false,
"require": false
}
}
6 changes: 5 additions & 1 deletion Makefile
Expand Up @@ -17,4 +17,8 @@ lib/template.js: lib/template.html
clean: clean:
rm -fr build components lib/template.js rm -fr build components lib/template.js


.PHONY: clean test:
@./node_modules/.bin/mocha \
--reporter spec

.PHONY: clean test
8 changes: 8 additions & 0 deletions Readme.md
Expand Up @@ -56,6 +56,14 @@ cal.el.appendTo('body');


Show the next view (month). Show the next view (month).


### Calendar#mix()

Define earliest valid date - calendar won't generate `change` events for dates before this one.

### Calendar#max()

Define latest valid date - calendar won't generate `change` events for dates after this one.

## Themes ## Themes


[Aurora](https://github.com/component/aurora-calendar): [Aurora](https://github.com/component/aurora-calendar):
Expand Down
1 change: 1 addition & 0 deletions component.json
Expand Up @@ -25,6 +25,7 @@
"lib/utils.js", "lib/utils.js",
"lib/template.js", "lib/template.js",
"lib/calendar.js", "lib/calendar.js",
"lib/dayrange.js",
"lib/days.js" "lib/days.js"
], ],
"license": "MIT" "license": "MIT"
Expand Down
11 changes: 11 additions & 0 deletions example.html
Expand Up @@ -35,6 +35,12 @@
font-size: 10px; font-size: 10px;
padding: 3px; padding: 3px;
} }

.calendar td a.invalid {
opacity: .2;
background-color: rgba(0, 0, 0, .2);
cursor: default;
}
</style> </style>
</head> </head>
<body> <body>
Expand Down Expand Up @@ -71,6 +77,11 @@ <h1>Calendar</h1>
var large = new Calendar; var large = new Calendar;
large.addClass('large'); large.addClass('large');
large.el.appendTo('body'); large.el.appendTo('body');

var restricted = new Calendar(new Date(2004, 6, 11))
.min(new Date(2004, 5, 12))
.max([2004, 7, 19]);
restricted.el.appendTo('body');
</script> </script>
</body> </body>
</html> </html>
31 changes: 29 additions & 2 deletions lib/calendar.js
Expand Up @@ -77,8 +77,10 @@ Calendar.prototype.addClass = function(name){
*/ */


Calendar.prototype.select = function(date){ Calendar.prototype.select = function(date){
this.selected = date; if (this.days.validRange.valid(date)) {
this.days.select(date); this.selected = date;
this.days.select(date);
}
this.show(date); this.show(date);
return this; return this;
}; };
Expand All @@ -97,6 +99,31 @@ Calendar.prototype.show = function(date){
return this; return this;
}; };


/**
* Set minimum valid date (inclusive)
*
* @param {Date} date
* @api public
*/

Calendar.prototype.min = function(date) {
this.days.validRange.min(date);
return this;
};


/**
* Set maximum valid date (inclusive)
*
* @param {Date} date
* @api public
*/

Calendar.prototype.max = function(date) {
this.days.validRange.max(date);
return this;
};

/** /**
* Enable a year dropdown. * Enable a year dropdown.
* *
Expand Down
46 changes: 46 additions & 0 deletions lib/dayrange.js
@@ -0,0 +1,46 @@
module.exports = DayRange;

function ymd(date) {
if (Array.isArray(date)) {
return date;
}
return [date.getFullYear(), date.getMonth(), date.getDate()];
}

function compare(a, b) {
var i, diff;
for (i = 0; i < a.length; ++i) {
diff = a[i] - b[i];
if (diff !== 0) {
return diff;
}
}
return 0;
}

function DayRange(min, max) {
this.min(min).max(max);
return this;
}

DayRange.prototype.min = function(v) {
this._min = v ? ymd(v) : undefined;
return this;
};

DayRange.prototype.max = function(v) {
this._max = v ? ymd(v) : undefined;
return this;
};

DayRange.prototype.before = function(day) {
return this._min && (compare(ymd(day), this._min) < 0);
};

DayRange.prototype.after = function(day) {
return this._max && (compare(ymd(day), this._max) > 0);
};

DayRange.prototype.valid = function(day) {
return !this.before(day) && !this.after(day);
};
62 changes: 37 additions & 25 deletions lib/days.js
Expand Up @@ -9,6 +9,7 @@ var o = require('jquery')
, inGroupsOf = require('in-groups-of') , inGroupsOf = require('in-groups-of')
, clamp = require('./utils').clamp , clamp = require('./utils').clamp
, range = require('range') , range = require('range')
, DayRange = require('./dayrange');


/** /**
* Days. * Days.
Expand Down Expand Up @@ -74,12 +75,16 @@ function Days() {
this.body = this.el.find('tbody'); this.body = this.el.find('tbody');
this.title = this.head.find('.title'); this.title = this.head.find('.title');
this.select(new Date); this.select(new Date);
this.validRange = new DayRange;


// emit "day" // emit "day"
this.body.on('click', 'a', function(e){ this.body.on('click', 'a', function(e){
var el = o(e.target); var el = o(e.target);
var day = parseInt(el.text(), 10); var day = parseInt(el.text(), 10);
var data = el.data('date').split('-'); var data = el.data('date').split('-');
if (!self.validRange.valid(data)) {
return false;
}
var year = data[0]; var year = data[0];
var month = data[1]; var month = data[1];
var date = new Date; var date = new Date;
Expand Down Expand Up @@ -123,6 +128,7 @@ Days.prototype.select = function(date){
return this; return this;
}; };



/** /**
* Show date selection. * Show date selection.
* *
Expand Down Expand Up @@ -278,21 +284,17 @@ Days.prototype.rowsFor = function(date){
var cells = []; var cells = [];


// cells before // cells before
cells = cells.concat(cellsBefore(before, month, year)); cells = cells.concat(cellsBefore(before, month, year, this.validRange));


// current cells // current cells
for (var i = 0; i < total; ++i) { for (var i = 0; i < total; ++i) {
var day = i + 1; var day = i + 1
var date = 'data-date=' + [year, month, day].join('-'); , select = (day == selectedDay && month == selectedMonth && year == selectedYear);
if (day == selectedDay && month == selectedMonth && year == selectedYear) { cells.push(renderDay([year, month, day], this.validRange, select));
cells.push('<td class=selected><a href="#" ' + date + '>' + day + '</a></td>');
} else {
cells.push('<td><a href="#" ' + date + '>' + day + '</a></td>');
}
} }


// after cells // after cells
cells = cells.concat(cellsAfter(after, month, year)); cells = cells.concat(cellsAfter(after, month, year, this.validRange));


return inGroupsOf(cells, 7); return inGroupsOf(cells, 7);
}; };
Expand Down Expand Up @@ -336,12 +338,12 @@ Days.prototype.showSelectedMonth = function(month) {
* @api private * @api private
*/ */


function cellsBefore(n, month, year){ function cellsBefore(n, month, year, validRange){
var cells = []; var cells = [];
if (month == 0) --year; if (month == 0) --year;
var prev = clamp(month - 1); var prev = clamp(month - 1);
var before = daysInMonth(prev); var before = daysInMonth(prev);
while (n--) cells.push(prevMonthDay(year, prev, before--)); while (n--) cells.push(renderDay([year, prev, before--], validRange, false, 'prev-day'));
return cells.reverse(); return cells.reverse();
} }


Expand All @@ -354,31 +356,41 @@ function cellsBefore(n, month, year){
* @api private * @api private
*/ */


function cellsAfter(n, month, year){ function cellsAfter(n, month, year, validRange){
var cells = []; var cells = [];
var day = 0; var day = 0;
if (month == 11) ++year; if (month == 11) ++year;
var next = clamp(month + 1); var next = clamp(month + 1);
while (n--) cells.push(nextMonthDay(year, next, ++day)); while (n--) cells.push(renderDay([year, next, ++day], validRange, false, 'next-day'));
return cells; return cells;
} }



/** /**
* Prev month day template. * Day template.
*/ */


function prevMonthDay(year, month, day) { function renderDay(ymd, validRange, selected, style) {
var date = 'data-date=' + [year, month, day].join('-'); var date = 'data-date=' + ymd.join('-')
return '<td><a href="#" ' + date + ' class=prev-day>' + day + '</a></td>'; , styles = []
} , tdClass = ''
, aClass = '';

if (selected) {
tdClass = ' class="selected"';
}
if (style) {
styles.push(style);
}
if (!validRange.valid(ymd)) {
styles.push('invalid');
}
if (styles.length) {
aClass = ' class="' + styles.join(' ') + '"';
}


/**
* Next month day template.
*/


function nextMonthDay(year, month, day) { return '<td' + tdClass + '><a href="#" ' + date + aClass + '>' + ymd[2] + '</a></td>';
var date = 'data-date=' + [year, month, day].join('-');
return '<td><a href="#" ' + date + ' class=next-day>' + day + '</a></td>';
} }


/** /**
Expand Down
15 changes: 12 additions & 3 deletions package.json
Expand Up @@ -2,20 +2,29 @@
"name": "calendar-component", "name": "calendar-component",
"description": "Calendar component", "description": "Calendar component",
"version": "0.0.3", "version": "0.0.3",
"keywords": ["calendar", "date", "ui"], "keywords": [
"calendar",
"date",
"ui"
],
"dependencies": { "dependencies": {
"jquery-component": "*", "jquery-component": "*",
"emitter-component": "*", "emitter-component": "*",
"in-groups-of": "*" "in-groups-of": "*"
}, },
"component": { "component": {
"styles": ["lib/calendar.css"], "styles": [
"lib/calendar.css"
],
"scripts": { "scripts": {
"calendar/index.js": "index.js", "calendar/index.js": "index.js",
"calendar/lib/utils.js": "lib/utils.js", "calendar/lib/utils.js": "lib/utils.js",
"calendar/lib/template.js": "lib/template.js", "calendar/lib/template.js": "lib/template.js",
"calendar/lib/calendar.js": "lib/calendar.js", "calendar/lib/calendar.js": "lib/calendar.js",
"calendar/lib/days.js": "lib/days.js" "calendar/lib/days.js": "lib/days.js"
} }
},
"devDependencies": {
"mocha": "~1.8.1"
} }
} }
49 changes: 49 additions & 0 deletions test/dayrange.js
@@ -0,0 +1,49 @@
var DayRange = require('../lib/dayrange')
, assert = require('assert');

describe('day range', function(){
it('should consider all dates as valid if no min/max specified', function(){
var dr = new DayRange;
assert.ok(!dr.before(new Date));
assert.ok(!dr.after(new Date));
assert.ok(dr.valid([2002, 12, 10]));
});

it('should consider dates inside of the range as valid', function(){
var dr = new DayRange([2014, 3, 2], [2014, 4, 3]);
assert.ok(dr.before([2014, 3, 1]));
assert.ok(!dr.valid([2014, 3, 1]));
assert.ok(dr.valid([2014, 3, 2]));
assert.ok(dr.valid([2014, 3, 30]));
assert.ok(dr.valid([2014, 4, 3]));
assert.ok(!dr.valid([2014, 4, 4]));
assert.ok(dr.after([2014, 4, 4]));
});

it('should work with mixture of dates and arrays', function(){
var dr = new DayRange()
.min([2014, 3, 2])
.max(new Date(2014, 4, 3));
assert.ok(dr.before(new Date(2014, 3, 1)));
assert.ok(!dr.valid(new Date(2014, 3, 1)));
assert.ok(dr.valid(new Date(2014, 3, 2)));
assert.ok(dr.valid(new Date(2014, 3, 30)));
assert.ok(dr.valid(new Date(2014, 4, 3)));
assert.ok(!dr.valid(new Date(2014, 4, 4)));
assert.ok(dr.after(new Date(2014, 4, 4)));
});

it('should work if only min is specified', function(){
var dr = new DayRange([2013, 3, 3]);
assert.ok(!dr.valid([2013, 3, 2]));
assert.ok(dr.valid([2013, 3, 3]));
assert.ok(dr.valid([2013, 3, 4]));
});

it('should work if only max is specified', function(){
var dr = new DayRange(null, [2013, 3, 3]);
assert.ok(dr.valid([2013, 3, 2]));
assert.ok(dr.valid([2013, 3, 3]));
assert.ok(!dr.valid([2013, 3, 4]));
});
});