From cb8466a46e752fe4e0892ea75ec89aeb4eec0474 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 11:14:30 +0000 Subject: [PATCH 01/10] Added reasonable value processing --- component.json | 12 +++++--- index.js | 34 +++++++++++++++++---- test/index.html | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 test/index.html diff --git a/component.json b/component.json index 3b4cb43..2d41068 100644 --- a/component.json +++ b/component.json @@ -1,9 +1,13 @@ { "name": "datepicker", - "repo": "component/datepicker", - "description": "Datepicker ui component built on component/calendar", + "repo": "redbadger/datepicker", + "description": "Improved datepicker UI forked from component/datepicker", "version": "1.0.0", - "keywords": ["date", "picker", "calendar"], + "keywords": [ + "date", + "picker", + "calendar" + ], "dependencies": { "component/calendar": "*", "component/popover": "*", @@ -18,4 +22,4 @@ "styles": [ "datepicker.css" ] -} +} \ No newline at end of file diff --git a/index.js b/index.js index 9f8cf96..404ea49 100644 --- a/index.js +++ b/index.js @@ -25,6 +25,7 @@ function Datepicker(el) { this.cal = new Calendar; this.cal.addClass('datepicker-calendar'); event.bind(el, 'click', this.onclick.bind(this)); + event.bind(el, 'change', this.textchange.bind(this)) } /** @@ -44,12 +45,35 @@ Datepicker.prototype.onclick = function(e){ */ Datepicker.prototype.onchange = function(date){ - this.el.value = date.getFullYear() - + '/' - + (date.getMonth() + 1) - + '/' - + date.getDate(); + this.el.value = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); this.popover.remove(); this.popover = null; }; + +Datepicker.prototype.textchange = 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); +}; + +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 = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); + + return true; +} + diff --git a/test/index.html b/test/index.html new file mode 100644 index 0000000..a67f703 --- /dev/null +++ b/test/index.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + From 034e1ba1a4fa99e60157f6e99300a8727bdeba53 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 11:18:44 +0000 Subject: [PATCH 02/10] Updated readme --- Readme.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 2aa426f..9b0b7cf 100644 --- a/Readme.md +++ b/Readme.md @@ -1,15 +1,26 @@ # 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 +## Example + +``` javascript +var Datepicker = require('datepicker'); + +var picker = Datepicker(document.getElementById('date')) + +picker.value(new Date()); +picker.value() // => currently selected date as a Date instance + +``` ## License From eb5cd8153f611f8253f8633f870e8f1f510bf952 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 12:42:34 +0000 Subject: [PATCH 03/10] Temp fix for version conflicts of tip and aurora-tip --- component.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/component.json b/component.json index 2d41068..1d234bf 100644 --- a/component.json +++ b/component.json @@ -12,7 +12,9 @@ "component/calendar": "*", "component/popover": "*", "component/aurora": "*", - "component/event": "*" + "component/event": "*", + "component/aurora-tip": "0.0.2", + "component/tip": "0.2.1" }, "development": {}, "license": "MIT", From 89403a25d306bf751c9a631939cb9b08643cf9bb Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 12:42:50 +0000 Subject: [PATCH 04/10] Improve default CSS --- datepicker.css | 5 +++++ test/index.html | 1 + 2 files changed, 6 insertions(+) diff --git a/datepicker.css b/datepicker.css index 9eb1690..75e0c75 100644 --- a/datepicker.css +++ b/datepicker.css @@ -9,4 +9,9 @@ .datepicker-popover .tip-inner { border: none; + background-color: transparent; +} + +.datepicker-popover .calendar-table { + background-color: #fff; } \ No newline at end of file diff --git a/test/index.html b/test/index.html index a67f703..75b6711 100644 --- a/test/index.html +++ b/test/index.html @@ -9,6 +9,7 @@ - + + + From 643f2c01f80601788b53c93702f74f85e4801b7b Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 15:10:20 +0000 Subject: [PATCH 07/10] Added keyboard support --- component.json | 1 + index.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/component.json b/component.json index c640771..c4d0fc8 100644 --- a/component.json +++ b/component.json @@ -14,6 +14,7 @@ "component/aurora": "*", "component/event": "*", "component/events": "*", + "component/keyname": "*", "component/aurora-tip": "0.0.2", "component/tip": "0.2.1" }, diff --git a/index.js b/index.js index 8b3edba..71ba0ab 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,8 @@ var Calendar = require('calendar') , Popover = require('popover') , event = require('event') , events = require('events') + , keyname = require('keyname') + /** * Expose `Datepicker`. @@ -29,6 +31,7 @@ function Datepicker(el) { this.events = events(this.el, this); this.events.bind('click', 'onclick'); this.events.bind('change', 'onchange'); + this.events.bind('keydown', 'onkeydown'); event.bind(document, 'click', this.hide.bind(this)); @@ -42,6 +45,7 @@ Datepicker.prototype.show = function() { if (this.popover) return; this.cal.on('change', this.value.bind(this)); + this.popover = new Popover(this.cal.el); this.popover.classname = 'datepicker-popover popover'; this.popover.show(this.el); @@ -67,6 +71,22 @@ Datepicker.prototype.onclick = function(e){ 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. */ @@ -93,6 +113,9 @@ Datepicker.prototype.value = function(date) { this.cal.select(date); this.el.value = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); + this.el.focus(); + + this.hide(); return true; } From 0d02858bb261c5754663966f9b1b0dd462254281 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Tue, 21 Jan 2014 15:53:32 +0000 Subject: [PATCH 08/10] Updated docs and readme set version to 0.1.0 --- Readme.md | 21 +++++++++++++++++++ component.json | 2 +- index.js | 55 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/Readme.md b/Readme.md index 9b0b7cf..d73dee9 100644 --- a/Readme.md +++ b/Readme.md @@ -10,6 +10,13 @@ A date picker UI component built on component/calendar. Forked from component/da $ component install redbadger/datepicker ``` +## Features + +* takes and returns a value of type `Date` +* hide on click outside +* manual date change support +* keyboard interaction + ## Example ``` javascript @@ -22,6 +29,20 @@ picker.value() // => currently selected date as a Date instance ``` +## 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 MIT diff --git a/component.json b/component.json index c4d0fc8..798baae 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "datepicker", "repo": "redbadger/datepicker", "description": "Improved datepicker UI forked from component/datepicker", - "version": "1.0.0", + "version": "0.1.0", "keywords": [ "date", "picker", diff --git a/index.js b/index.js index 71ba0ab..197181d 100644 --- a/index.js +++ b/index.js @@ -38,6 +38,38 @@ function Datepicker(el) { return this; } +/** + * 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 = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); + this.el.focus(); + + this.hide(); + + return true; +} + +/** + * Show popover + * + * @api public + */ + Datepicker.prototype.show = function() { var ev = new Event('click'); document.dispatchEvent(ev); @@ -53,6 +85,12 @@ Datepicker.prototype.show = function() { event.bind(this.popover.el[0], 'click', function(e) { e.stopPropagation(); return false; }); } +/** + * Hide popover + * + * @api public + */ + Datepicker.prototype.hide = function() { if (!this.popover) return; @@ -101,22 +139,5 @@ Datepicker.prototype.onchange = function(e){ this.value(date); }; -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 = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); - this.el.focus(); - - this.hide(); - - return true; -} From 16666971119b5ce61a9706b5211a54ccfb95f74d Mon Sep 17 00:00:00 2001 From: Alex Savin Date: Fri, 24 Jan 2014 12:11:22 +0000 Subject: [PATCH 09/10] Adding Change event emitter --- component.json | 3 ++- index.js | 12 ++++++++++-- test/index.html | 8 ++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/component.json b/component.json index 798baae..506b621 100644 --- a/component.json +++ b/component.json @@ -16,7 +16,8 @@ "component/events": "*", "component/keyname": "*", "component/aurora-tip": "0.0.2", - "component/tip": "0.2.1" + "component/tip": "0.2.1", + "component/emitter": "*" }, "development": {}, "license": "MIT", diff --git a/index.js b/index.js index 197181d..5fdb077 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ var Calendar = require('calendar') , event = require('event') , events = require('events') , keyname = require('keyname') + , Emitter = require('emitter'); /** @@ -33,11 +34,19 @@ function Datepicker(el) { this.events.bind('change', 'onchange'); this.events.bind('keydown', 'onkeydown'); + this.cal.on('change', this.value.bind(this)); + event.bind(document, 'click', this.hide.bind(this)); return this; } +/** + * Mixin emitter. + */ + +Emitter(Datepicker.prototype); + /** * Get/set value. * @@ -60,6 +69,7 @@ Datepicker.prototype.value = function(date) { this.el.focus(); this.hide(); + this.emit('change', date); return true; } @@ -76,8 +86,6 @@ Datepicker.prototype.show = function() { if (this.popover) return; - this.cal.on('change', this.value.bind(this)); - this.popover = new Popover(this.cal.el); this.popover.classname = 'datepicker-popover popover'; this.popover.show(this.el); diff --git a/test/index.html b/test/index.html index af94d82..fac5ca6 100644 --- a/test/index.html +++ b/test/index.html @@ -77,6 +77,14 @@ picker1.value(new Date()); console.log("Today:", picker1.value()) + + picker1.on("change", function(date) { + console.log("Picker 1 change detected, new date: " + date); + }); + + picker2.on("change", function(date) { + console.log("Picker 2 change detected, new date: " + date); + }); From a2cec2464d601dde2dba191b20980b004ded2ffc Mon Sep 17 00:00:00 2001 From: Alex Savin Date: Sun, 26 Jan 2014 21:51:58 +0000 Subject: [PATCH 10/10] Fully customizable date format --- Readme.md | 21 ++++++++++---- index.js | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- test/index.html | 4 +-- 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/Readme.md b/Readme.md index d73dee9..88b5162 100644 --- a/Readme.md +++ b/Readme.md @@ -12,23 +12,34 @@ $ component install redbadger/datepicker ## Features -* takes and returns a value of type `Date` -* hide on click outside -* manual date change support -* keyboard interaction +* 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')) +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) diff --git a/index.js b/index.js index 5fdb077..8bcf3e3 100644 --- a/index.js +++ b/index.js @@ -20,11 +20,12 @@ 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'); @@ -36,6 +37,14 @@ function Datepicker(el) { 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; @@ -47,6 +56,63 @@ function Datepicker(el) { 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. * @@ -65,7 +131,8 @@ Datepicker.prototype.value = function(date) { } this.cal.select(date); - this.el.value = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); + this.el.value = this.processDate(date); + this.el.focus(); this.hide(); diff --git a/test/index.html b/test/index.html index fac5ca6..1f751a4 100644 --- a/test/index.html +++ b/test/index.html @@ -72,8 +72,8 @@ var input1 = document.getElementById("date1"); var input2 = document.getElementById("date2"); - var picker1 = Datepicker(input1); - var picker2 = Datepicker(input2); + var picker1 = Datepicker(input1, "DD/MM/YYYY"); + var picker2 = Datepicker(input2, "YY-MM-DD"); picker1.value(new Date()); console.log("Today:", picker1.value())