Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 48 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,58 @@
# datepicker

Example date picker ui component built on component/calendar.

Not yet feature-rich, just a blog post example.
A date picker UI component built on component/calendar. Forked from component/datepicker.

![screen shot 2013-06-17 at 13 31 47](https://f.cloud.github.com/assets/574696/661644/4593118a-d739-11e2-9bdf-4b91b99b8a38.png)

## Install

## Installation
```
$ component install redbadger/datepicker
```

$ component install component/datepicker
## Features

* Takes and returns a value of type `Date`
* Hide on click outside
* Manual date change support
* Keyboard interaction
* Fully configurable date format with custom divider symbols

## Example

``` javascript
var Datepicker = require('datepicker');

var picker = Datepicker(document.getElementById('date'), "DD/MM/YYYY")

picker.value(new Date());
picker.value() // => currently selected date as a Date instance

```

## Custom date format

You can specify the format of the date you expect it to produce. Format is a string, which can be something like this:

* "DD/MM/YYYY"
* "YYYY-MM-DD"
* "mm.dd.yy"

Order of month, day and year will be recognized by the component, divider symbol will also be honored. You can ask for 2 digit year or 4 with "YY" or "YYYY" respectably.

## API

### .value(value)

Get or set current value. `value` argument is optional.

### .show()

Show the date picker popover.

### .hide()

Hide the date picker popover.

## License

Expand Down
21 changes: 15 additions & 6 deletions component.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
{
"name": "datepicker",
"repo": "component/datepicker",
"description": "Datepicker ui component built on component/calendar",
"version": "1.0.0",
"keywords": ["date", "picker", "calendar"],
"repo": "redbadger/datepicker",
"description": "Improved datepicker UI forked from component/datepicker",
"version": "0.1.0",
"keywords": [
"date",
"picker",
"calendar"
],
"dependencies": {
"component/calendar": "*",
"component/popover": "*",
"component/aurora": "*",
"component/event": "*"
"component/event": "*",
"component/events": "*",
"component/keyname": "*",
"component/aurora-tip": "0.0.2",
"component/tip": "0.2.1",
"component/emitter": "*"
},
"development": {},
"license": "MIT",
Expand All @@ -18,4 +27,4 @@
"styles": [
"datepicker.css"
]
}
}
5 changes: 5 additions & 0 deletions datepicker.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@

.datepicker-popover .tip-inner {
border: none;
background-color: transparent;
}

.datepicker-popover .calendar-table {
background-color: #fff;
}
191 changes: 177 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
var Calendar = require('calendar')
, Popover = require('popover')
, event = require('event')
, events = require('events')
, keyname = require('keyname')
, Emitter = require('emitter');


/**
* Expose `Datepicker`.
Expand All @@ -16,40 +20,199 @@ module.exports = Datepicker;
* Initialize a new date picker with the given input `el`.
*
* @param {Element} el
* @format String "DD/MM/YYYY", "YYYY/MM/DD", "MM/DD/YYYY"
* @api public
*/

function Datepicker(el) {
if (!(this instanceof Datepicker)) return new Datepicker(el);
function Datepicker(el, format) {
if (!(this instanceof Datepicker)) return new Datepicker(el, format);
this.el = el;
this.cal = new Calendar;
this.cal.addClass('datepicker-calendar');
event.bind(el, 'click', this.onclick.bind(this));

this.events = events(this.el, this);
this.events.bind('click', 'onclick');
this.events.bind('change', 'onchange');
this.events.bind('keydown', 'onkeydown');

this.cal.on('change', this.value.bind(this));

if (typeof(format) === 'undefined') {
this.format = "DD/MM/YYYY";
} else {
this.format = format;
}

this.initDateFormat(this.format);

event.bind(document, 'click', this.hide.bind(this));

return this;
}

/**
* Handle input clicks.
* Mixin emitter.
*/

Datepicker.prototype.onclick = function(e){
Emitter(Datepicker.prototype);

/**
* Parsing the format string
*/

Datepicker.prototype.initDateFormat = function(format) {
var reDay = /DD/i
, reMonth = /MM/i
, reYear = /Y/gi
, reDivider = /[^a-zA-Z0-9]/
, dayPos = 0
, monthPos = 0
, yearPos = 0
, yearCount = 0
, divider = ""
, dateArray = [];

this.dayPos = format.search(reDay);
this.monthPos = format.search(reMonth);
this.yearPos = format.search(reYear);
this.yearCount = format.match(reYear).length;
this.divider = format.match(reDivider)[0];
}

Datepicker.prototype.processDate = function(date) {
var dateArray = []
, year
, finalString = ""
, divider = this.divider;

if (this.yearCount == 2) {
year = String(date.getFullYear()).slice(2, 4);
} else {
year = date.getFullYear();
}

dateArray = [
{ value: date.getDate(), position: this.dayPos },
{ value: (date.getMonth() + 1), position: this.monthPos },
{ value: year, position: this.yearPos }
];

dateArray.sort(function(a, b) {
if (a.position < b.position)
return -1;
if (a.position > b.position)
return 1;
return 0;
});

dateArray.forEach(function(entry){
finalString += entry.value + divider;
});

// Slicing away the last applied divider
return finalString.slice(0, -1);
}

/**
* Get/set value.
*
* @param {Date} date (optional)
* @api public
*/

Datepicker.prototype.value = function(date) {
if(!date) {
if(!this.el.value.match(/\d{1,2}\/\d{1,2}\/\d{4}/))
return null;

var parts = this.el.value.split("/");

return new Date(parts[2], parts[1] - 1, parts[0]);
}

this.cal.select(date);
this.el.value = this.processDate(date);

this.el.focus();

this.hide();
this.emit('change', date);

return true;
}

/**
* Show popover
*
* @api public
*/

Datepicker.prototype.show = function() {
var ev = new Event('click');
document.dispatchEvent(ev);

if (this.popover) return;
this.cal.once('change', this.onchange.bind(this));

this.popover = new Popover(this.cal.el);
this.popover.classname = 'datepicker-popover popover';
this.popover.show(this.el);
};

event.bind(this.popover.el[0], 'click', function(e) { e.stopPropagation(); return false; });
}

/**
* Handle date changes.
* Hide popover
*
* @api public
*/

Datepicker.prototype.onchange = function(date){
this.el.value = date.getFullYear()
+ '/'
+ (date.getMonth() + 1)
+ '/'
+ date.getDate();
Datepicker.prototype.hide = function() {
if (!this.popover) return;

this.popover.remove();
this.popover = null;
}

/**
* Handle input clicks.
*/

Datepicker.prototype.onclick = function(e){
e.stopPropagation();

this.show();
return false;
};

Datepicker.prototype.onkeydown = function(e){
switch (keyname(e.which)) {
case 'enter':
e.preventDefault();
this.onchange(e);

break;
case 'esc':
this.hide();

break;
default:
console.log(keyname(e.which));
}
};

/**
* Handle date changes.
*/

Datepicker.prototype.onchange = function(e){
var parts = this.el.value.split("/");
if(parts.length < 3)
return this.value(null);

var date = new Date(parts[2], parts[1] - 1, parts[0]);

this.value(date);
};



Loading