diff --git a/coffee/.gitignore b/coffee/.gitignore
deleted file mode 100644
index a30fff1..0000000
--- a/coffee/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Directories
-.cache
-.sass-cache
-node_modules
-
-# Files
-npm-debug.log
-*~
\ No newline at end of file
diff --git a/coffee/.sass-lint.yml b/coffee/.sass-lint.yml
deleted file mode 100644
index c0f7caf..0000000
--- a/coffee/.sass-lint.yml
+++ /dev/null
@@ -1,146 +0,0 @@
-# Rule Configuration
-rules:
- attribute-quotes:
- - 2
- border-zero:
- - convention: 'none'
- brace-style:
- -
- style: '1tbs'
- allow-single-line: false
- class-name-format:
- - 2
- -
- allow-leading-underscore: true
- convention: hyphenatedbem
- empty-args:
- - 2
- - include: true
- empty-line-between-blocks:
- - 2
- -
- include: true
- allow-single-line-rulesets: false
- extends-before-declarations:
- - 2
- extends-before-mixins:
- - 2
- final-newline:
- - 2
- - include: false
- force-attribute-nesting:
- - 0
- force-element-nesting:
- - 0
- force-pseudo-nesting:
- - 0
- function-name-format:
- - 2
- -
- allow-leading-underscore: true
- convention: hyphenatedbem
- hex-length:
- - 2
- - style: short
- hex-notation:
- - 2
- - style: lowercase
- id-name-format:
- - 2
- -
- allow-leading-underscore: true
- convention: hyphenatedlowercase
- indentation:
- - 1
- - size: 4
- leading-zero:
- - 2
- - include: true
- mixin-name-format:
- - 0
- mixins-before-declarations:
- - 0
- nesting-depth:
- - 2
- - max-depth: 4
- no-attribute-selectors:
- - 2
- no-color-hex:
- - 0
- no-color-keywords:
- - 2
- no-color-literals:
- - 0
- no-combinator:
- - 0
- no-css-comments:
- - 0
- no-duplicate-properties:
- - 2
- no-empty-rulesets:
- - 2
- no-important:
- - 0
- no-invalid-hex:
- - 2
- no-mergeable-selectors:
- - 2
- no-misspelled-properties:
- - 2
- no-trailing-whitespace:
- - 2
- no-transition-all:
- - 2
- no-universal-selectors:
- - 0
- no-vendor-prefixes:
- - 0
- one-declaration-per-line:
- - 2
- property-sort-order:
- - 2
- - order: 'alphabetical'
- quotes:
- - 2
- - style: 'single'
- shorthand-values:
- - 2
- - allowed-shorthands: [1, 2, 3]
- single-line-per-selector:
- - 2
- space-after-bang:
- - 2
- - include: 'false'
- space-after-colon:
- - 2
- - include: true
- space-after-comma:
- - 2
- - include: true
- space-around-operator:
- - 2
- - include: true
- space-before-bang:
- - 2
- - include: true
- space-before-brace:
- - 2
- - include: true
- space-before-colon:
- - 2
- - include: false
- space-between-parens:
- - 2
- - include: false
- trailing-semicolon:
- - 2
- - include: true
- url-quotes:
- - 2
- variable-name-format:
- - 2
- -
- allow-leading-underscore: true
- convention: hyphenatedbem
- zero-unit:
- - 0
\ No newline at end of file
diff --git a/coffee/README.md b/coffee/README.md
deleted file mode 100644
index 8c91b54..0000000
--- a/coffee/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# manhattan-date-picker
-
-Date picker support for form fields.
\ No newline at end of file
diff --git a/coffee/coffeelint.json b/coffee/coffeelint.json
deleted file mode 100644
index 7a409c1..0000000
--- a/coffee/coffeelint.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "arrow_spacing": {
- "level": "error"
- },
- "braces_spacing": {
- "level": "error",
- "empty_object_spaces": 0,
- "spaces": 0
- },
- "camel_case_classes": {
- "level": "error"
- },
- "colon_assignment_spacing": {
- "level": "error",
- "spacing": {
- "left": 0,
- "right": 1
- }
- },
- "empty_constructor_needs_parens": {
- "level": "error"
- },
- "ensure_comprehensions": {
- "level": "error"
- },
- "indentation": {
- "level": "error",
- "value": 4
- },
- "newlines_after_classes": {
- "level": "ignore"
- },
- "no_implicit_braces": {
- "level": "ignore"
- },
- "no_stand_alone_at": {
- "level": "error"
- },
- "no_this": {
- "level": "error"
- },
- "no_unnecessary_double_quotes": {
- "level": "error"
- },
- "non_empty_constructor_needs_parens": {
- "level": "error"
- },
- "space_operators": {
- "level": "ignore"
- },
- "spacing_after_comma": {
- "level": "error"
- }
-}
\ No newline at end of file
diff --git a/coffee/dist/date-picker.css b/coffee/dist/date-picker.css
deleted file mode 100644
index bc406d0..0000000
--- a/coffee/dist/date-picker.css
+++ /dev/null
@@ -1,136 +0,0 @@
-.mh-calendar {
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -webkit-user-select: none;
- box-sizing: border-box;
- float: left;
- font-family: sans-serif;
- padding: 10px;
- user-select: none;
- width: 300px; }
- .mh-calendar * {
- box-sizing: border-box; }
- .mh-calendar__nav {
- position: relative; }
- .mh-calendar__month {
- color: #666;
- font-size: 18px;
- text-align: center; }
- .mh-calendar__next {
- border-bottom: 8px solid transparent;
- border-left: 12px solid #334144;
- border-radius: 3px;
- border-top: 8px solid transparent;
- cursor: pointer;
- height: 0;
- position: absolute;
- right: 10px;
- top: 2px;
- width: 0; }
- .mh-calendar__previous {
- border-bottom: 8px solid transparent;
- border-radius: 3px;
- border-right: 12px solid #334144;
- border-top: 8px solid transparent;
- cursor: pointer;
- height: 0;
- left: 10px;
- position: absolute;
- top: 2px;
- width: 0; }
- .mh-calendar__weekdays {
- margin-top: 10px; }
- .mh-calendar__weekdays::after {
- clear: both;
- content: ' ';
- display: table; }
- .mh-calendar__weekday {
- color: #999;
- float: left;
- font-size: 11px;
- font-weight: bold;
- text-align: center;
- width: 40px; }
- .mh-calendar__dates {
- margin-top: 10px; }
- .mh-calendar__dates::after {
- clear: both;
- content: ' ';
- display: table; }
- .mh-calendar__date {
- color: #666;
- float: left;
- font-size: 14px;
- height: 40px;
- line-height: 40px;
- position: relative;
- text-align: center;
- width: 40px; }
- .mh-calendar__date:hover {
- cursor: pointer; }
- .mh-calendar__date:hover::after {
- background: rgba(226, 106, 106, 0.1);
- border-radius: 20px;
- content: '';
- display: block;
- height: 40px;
- left: 0;
- position: absolute;
- top: 0;
- width: 40px;
- z-index: -1; }
- .mh-calendar__date--in-range {
- background: rgba(226, 106, 106, 0.1); }
- .mh-calendar__date--range-start {
- background: #e26a6a;
- border-bottom-left-radius: 20px;
- border-top-left-radius: 20px;
- color: #fff;
- font-weight: bold; }
- .mh-calendar__date--range-start:hover {
- cursor: default; }
- .mh-calendar__date--range-start:hover::after {
- display: none; }
- .mh-calendar__date--range-end {
- background: #e26a6a;
- border-bottom-right-radius: 20px;
- border-top-right-radius: 20px;
- color: #fff;
- font-weight: bold; }
- .mh-calendar__date--range-end:hover {
- cursor: default; }
- .mh-calendar__date--range-end:hover::after {
- display: none; }
- .mh-calendar__date--today {
- text-decoration: underline; }
- .mh-calendar__date--blocked {
- color: #999;
- font-style: italic;
- font-weight: normal; }
- .mh-calendar__date--blocked:hover {
- cursor: default; }
- .mh-calendar__date--blocked:hover::after {
- display: none; }
- .mh-calendar__date--range-start.mh-calendar__date--blocked, .mh-calendar__date--range-end.mh-calendar__date--blocked {
- color: #fff; }
-
-.mh-date-picker,
-.mh-date-range-picker {
- background: #fff;
- border: 1px solid #d4dce0;
- border-radius: 3px;
- margin-top: 10px;
- position: absolute;
- width: 300px;
- z-index: 4; }
- .mh-date-picker--closed,
- .mh-date-range-picker--closed {
- display: none; }
-
-.mh-date-range-picker {
- width: 600px; }
- .mh-date-range-picker .mh-calendar:first-child .mh-calendar__next {
- display: none; }
- .mh-date-range-picker .mh-calendar:nth-child(2) .mh-calendar__previous {
- display: none; }
diff --git a/coffee/dist/index.html b/coffee/dist/index.html
deleted file mode 100644
index 9e3a7c2..0000000
--- a/coffee/dist/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- manhattan-date-picker
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/coffee/dist/index.js b/coffee/dist/index.js
deleted file mode 100644
index 211f6b7..0000000
--- a/coffee/dist/index.js
+++ /dev/null
@@ -1,1151 +0,0 @@
-(function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory();
- else if(typeof define === 'function' && define.amd)
- define([], factory);
- else if(typeof exports === 'object')
- exports["ManhattanDatePicker"] = factory();
- else
- root["ManhattanDatePicker"] = factory();
-})(this, function() {
-return /******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var installedModules = {};
-
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-
-/******/ // Check if module is in cache
-/******/ if(installedModules[moduleId])
-/******/ return installedModules[moduleId].exports;
-
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = installedModules[moduleId] = {
-/******/ exports: {},
-/******/ id: moduleId,
-/******/ loaded: false
-/******/ };
-
-/******/ // Execute the module function
-/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-
-/******/ // Flag the module as loaded
-/******/ module.loaded = true;
-
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-
-
-/******/ // expose the modules object (__webpack_modules__)
-/******/ __webpack_require__.m = modules;
-
-/******/ // expose the module cache
-/******/ __webpack_require__.c = installedModules;
-
-/******/ // __webpack_public_path__
-/******/ __webpack_require__.p = "";
-
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(0);
-/******/ })
-/************************************************************************/
-/******/ ([
-/* 0 */
-/***/ function(module, exports, __webpack_require__) {
-
- __webpack_require__(1);
- module.exports = __webpack_require__(2);
-
-
-/***/ },
-/* 1 */
-/***/ function(module, exports, __webpack_require__) {
-
- module.exports = __webpack_require__.p + "date-picker.css";
-
-/***/ },
-/* 2 */
-/***/ function(module, exports, __webpack_require__) {
-
- var $, BasePicker, Calendar, DatePicker, DateRangePicker,
- bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
- extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
- hasProp = {}.hasOwnProperty;
-
- $ = __webpack_require__(3);
-
- Calendar = __webpack_require__(4).Calendar;
-
- BasePicker = (function() {
- function BasePicker() {
- this.close = bind(this.close, this);
- this._isOpen = false;
- Object.defineProperty(this, 'isOpen', {
- get: (function(_this) {
- return function() {
- return _this._isOpen;
- };
- })(this)
- });
- $.listen(window, {
- 'fullscreenchange orientationchange resize': (function(_this) {
- return function(ev) {
- if (_this.isOpen) {
- return _this.close('resize');
- }
- };
- })(this)
- });
- }
-
- BasePicker.prototype.close = function(input, block, reason) {
- if (!this.isOpen) {
- return;
- }
- this._dom.picker.classList.add(this._bem(block, '', 'closed'));
- this._isOpen = false;
- return $.dispatch(input, this._et('close'), {
- 'reason': reason
- });
- };
-
- BasePicker.prototype._bem = function(block, element, modifier) {
- var name;
- if (element == null) {
- element = '';
- }
- if (modifier == null) {
- modifier = '';
- }
- name = block;
- if (element) {
- name = name + "__" + element;
- }
- if (modifier) {
- name = name + "--" + modifier;
- }
- return name;
- };
-
- BasePicker.prototype._track = function(input) {
- var left, rect, top;
- rect = input.getBoundingClientRect();
- top = rect.top += window.scrollY;
- left = rect.left += window.scrollX;
- this._dom.picker.style.top = (top + rect.height) + "px";
- return this._dom.picker.style.left = left + "px";
- };
-
- return BasePicker;
-
- })();
-
- DatePicker = (function(superClass) {
- extend(DatePicker, superClass);
-
- DatePicker.clsPrefix = 'data-mh-date-picker--';
-
- function DatePicker(input, options) {
- var eventListeners, proxyOptions;
- if (options == null) {
- options = {};
- }
- this.open = bind(this.open, this);
- DatePicker.__super__.constructor.call(this);
- $.config(this, {
- closeOnPick: false,
- format: 'human_en',
- parsers: ['human_en', 'dmy', 'iso']
- }, options, input, this.constructor.clsPrefix);
- this._behaviours = {};
- $.config(this._behaviours, {
- input: 'set-value'
- }, options, input, this.constructor.clsPrefix);
- this._dom = {};
- this._dom.input = input;
- this._dom.input.__mh_datePicker = this;
- this._dom.picker = $.create('div', {
- 'class': [this._bem('mh-date-picker'), this._bem('mh-date-picker', '', 'closed')].join(' ')
- });
- document.body.appendChild(this._dom.picker);
- proxyOptions = Calendar.proxyOptions(options, input);
- this._calendar = new Calendar(this._dom.picker, proxyOptions);
- Object.defineProperty(this, 'calendar', {
- get: (function(_this) {
- return function() {
- return _this._calendar;
- };
- })(this)
- });
- Object.defineProperty(this, 'input', {
- value: this._dom.input
- });
- $.listen(this.input, {
- 'blur': (function(_this) {
- return function() {
- return _this.close('blur');
- };
- })(this),
- 'click': (function(_this) {
- return function() {
- return _this.open();
- };
- })(this),
- 'focus': (function(_this) {
- return function() {
- return _this.open();
- };
- })(this),
- 'change': (function(_this) {
- return function(ev) {
- var date;
- if (ev.caller === _this) {
- return;
- }
- date = Calendar.parseDate(_this.input.value, _this.parsers);
- if (date) {
- return _this.pick(date, 'input');
- }
- };
- })(this)
- });
- eventListeners = {};
- eventListeners[this.calendar._et('pick')] = (function(_this) {
- return function(ev) {
- return _this.pick(ev.date, 'calendar');
- };
- })(this);
- $.listen(this.calendar.calendar, eventListeners);
- }
-
- DatePicker.prototype.close = function(reason) {
- return DatePicker.__super__.close.call(this, this.input, 'mh-date-picker', reason);
- };
-
- DatePicker.prototype.open = function() {
- var date;
- date = Calendar.parseDate(this.input.value, this.parsers);
- if (date) {
- this.calendar.goto(date.getMonth(), date.getFullYear());
- this.calendar.select(date);
- }
- this._track();
- this._dom.picker.classList.remove(this._bem('mh-date-picker', '', 'closed'));
- this._isOpen = true;
- return $.dispatch(this.input, this._et('open'));
- };
-
- DatePicker.prototype.pick = function(date, source) {
- if (source == null) {
- source = '';
- }
- this.calendar.select(date);
- if ($.dispatch(this.input, this._et('pick'), {
- 'date': date,
- 'source': source
- })) {
- this.constructor.behaviours.input[this._behaviours.input](this, date);
- $.dispatch(this.input, this._et('picked'), {
- 'date': date,
- 'source': source
- });
- if (this.closeOnPick) {
- return this.close({
- 'reason': 'pick'
- });
- }
- }
- };
-
- DatePicker.prototype._et = function(eventName) {
- return "mh-date-picker--" + eventName;
- };
-
- DatePicker.prototype._track = function() {
- return DatePicker.__super__._track.call(this, this.input);
- };
-
- DatePicker.behaviours = {
- input: {
- 'set-hidden': function(datePicker, date) {
- var dateStr, hidden, hiddenDateStr, hiddenFormat, hiddenSelector;
- dateStr = Calendar.formats[datePicker.format](date);
- datePicker.input.value = dateStr;
- hiddenSelector = datePicker.input.getAttribute(datePicker.constructor.clsPrefix + "hidden");
- hidden = $.one(hiddenSelector);
- hiddenFormat = datePicker.input.getAttribute(datePicker.constructor.clsPrefix + "hidden-format");
- hiddenDateStr = Calendar.formats[hiddenFormat](date);
- hidden.value = hiddenDateStr;
- return $.dispatch(hidden, 'change');
- },
- 'set-value': function(datePicker, date) {
- var dateStr;
- dateStr = Calendar.formats[datePicker.format](date);
- datePicker.input.value = dateStr;
- $.dispatch(datePicker.input, 'change', {
- caller: datePicker
- });
- return console.log(dateStr);
- }
- }
- };
-
- return DatePicker;
-
- })(BasePicker);
-
- DateRangePicker = (function(superClass) {
- extend(DateRangePicker, superClass);
-
- DateRangePicker.clsPrefix = 'data-mh-date-range-picker--';
-
- function DateRangePicker(startInput, endInput, options) {
- var eventListeners, i, input, len, proxyOptions, ref;
- if (options == null) {
- options = {};
- }
- DateRangePicker.__super__.constructor.call(this);
- $.config(this, {
- closeOnPick: false,
- format: 'human_en',
- parsers: ['human_en', 'dmy', 'iso'],
- pinToStart: false
- }, options, startInput, this.constructor.clsPrefix);
- this._behaviours = {};
- $.config(this._behaviours, {
- input: 'set-value'
- }, options, startInput, this.constructor.clsPrefix);
- this._dom = {};
- this._dom.picker = $.create('div', {
- 'class': [this._bem('mh-date-range-picker'), this._bem('mh-date-range-picker', '', 'closed')].join(' ')
- });
- document.body.appendChild(this._dom.picker);
- this._dom.startInput = startInput;
- this._dom.startInput.__mh_dateRangePicker = this;
- this._dom.endInput = endInput;
- this._dom.endInput.__mh_dateRangePicker = this;
- proxyOptions = Calendar.proxyOptions(options, startInput);
- this._calendars = [new Calendar(this._dom.picker, proxyOptions), new Calendar(this._dom.picker, proxyOptions)];
- this._picking = 'start';
- Object.defineProperty(this, 'calendars', {
- get: (function(_this) {
- return function() {
- return _this._calendars;
- };
- })(this)
- });
- Object.defineProperty(this, 'endInput', {
- value: this._dom.endInput
- });
- Object.defineProperty(this, 'startInput', {
- value: this._dom.startInput
- });
- Object.defineProperty(this, 'picking', {
- get: (function(_this) {
- return function() {
- return _this._picking;
- };
- })(this)
- });
- ref = [this.startInput, this.endInput];
- for (i = 0, len = ref.length; i < len; i++) {
- input = ref[i];
- $.listen(input, {
- 'click': function(ev) {
- return ev.target.focus();
- },
- 'focus': (function(_this) {
- return function(ev) {
- if (ev.target === _this.startInput) {
- _this._picking = 'start';
- } else {
- _this._picking = 'end';
- }
- return _this.open();
- };
- })(this),
- 'blur': (function(_this) {
- return function() {
- var activeInput;
- activeInput = document.activeElement;
- if (_this.startInput === activeInput || _this.endInput === activeInput) {
- return;
- }
- return _this.close('blur');
- };
- })(this),
- 'change': (function(_this) {
- return function(ev) {
- var date, dateRange;
- if (ev.caller === _this) {
- return;
- }
- date = Calendar.parseDate(ev.target.value, _this.parsers);
- if (date) {
- dateRange = _this.calendars[0].dateRange;
- if (_this.picking === 'start') {
- dateRange[0] = date;
- } else {
- dateRange[1] = date;
- }
- return _this.pick(dateRange, {
- 'source': 'input'
- });
- }
- };
- })(this)
- });
- }
- eventListeners = {};
- eventListeners[this.calendars[0]._et('pick')] = (function(_this) {
- return function(ev) {
- var dateRange;
- dateRange = _this.calendars[0].dateRange;
- if (_this.picking === 'start') {
- dateRange[0] = ev.date;
- } else {
- dateRange[1] = ev.date;
- }
- return _this.pick(dateRange, {
- 'source': 'calendar'
- });
- };
- })(this);
- eventListeners[this.calendars[0]._et('view')] = (function(_this) {
- return function(ev) {
- if (_this.calendars.indexOf(ev.calendar) === 0) {
- return _this.calendars[1].sync(_this.calendars[0], 1);
- } else {
- return _this.calendars[0].sync(_this.calendars[1], -1);
- }
- };
- })(this);
- $.listen(this.calendars[0].calendar, eventListeners);
- $.listen(this.calendars[1].calendar, eventListeners);
- }
-
- DateRangePicker.prototype.close = function(reason) {
- return DateRangePicker.__super__.close.call(this, this.startInput, 'mh-date-range-picker', reason);
- };
-
- DateRangePicker.prototype.open = function() {
- var calendar, closedClass, dateRange, endDate, endStr, i, input, len, ref, startDate, startStr, viewDate, viewStrs;
- input = this.startInput;
- if (this.picking === 'end') {
- input = this.endInput;
- }
- startDate = Calendar.parseDate(this.startInput.value, this.parsers);
- endDate = Calendar.parseDate(this.endInput.value, this.parsers);
- dateRange = this.calendars[0].dateRange;
- if (startDate) {
- dateRange[0] = startDate;
- }
- if (endDate) {
- dateRange[1] = endDate;
- }
- if (dateRange[1] < dateRange[0]) {
- this.pick([dateRange[1], dateRange[0]]);
- this.endInput.focus();
- return;
- }
- ref = this.calendars;
- for (i = 0, len = ref.length; i < len; i++) {
- calendar = ref[i];
- calendar.select(dateRange[0], dateRange[1]);
- }
- startStr = (dateRange[0].getMonth()) + "." + (dateRange[0].getFullYear());
- endStr = (dateRange[1].getMonth()) + "." + (dateRange[1].getFullYear());
- viewStrs = [this.calendars[0].month + "." + this.calendars[0].year, this.calendars[1].month + "." + this.calendars[1].year];
- if (viewStrs.indexOf(startStr) === -1 && viewStrs.indexOf(endStr) === -1) {
- viewDate = dateRange[0];
- this.calendars[0].goto(viewDate.getMonth(), viewDate.getFullYear());
- }
- this._track(this.pinToStart ? this.startInput : input);
- closedClass = this._bem('mh-date-range-picker', '', 'closed');
- this._dom.picker.classList.remove(closedClass);
- this._isOpen = true;
- return $.dispatch(this.startInput, this._et('open'));
- };
-
- DateRangePicker.prototype.pick = function(dateRange, source) {
- var calendar, evData, i, len, ref;
- ref = this.calendars;
- for (i = 0, len = ref.length; i < len; i++) {
- calendar = ref[i];
- calendar.select(dateRange[0], dateRange[1]);
- }
- evData = {
- 'dateRange': dateRange,
- 'source': source
- };
- if ($.dispatch(this.startInput, this._et('pick'), evData)) {
- this.constructor.behaviours.input[this._behaviours.input](this, dateRange);
- $.dispatch(this.startInput, this._et('picked'), evData);
- if (this.picking === 'start') {
- this.endInput.focus();
- } else {
- this.startInput.focus();
- }
- if (this.closeOnPick) {
- return this.close();
- }
- }
- };
-
- DateRangePicker.prototype._et = function(eventName) {
- return "mh-date-range-picker--" + eventName;
- };
-
- DateRangePicker.behaviours = {
- input: {
- 'set-value': function(dateRangePicker, dateRange) {
- var format;
- format = Calendar.formats[dateRangePicker.format];
- dateRangePicker.startInput.value = format(dateRange[0]);
- $.dispatch(dateRangePicker.startInput, 'change', {
- caller: datePicker
- });
- dateRangePicker.endInput.value = format(dateRange[1]);
- return $.dispatch(dateRangePicker.endInput, 'change', {
- caller: datePicker
- });
- }
- }
- };
-
- return DateRangePicker;
-
- })(BasePicker);
-
- module.exports = {
- Calendar: Calendar,
- DatePicker: DatePicker,
- DateRangePicker: DateRangePicker
- };
-
-
-/***/ },
-/* 3 */
-/***/ function(module, exports, __webpack_require__) {
-
- !function(e,t){ true?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ManhattanEssentials=t():e.ManhattanEssentials=t()}(this,function(){return function(e){function __webpack_require__(r){if(t[r])return t[r].exports;var n=t[r]={exports:{},id:r,loaded:!1};return e[r].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}var t={};return __webpack_require__.m=e,__webpack_require__.c=t,__webpack_require__.p="",__webpack_require__(0)}([function(e,t,r){e.exports=r(1)},function(e,t){var r,n,u,o,i,a,c,s,p=[].indexOf||function(e){for(var t=0,r=this.length;t=0?r[n]=u:r.setAttribute(n,u);return r},c=function(e,t){return null==t&&(t=document),Array.prototype.slice.call(t.querySelectorAll(e))},s=function(e,t){return null==t&&(t=document),t.querySelector(e)},u=function(e,t,r){var n,u,o;null==r&&(r={}),n=document.createEvent("Event"),n.initEvent(t,!0,!0);for(u in r)o=r[u],n[u]=o;return e.dispatchEvent(n)},i=function(e,t){var r,n,u,o;o=[];for(n in t)u=t[n],o.push(function(){var t,o,i,a;for(i=n.split(/\s+/),a=[],t=0,o=i.length;t ref1; i = ref <= ref1 ? ++j : --j) {
- weekday = $.create('div', {
- 'class': this._bem('mh-calendar', 'weekday')
- });
- weekdayIndex = i;
- if (i >= this.weekdayNames.length) {
- weekdayIndex -= this.weekdayNames.length;
- }
- weekday.innerHTML = this.weekdayNames[weekdayIndex];
- this._dom.weekdays.appendChild(weekday);
- }
- this._dom.dates = $.create('div', {
- 'class': this._bem('mh-calendar', 'dates')
- });
- this._dom.calendar.appendChild(this._dom.dates);
- for (i = k = 0, ref2 = 7 * 6; 0 <= ref2 ? k < ref2 : k > ref2; i = 0 <= ref2 ? ++k : --k) {
- date = $.create('div', {
- 'class': this._bem('mh-calendar', 'date')
- });
- this._dom.dates.appendChild(date);
- }
- Object.defineProperty(this, 'calendar', {
- value: this._dom.calendar
- });
- Object.defineProperty(this, 'parent', {
- value: this._dom.parent
- });
- Object.defineProperty(this, 'dateRange', {
- get: function() {
- return this._dateRange.slice();
- }
- });
- Object.defineProperty(this, 'month', {
- get: function() {
- return this._month;
- }
- });
- Object.defineProperty(this, 'year', {
- get: function() {
- return this._year;
- }
- });
- $.listen(this._dom.calendar, {
- 'mousedown': function(ev) {
- return ev.preventDefault();
- }
- });
- $.listen(this._dom.next, {
- 'click': (function(_this) {
- return function(ev) {
- ev.preventDefault();
- return _this.next();
- };
- })(this)
- });
- $.listen(this._dom.previous, {
- 'click': (function(_this) {
- return function(ev) {
- ev.preventDefault();
- return _this.previous();
- };
- })(this)
- });
- $.listen(this._dom.dates, {
- 'click': (function(_this) {
- return function(ev) {
- var blockedCSS, dateElm;
- ev.preventDefault();
- dateElm = ev.target;
- if (dateElm === _this._dom.dates) {
- return;
- }
- while (dateElm.parentNode !== _this._dom.dates) {
- dateElm = dateElm.parentNode;
- }
- blockedCSS = _this._bem('mh-calendar', 'date', 'blocked');
- if (dateElm.classList.contains(blockedCSS)) {
- return;
- }
- return $.dispatch(_this.calendar, _this._et('pick'), {
- 'calendar': _this,
- 'date': dateElm.__mh_date
- });
- };
- })(this)
- });
- this.update();
- }
-
- Calendar.prototype.destroy = function() {
- if (this.calendar.parentNode === this.parent) {
- return this.parent.removeChild(this.calendar);
- }
- };
-
- Calendar.prototype.goto = function(month, year) {
- if (this._month === month && year === this._year) {
- return;
- }
- this._month = month;
- this._year = year;
- this.update();
- return $.dispatch(this.calendar, this._et('view'), {
- 'calendar': this,
- 'month': month,
- 'year': year
- });
- };
-
- Calendar.prototype.next = function() {
- return this.offset(1);
- };
-
- Calendar.prototype.offset = function(months, years) {
- var month, year;
- if (years == null) {
- years = 0;
- }
- if (months > 0) {
- years += Math.floor(Math.abs(months) / 12);
- } else {
- years -= Math.floor(Math.abs(months) / 12);
- }
- months = months % 12;
- month = this._month + months;
- year = this._year + years;
- if (month < 0) {
- month = 12 + month;
- year -= 1;
- } else if (month > 11) {
- month = month - 12;
- year += 1;
- }
- return this.goto(month, year);
- };
-
- Calendar.prototype.previous = function() {
- return this.offset(-1);
- };
-
- Calendar.prototype.select = function(startDate, endDate) {
- if (endDate == null) {
- endDate = null;
- }
- if (endDate) {
- this._dateRange = [startDate, endDate];
- } else {
- this._dateRange = [startDate, startDate];
- }
- return this.update();
- };
-
- Calendar.prototype.sync = function(otherCalendar, months, years) {
- var month, year;
- if (years == null) {
- years = 0;
- }
- if (months > 0) {
- years += Math.floor(Math.abs(months) / 12);
- } else {
- years -= Math.floor(Math.abs(months) / 12);
- }
- months = months % 12;
- month = otherCalendar.month + months;
- year = otherCalendar.year + years;
- if (month < 0) {
- month = 12 + month;
- year -= 1;
- } else if (month > 11) {
- month = month - 12;
- year += 1;
- }
- if (this._month === month && year === this._year) {
- return;
- }
- this._month = month;
- this._year = year;
- return this.update();
- };
-
- Calendar.prototype.update = function() {
- var classList, date, dateElm, daysOffset, i, j, ref, results, test, today, weekday;
- this._dom.month.innerHTML = this.monthNames[this.month] + ", " + this.year;
- weekday = new Date(this.year, this.month, 1).getDay();
- console.log(weekday, this.firstWeekday);
- daysOffset = weekday - this.firstWeekday;
- if (daysOffset < 0) {
- daysOffset = 7 - Math.abs(daysOffset);
- }
- date = new Date(this.year, this.month, 1);
- if (daysOffset > 0) {
- date.setDate(date.getDate() - daysOffset);
- }
- results = [];
- for (i = j = 0, ref = 7 * 6; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
- dateElm = this._dom.dates.childNodes[i];
- dateElm.innerHTML = date.getDate();
- dateElm.__mh_date = new Date(date);
- dateElm.setAttribute('class', this._bem('mh-calendar', 'date'));
- classList = dateElm.classList;
- if (date.getMonth() !== this.month) {
- classList.add(this._bem('mh-calendar', 'date', 'blocked'));
- }
- if (this.minDate && this.minDate.getTime() > date.getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'blocked'));
- }
- if (this.maxDate && this.maxDate.getTime() < date.getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'blocked'));
- }
- test = this.constructor.behaviours.test[this._behaviours.test];
- if (!test(this, this.dates, date)) {
- classList.add(this._bem('mh-calendar', 'date', 'blocked'));
- }
- today = new Date();
- today.setHours(0, 0, 0, 0);
- if (date.getTime() === today.getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'today'));
- }
- if (date.getTime() === this.dateRange[0].getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'range-start'));
- }
- if (date.getTime() === this.dateRange[1].getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'range-end'));
- }
- if (date.getTime() > this.dateRange[0].getTime() && date.getTime() < this.dateRange[1].getTime()) {
- classList.add(this._bem('mh-calendar', 'date', 'in-range'));
- }
- results.push(date.setDate(date.getDate() + 1));
- }
- return results;
- };
-
- Calendar.prototype._bem = function(block, element, modifier) {
- var name;
- if (element == null) {
- element = '';
- }
- if (modifier == null) {
- modifier = '';
- }
- name = block;
- if (element) {
- name = name + "__" + element;
- }
- if (modifier) {
- name = name + "--" + modifier;
- }
- return name;
- };
-
- Calendar.prototype._et = function(eventName) {
- return "mh-calendar--" + eventName;
- };
-
- Calendar.parseDate = function(s, parsers) {
- var date, j, len, parser;
- if (s instanceof Date) {
- return s;
- }
- for (j = 0, len = parsers.length; j < len; j++) {
- parser = parsers[j];
- date = this.parsers[parser](s);
- if (date) {
- return date;
- }
- }
- };
-
- Calendar.proxyOptions = function(prefix, options, input) {
- var _parse, _split, defaults, j, len, option, proxy, ref, v;
- defaults = Calendar.getDefaultConfig();
- defaults.parsers = [];
- proxy = {};
- $.config(proxy, defaults, options, input, prefix);
- _parse = function(s, parsers) {
- return Calendar.parseDate(s, parsers);
- };
- _split = function(s) {
- var v;
- return (function() {
- var j, len, ref, results;
- ref = s.split(',');
- results = [];
- for (j = 0, len = ref.length; j < len; j++) {
- v = ref[j];
- if (v.trim()) {
- results.push(v.trim());
- }
- }
- return results;
- })();
- };
- if (typeof proxy.firstWeekday === 'string') {
- proxy.firstWeekday = Number(proxy.firstWeekday);
- }
- ref = ['dates', 'monthNames', 'parsers', 'weekdayNames'];
- for (j = 0, len = ref.length; j < len; j++) {
- option = ref[j];
- if (typeof proxy[option] === 'string') {
- proxy[option] = _split(proxy[option]);
- }
- }
- if (typeof proxy.minDate === 'string') {
- proxy.minDate = _parse(proxy.minDate, proxy.parsers);
- }
- if (typeof proxy.maxDate === 'string') {
- proxy.maxDate = _parse(proxy.maxDate, proxy.parsers);
- }
- proxy.dates = (function() {
- var k, len1, ref1, results;
- ref1 = proxy.dates;
- results = [];
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- v = ref1[k];
- if (_parse(v, proxy.parsers)) {
- results.push(_parse(v, proxy.parsers));
- }
- }
- return results;
- })();
- delete proxy.parsers;
- return proxy;
- };
-
- Calendar.behaviours = {
- test: {
- 'any': function(calendar, dates, date) {
- return true;
- },
- 'excluding': function(calendar, dates, date) {
- var j, len, other_date;
- for (j = 0, len = dates.length; j < len; j++) {
- other_date = dates[j];
- if (date.getTime() === other_date.getTime()) {
- return false;
- }
- }
- return true;
- },
- 'only': function(calendar, dates, date) {
- var j, len, other_date;
- for (j = 0, len = dates.length; j < len; j++) {
- other_date = dates[j];
- if (date.getTime() === other_date.getTime()) {
- return true;
- }
- }
- return false;
- },
- 'weekdays': function(calendar, weekdays, date) {
- return weekdays.indexOf(date.getDay()) > -1;
- }
- }
- };
-
- Calendar.formats = {
- 'dmy': function(date) {
- var dd, mm, yyyy;
- dd = ("00" + (date.getDate())).slice(-2);
- mm = ("00" + (date.getMonth() + 1)).slice(-2);
- yyyy = date.getFullYear();
- return dd + "/" + mm + "/" + yyyy;
- },
- 'human_en': function(date) {
- var month_name;
- month_name = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][date.getMonth()];
- return (date.getDate()) + " " + month_name + " " + (date.getFullYear());
- },
- 'human_abbr_en': function(date) {
- var month_name;
- month_name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()];
- return (date.getDate()) + " " + month_name + " " + (date.getFullYear());
- },
- 'iso': function(date) {
- var dd, mm, yyyy;
- dd = ("00" + (date.getDate())).slice(-2);
- mm = ("00" + (date.getMonth() + 1)).slice(-2);
- yyyy = date.getFullYear();
- return yyyy + "-" + mm + "-" + dd;
- },
- 'mdy': function(date) {
- var dd, mm, yyyy;
- dd = ("00" + (date.getDate())).slice(-2);
- mm = ("00" + (date.getMonth() + 1)).slice(-2);
- yyyy = date.getFullYear();
- return mm + "/" + dd + "/" + yyyy;
- }
- };
-
- Calendar.parsers = {
- 'dmy': function(s) {
- var date, dateExp, day, match, month, year;
- dateExp = /^(\d{1,2})(\/|\.|\-)(\d{1,2})(\/|\.|\-)(\d{2}|\d{4})$/;
- match = dateExp.exec(s);
- if (!match) {
- return;
- }
- year = Number(match[5]);
- month = Number(match[3]) - 1;
- day = Number(match[1]);
- if (year < 100) {
- year += parseInt((new Date()).getFullYear() / 100) * 100;
- }
- date = new Date(year, month, day);
- if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
- return;
- }
- return date;
- },
- 'human_en': function(s) {
- var component, components, date, day, i, j, k, len, len1, month, month_names, month_short_names, ref, ref1, year;
- month_names = {
- 'january': 0,
- 'february': 1,
- 'march': 2,
- 'april': 3,
- 'may': 4,
- 'june': 5,
- 'july': 6,
- 'august': 7,
- 'september': 8,
- 'october': 9,
- 'november': 10,
- 'december': 11
- };
- month_short_names = {
- 'jan': 0,
- 'feb': 1,
- 'mar': 2,
- 'apr': 3,
- 'may': 4,
- 'jun': 5,
- 'jul': 6,
- 'aug': 7,
- 'sep': 8,
- 'oct': 9,
- 'nov': 10,
- 'dec': 11
- };
- s = s.toLowerCase();
- s = s.replace(',', ' ');
- s = s.replace(/(\d)st/g, '$1 ');
- s = s.replace(/(\d)nd/g, '$1 ');
- s = s.replace(/(\d)rd/g, '$1 ');
- s = s.replace(/(\d)th/g, '$1 ');
- s = s.trim();
- components = s.split(/\s+/);
- if (components.length > 3) {
- return;
- }
- month = (new Date()).getMonth();
- year = (new Date()).getFullYear();
- if (components.length > 1) {
- month = null;
- ref = components.slice();
- for (i = j = 0, len = ref.length; j < len; i = ++j) {
- component = ref[i];
- if (month_names.hasOwnProperty(component)) {
- month = month_names[component];
- } else if (month_short_names.hasOwnProperty(component)) {
- month = month_short_names[component];
- }
- if (month !== null) {
- components.splice(i, 1);
- break;
- }
- }
- if (month === null) {
- return;
- }
- year = null;
- ref1 = components.slice();
- for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) {
- component = ref1[i];
- if (component.length === 4) {
- year = Number(component);
- components.splice(i, 1);
- break;
- }
- }
- if (year === null && components.length === 2) {
- year = Number(components[1]);
- components.splice(1, 1);
- }
- if (year === (0/0)) {
- return;
- }
- if (year === null) {
- year = (new Date()).getFullYear();
- }
- if (year < 100) {
- year += parseInt((new Date()).getFullYear() / 100) * 100;
- }
- }
- day = Number(components[0]);
- if (day === (0/0)) {
- return;
- }
- date = new Date(year, month, day);
- if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
- return;
- }
- return date;
- },
- 'iso': function(s) {
- var date, dateExp, day, match, month, year;
- dateExp = /^(\d{4})-(\d{2})-(\d{2})$/;
- match = dateExp.exec(s);
- if (!match) {
- return;
- }
- year = Number(match[1]);
- month = Number(match[2]) - 1;
- day = Number(match[3]);
- date = new Date(year, month, day);
- if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
- return;
- }
- return date;
- },
- 'mdy': function(s) {
- var date, dateExp, day, match, month, year;
- dateExp = /^(\d{1,2})(\/|\.|\-)(\d{1,2})(\/|\.|\-)(\d{2}|\d{4})$/;
- match = dateExp.exec(s);
- if (!match) {
- return;
- }
- year = Number(match[5]);
- month = Number(match[1]) - 1;
- day = Number(match[3]);
- if (year < 100) {
- year += parseInt((new Date()).getFullYear() / 100) * 100;
- }
- date = new Date(year, month, day);
- if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
- return;
- }
- return date;
- }
- };
-
- return Calendar;
-
- })();
-
- module.exports = {
- Calendar: Calendar
- };
-
-
-/***/ }
-/******/ ])
-});
-;
\ No newline at end of file
diff --git a/coffee/package.json b/coffee/package.json
deleted file mode 100644
index ae20b65..0000000
--- a/coffee/package.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "name": "manhattan-date-picker",
- "version": "0.0.7",
- "description": "Date picker support for form fields.",
- "main": "dist/index.js",
- "scripts": {
- "dist": "NODE_ENV=dist webpack --progress",
- "live": "webpack-dev-server --progress",
- "watch": "webpack --watch --progress",
- "test": "mocha --require coffee-script/register --compilers coffee:coffee-script"
- },
- "repository": {
- "type": "git",
- "url": "git@git.getme.co.uk:manhattan/manhattan_js_date-picker.git"
- },
- "keywords": [
- "typeahead",
- "manhattan"
- ],
- "author": "Anthony Blackshaw",
- "license": "MIT",
- "devDependencies": {
- "chai": "^3.5.0",
- "coffee-loader": "^0.7.2",
- "coffee-script": "^1.11.1",
- "coffeelint": "^1.16.0",
- "coffeelint-loader": "^0.1.1",
- "css-loader": "^0.25.0",
- "extract-loader": "0.0.2",
- "file-loader": "^0.9.0",
- "jsdom": "^9.8.3",
- "manhattan-essentials": "0.0.10",
- "mocha": "^3.1.2",
- "mocha-jsdom": "^1.1.0",
- "node-sass": "^3.11.1",
- "sass-loader": "^4.0.2",
- "sasslint-loader": "0.0.1",
- "sinon": "^1.17.6",
- "sinon-chai": "^2.8.0",
- "webpack": "^1.13.3",
- "webpack-dev-server": "^1.16.2"
- }
-}
diff --git a/coffee/src/scripts/calendar.coffee b/coffee/src/scripts/calendar.coffee
deleted file mode 100644
index 0e8d4f2..0000000
--- a/coffee/src/scripts/calendar.coffee
+++ /dev/null
@@ -1,733 +0,0 @@
-$ = require 'manhattan-essentials'
-
-
-class Calendar
-
- # A calendar from which a date can be selected.
-
- @getDefaultConfig: () ->
- # Return the default configuration options for the `Calendar` class
- return {
- # Typically a list of dates, the `dates` option is used in
- # conjunction with the `test` behaviour to determine which dates
- # can be picked.
- dates: [],
-
- # The earliest date that can be selected
- minDate: null,
-
- # The latest date that can be selected
- maxDate: null,
-
- # The weekday that will be displayed first in the calendar view.
- # Weekday must be a number between 0 (Sunday) and 6 (Saturday).
- firstWeekday: 1,
-
- # A list of all month names that will be used when displaying
- # the month (must contain exactly 12 names).
- monthNames: [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December'
- ],
-
- # A list of weekday names that will be used when displaying the
- # days of the week (must contain exactly 7 names).
- weekdayNames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
- }
-
- constructor: (parent, options={}) ->
-
- # Configure the instance
- $.config(this, Calendar.getDefaultConfig(), options)
-
- # Set up and configure behaviours
- @_behaviours = {}
- $.config(@_behaviours, {test: 'any'}, options)
-
- # Initially the calendar view will focus on today's date
- today = new Date()
- today.setHours(0, 0, 0, 0)
-
- # The date range currently selected
- @_dateRange = [today, today]
-
- # The month and year currently displayed by the calendar
- @_month = today.getMonth()
- @_year = today.getFullYear()
-
- # Domain for related DOM elements
- @_dom = {}
-
- # Store a reference to the parent the calendar is being added to
- @_dom.parent = parent
-
- # Build the elements required for the calendar
-
- # Calendar
- @_dom.calendar = $.create('div', {'class': @_bem('mh-calendar')})
- parent.appendChild(@_dom.calendar)
-
- # Nav
- @_dom.nav = $.create('div', {'class': @_bem('mh-calendar', 'nav')})
- @_dom.calendar.appendChild(@_dom.nav)
-
- @_dom.month = $.create('div', {'class': @_bem('mh-calendar', 'month')})
- @_dom.nav.appendChild(@_dom.month)
-
- @_dom.next = $.create(
- 'div', {'class': @_bem('mh-calendar', 'next')})
- @_dom.previous = $.create(
- 'div', {'class': @_bem('mh-calendar', 'previous')})
- @_dom.nav.appendChild(@_dom.next)
- @_dom.nav.appendChild(@_dom.previous)
-
- # Weekdays
- @_dom.weekdays = $.create(
- 'div', {'class': @_bem('mh-calendar', 'weekdays')})
- @_dom.calendar.appendChild(@_dom.weekdays)
-
- for i in [@firstWeekday...(@firstWeekday + 7)]
- weekday = $.create(
- 'div', {'class': @_bem('mh-calendar', 'weekday')})
-
- weekdayIndex = i
- if i >= @weekdayNames.length
- weekdayIndex -= @weekdayNames.length
- weekday.innerHTML = @weekdayNames[weekdayIndex]
-
- @_dom.weekdays.appendChild(weekday)
-
- # Dates
- @_dom.dates = $.create('div', {'class': @_bem('mh-calendar', 'dates')})
- @_dom.calendar.appendChild(@_dom.dates)
-
- for i in [0...(7 * 6)]
- date = $.create('div', {'class': @_bem('mh-calendar', 'date')})
- @_dom.dates.appendChild(date)
-
- # Define read-only properties
- Object.defineProperty(this, 'calendar', {value: @_dom.calendar})
- Object.defineProperty(this, 'parent', {value: @_dom.parent})
- Object.defineProperty(
- this, 'dateRange', {get: () -> return @_dateRange.slice()})
- Object.defineProperty(this, 'month', {get: () -> return @_month})
- Object.defineProperty(this, 'year', {get: () -> return @_year})
-
- # Set up event listeners for the calendar
- $.listen @_dom.calendar,
- 'mousedown': (ev) ->
- # Prevent picking from the calendar switching focus
- ev.preventDefault()
-
- $.listen @_dom.next,
- 'click': (ev) =>
- ev.preventDefault()
- @next()
-
- $.listen @_dom.previous,
- 'click': (ev) =>
- ev.preventDefault()
- @previous()
-
- $.listen @_dom.dates,
- 'click': (ev) =>
- ev.preventDefault()
-
- # Find the date element
- dateElm = ev.target
-
- if dateElm is @_dom.dates
- return
-
- while dateElm.parentNode isnt @_dom.dates
- dateElm = dateElm.parentNode
-
- # Check the date isn't been blocked
- blockedCSS = @_bem('mh-calendar', 'date', 'blocked')
- if dateElm.classList.contains(blockedCSS)
- return
-
- # Dispatch a pick event against the calendar
- $.dispatch(
- @calendar,
- @_et('pick'),
- {'calendar': this, 'date': dateElm.__mh_date}
- )
-
- # Update the calendar view
- @update()
-
- # Public methods
-
- destroy: () =>
- # Destroy the calendar (remove it from the DOM)
- if @calendar.parentNode == @parent
- @parent.removeChild(@calendar)
-
- goto: (month, year) =>
- # Display the given month, year in the calendar
-
- # If the month and year match then there's nothing to do
- if @_month == month and year == @_year
- return
-
- # Update the view
- @_month = month
- @_year = year
- @update()
-
- # Dispatch a goto event against the calendar
- $.dispatch(
- @calendar,
- @_et('view'),
- {'calendar': this, 'month': month, 'year': year}
- )
-
- next: () ->
- # Display the next month in the calendar
- @offset(1)
-
- offset: (months, years=0) ->
- # Display the given offset (from the current month, year) in the
- # calendar.
-
- # Handle month offsets in excess of 1 year (12 months)
- if months > 0
- years += Math.floor(Math.abs(months) / 12)
- else
- years -= Math.floor(Math.abs(months) / 12)
- months = months % 12
-
- # Calculate the new month, year
- month = @_month + months
- year = @_year + years
-
- # Handle rotating the year when the month value is < 0 or > 11
- if month < 0
- month = 12 + month
- year -= 1
-
- else if month > 11
- month = month - 12
- year += 1
-
- # Apply the offset
- @goto(month, year)
-
- previous: () ->
- # Display the previous month in the calendar
- @offset(-1)
-
- select: (startDate, endDate=null) ->
- # Set the selected date/date range for the calendar
- if endDate
- @_dateRange = [startDate, endDate]
- else
- @_dateRange = [startDate, startDate]
-
- @update()
-
- sync: (otherCalendar, months, years=0) ->
- # Sync this calendar view with another with the given offset
-
- # Handle month offsets in excess of 1 year (12 months)
- if months > 0
- years += Math.floor(Math.abs(months) / 12)
- else
- years -= Math.floor(Math.abs(months) / 12)
- months = months % 12
-
- # Calculate the new month, year
- month = otherCalendar.month + months
- year = otherCalendar.year + years
-
- # Handle rotating the year when the month value is < 0 or > 11
- if month < 0
- month = 12 + month
- year -= 1
-
- else if month > 11
- month = month - 12
- year += 1
-
- # If the month and year match then there's nothing to do
- if @_month == month and year == @_year
- return
-
- # Update the view
- @_month = month
- @_year = year
- @update()
-
- update: () ->
- # Update the calendar based on the current date range
-
- # Update the month, year
- @_dom.month.innerHTML = "#{@monthNames[@month]}, #{@year}"
-
- # Find the first weekday in the month
- weekday = new Date(@year, @month, 1).getDay()
-
- # Determine the start date for the calendar month given the the first
- # day.
- daysOffset = weekday - @firstWeekday
- if daysOffset < 0
- daysOffset = 7 - Math.abs(daysOffset)
-
- date = new Date(@year, @month, 1)
- if daysOffset > 0
- date.setDate(date.getDate() - daysOffset)
-
- # Update the dates
- for i in [0...(7 * 6)]
- dateElm = @_dom.dates.childNodes[i]
-
- # Set the contents of the date
- dateElm.innerHTML = date.getDate()
-
- # Associate the JS date with the element
- dateElm.__mh_date = new Date(date)
-
- # Clear all existing classes for the date
- dateElm.setAttribute('class', @_bem('mh-calendar', 'date'))
-
- # Add any modified classes to the date
- classList = dateElm.classList
-
- # Outside of the current months scope (blocked)
- if date.getMonth() != @month
- classList.add(@_bem('mh-calendar', 'date', 'blocked'))
-
- # Check if the date is within the min/max range
- if @minDate and @minDate.getTime() > date.getTime()
- classList.add(@_bem('mh-calendar', 'date', 'blocked'))
-
- if @maxDate and @maxDate.getTime() < date.getTime()
- classList.add(@_bem('mh-calendar', 'date', 'blocked'))
-
- # Check if the date is blocked
- test = @constructor.behaviours.test[@_behaviours.test]
- if not test(this, @dates, date)
- classList.add(@_bem('mh-calendar', 'date', 'blocked'))
-
- # Today's date
- today = new Date()
- today.setHours(0, 0, 0, 0)
- if date.getTime() is today.getTime()
- classList.add(@_bem('mh-calendar', 'date', 'today'))
-
- # Selected date
- if date.getTime() is @dateRange[0].getTime()
- classList.add(@_bem('mh-calendar', 'date', 'range-start'))
-
- if date.getTime() is @dateRange[1].getTime()
- classList.add(@_bem('mh-calendar', 'date', 'range-end'))
-
- if date.getTime() > @dateRange[0].getTime() and
- date.getTime() < @dateRange[1].getTime()
- classList.add(@_bem('mh-calendar', 'date', 'in-range'))
-
- # Increment the date by one day
- date.setDate(date.getDate() + 1)
-
- # Private methods
-
- _bem: (block, element='', modifier='') ->
- # Build and return a class name
- name = block
- if element
- name = "#{name}__#{element}"
- if modifier
- name = "#{name}--#{modifier}"
- return name
-
- _et: (eventName) ->
- # Generate an event type name
- return "mh-calendar--#{eventName}"
-
- # Class methods
-
- @parseDate: (s, parsers) ->
- # Parse a date string (if a date is supplied it'll be returned as is)
-
- # Check if we've been sent a date
- if s instanceof Date
- return s
-
- # Attempt to parse the string as a date
- for parser in parsers
- date = @parsers[parser](s)
- if date
- return date
-
- @proxyOptions: (prefix, options, input) ->
- # Return a set of config options for the calendar based on a set of user
- # defined options and an input element.
- #
- # The `proxyOptions` method is typically used by classes using one or
- # more instances of the `Calendar` class and wishing to configure it
- # through their own config options and input.
-
- # We add a default empty list of date parsers to the proxy to allow this
- # to be configured by the caller.
- defaults = Calendar.getDefaultConfig()
- defaults.parsers = []
-
- # Initially we configure a set of proxy options
- proxy = {}
- $.config(proxy, defaults, options, input, prefix)
-
- # Data options passed as strings need to be converted to native JS types
-
- _parse = (s, parsers) ->
- # Attempt to parse a string to a date
- return Calendar.parseDate(s, parsers)
-
- _split = (s) ->
- # Convert a comma separated list of values to a native list
- return (v.trim() for v in s.split(',') when v.trim())
-
- # Convert numbers
- if typeof(proxy.firstWeekday) is 'string'
- proxy.firstWeekday = Number(proxy.firstWeekday)
-
- # Convert comma separated strings to native lists
- for option in ['dates', 'monthNames', 'parsers', 'weekdayNames']
- if typeof(proxy[option]) is 'string'
- proxy[option] = _split(proxy[option])
-
- # Convert date strings to native dates
- if typeof(proxy.minDate) is 'string'
- proxy.minDate = _parse(proxy.minDate, proxy.parsers)
-
- if typeof(proxy.maxDate) is 'string'
- proxy.maxDate = _parse(proxy.maxDate, proxy.parsers)
-
- proxy.dates = (_parse(v, proxy.parsers) for v in proxy.dates \
- when _parse(v, proxy.parsers))
-
- # Remove parsers from the proxy
- delete proxy.parsers
-
- return proxy
-
- # Behaviours
-
- @behaviours:
-
- test:
- 'any': (calendar, dates, date) ->
- # Allow any date
- return true
-
- 'excluding': (calendar, dates, date) ->
- # Only enable dates which are not in the list of dates
- for other_date in dates
- if date.getTime() is other_date.getTime()
- return false
- return true
-
- 'only': (calendar, dates, date) ->
- # Only enable dates which are in the list of dates
- for other_date in dates
- if date.getTime() is other_date.getTime()
- return true
- return false
-
- 'weekdays': (calendar, weekdays, date) ->
- # Only enable dates for the given list of weekdays
- return weekdays.indexOf(date.getDay()) > -1
-
- # Formats
-
- @formats:
-
- 'dmy': (date) ->
- # Format a date as `dd/mm/yyyy`
- dd = "00#{date.getDate()}".slice(-2)
- mm = "00#{date.getMonth() + 1}".slice(-2)
- yyyy = date.getFullYear()
- return "#{dd}/#{mm}/#{yyyy}"
-
- 'human_en': (date) ->
- # Format a date as `{day} {full month name} {full year}`, e.g
- # `22 January 2011`.
- month_name = [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December'
- ][date.getMonth()]
- return "#{date.getDate()} #{month_name} #{date.getFullYear()}"
-
- 'human_abbr_en': (date) ->
- # Format a date as `{day} {month name} {full year}`, e.g:
- #
- # - `22 Jan 2016`
- month_name = [
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'Jun',
- 'Jul',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec'
- ][date.getMonth()]
- return "#{date.getDate()} #{month_name} #{date.getFullYear()}"
-
- 'iso': (date) ->
- # Format a date as ISO 8601 (e.g `yyyy-mm-dd`)
- dd = "00#{date.getDate()}".slice(-2)
- mm = "00#{date.getMonth() + 1}".slice(-2)
- yyyy = date.getFullYear()
- return "#{yyyy}-#{mm}-#{dd}"
-
- 'mdy': (date) ->
- # Format a date as `mm/dd/yyyy`
- dd = "00#{date.getDate()}".slice(-2)
- mm = "00#{date.getMonth() + 1}".slice(-2)
- yyyy = date.getFullYear()
- return "#{mm}/#{dd}/#{yyyy}"
-
- # Parsers
-
- @parsers:
-
- 'dmy': (s) ->
- # Return a date from a string using the format (`d/m/y`), the slash
- # separator can be a `/`, '-', or '.'
-
- # Parse the date information
- dateExp = /^(\d{1,2})(\/|\.|\-)(\d{1,2})(\/|\.|\-)(\d{2}|\d{4})$/
- match = dateExp.exec(s)
- if not match
- return
-
- # Generate a date
- year = Number(match[5])
- month = Number(match[3]) - 1
- day = Number(match[1])
-
- # If the year doesn't contain the century then we add the current
- # century to it.
- if year < 100
- year += parseInt((new Date()).getFullYear() / 100) * 100
-
- date = new Date(year, month, day)
-
- # Validate the date is as expected
- if date.getFullYear() isnt year or
- date.getMonth() isnt month or
- date.getDate() isnt day
- return
-
- return date
-
- 'human_en': (s) ->
- # Return a date from a string using a human readable format, e.g:
- #
- # - `2nd`
- # - `1 Aug`
- # - `15 Feb 17`
- # - `January 22, 2011`
- # - `Nov 22`
- #
- # The order of the date components is not important, one component
- # be a string representing the month, two other components must be
- # digits (numbers) representing the month and year.
-
- # Define the name of the months in english
- month_names = {
- 'january': 0,
- 'february': 1,
- 'march': 2,
- 'april': 3,
- 'may': 4,
- 'june': 5,
- 'july': 6,
- 'august': 7,
- 'september': 8,
- 'october': 9,
- 'november': 10,
- 'december': 11
- }
-
- month_short_names = {
- 'jan': 0,
- 'feb': 1,
- 'mar': 2,
- 'apr': 3,
- 'may': 4,
- 'jun': 5,
- 'jul': 6,
- 'aug': 7,
- 'sep': 8,
- 'oct': 9,
- 'nov': 10,
- 'dec': 11
- }
-
- # Clean up the date string removing commas as suffixes
- s = s.toLowerCase()
- s = s.replace(',', ' ')
- s = s.replace(/(\d)st/g, '$1 ')
- s = s.replace(/(\d)nd/g, '$1 ')
- s = s.replace(/(\d)rd/g, '$1 ')
- s = s.replace(/(\d)th/g, '$1 ')
- s = s.trim()
-
- # Split the date string into its components
- components = s.split(/\s+/)
-
- # Check there is not more than 3 components
- if components.length > 3
- return
-
- # If there's only one component then this must be the day so we
- # default the year and month to the current until we determine the
- # number of components.
- month = (new Date()).getMonth()
- year = (new Date()).getFullYear()
-
- # If we're dealing with more than one component we need to attempt
- # to extract the month (2+ components) and year (3 components).
- if components.length > 1
-
- # Find the month component
- month = null
- for component, i in components.slice()
-
- if month_names.hasOwnProperty(component)
- month = month_names[component]
-
- else if month_short_names.hasOwnProperty(component)
- month = month_short_names[component]
-
- if month isnt null
- components.splice(i, 1)
- break
-
- if month is null
- return
-
- # Find a 4 digit year
- year = null
- for component, i in components.slice()
- if component.length == 4
- year = Number(component)
- components.splice(i, 1)
- break
-
- # Check for 2 digit year
- if year is null and components.length == 2
- year = Number(components[1])
- components.splice(1, 1)
-
- if year is NaN
- return
-
- # Default to the current year
- if year is null
- year = (new Date()).getFullYear()
-
- # If the year doesn't contain the century then we add the
- # current century to it.
- if year < 100
- year += parseInt((new Date()).getFullYear() / 100) * 100
-
- # All that's left is the day
- day = Number(components[0])
-
- if day is NaN
- return
-
- # Generate the date
- date = new Date(year, month, day)
-
- # Validate the date is as expected
- if date.getFullYear() isnt year or
- date.getMonth() isnt month or
- date.getDate() isnt day
- return
-
- return date
-
- 'iso': (s) ->
- # Return a date from a string in ISO 8601 format (e.g `yyyy-mm-dd`)
-
- # Parse the date information
- dateExp = /^(\d{4})-(\d{2})-(\d{2})$/
- match = dateExp.exec(s)
- if not match
- return
-
- # Generate a date
- year = Number(match[1])
- month = Number(match[2]) - 1
- day = Number(match[3])
-
- date = new Date(year, month, day)
-
- # Validate the date is as expected
- if date.getFullYear() isnt year or
- date.getMonth() isnt month or
- date.getDate() isnt day
- return
-
- return date
-
- 'mdy': (s) ->
- # Return a date from a string using the format (`m/d/y`), the slash
- # separator can be a `/`, '-', or '.'
-
- # Parse the date information
- dateExp = /^(\d{1,2})(\/|\.|\-)(\d{1,2})(\/|\.|\-)(\d{2}|\d{4})$/
- match = dateExp.exec(s)
- if not match
- return
-
- # Generate a date
- year = Number(match[5])
- month = Number(match[1]) - 1
- day = Number(match[3])
-
- # If the year doesn't contain the century then we add the current
- # century to it.
- if year < 100
- year += parseInt((new Date()).getFullYear() / 100) * 100
-
- date = new Date(year, month, day)
-
- # Validate the date is as expected
- if date.getFullYear() isnt year or
- date.getMonth() isnt month or
- date.getDate() isnt day
- return
-
- return date
-
-
-module.exports = {Calendar: Calendar}
\ No newline at end of file
diff --git a/coffee/src/scripts/date-picker.coffee b/coffee/src/scripts/date-picker.coffee
deleted file mode 100644
index 8cbc290..0000000
--- a/coffee/src/scripts/date-picker.coffee
+++ /dev/null
@@ -1,540 +0,0 @@
-$ = require 'manhattan-essentials'
-
-Calendar = require('./calendar.coffee').Calendar
-
-
-class BasePicker
-
- # A base class that provides some shared functionality for date pickers.
-
- constructor: () ->
-
- # Flag indicating if the picker is currently open
- @_isOpen = false
- Object.defineProperty(this, 'isOpen', {get: () => return @_isOpen})
-
- # Set up event listeners for the picker
- $.listen window,
- 'fullscreenchange orientationchange resize': (ev) =>
- # We close the date picker if the window is resized
- if @isOpen
- @close('resize')
-
- # Public methods
-
- close: (input, block, reason) =>
- # Close the picker
-
- # Check the picker is open (otherwise there's nothing for us to do)
- if not @isOpen
- return
-
- # Hide the picker visually
- @_dom.picker.classList.add(@_bem(block, '', 'closed'))
-
- # Flag the picker as closed
- @_isOpen = false
-
- # Dispatch a close event
- $.dispatch(input, @_et('close'), {'reason': reason})
-
- # Private methods
-
- _bem: (block, element='', modifier='') ->
- # Build and return a class name
- name = block
- if element
- name = "#{name}__#{element}"
- if modifier
- name = "#{name}--#{modifier}"
- return name
-
- _track: (input) ->
- # Position and size the picker inline with an input element
-
- # Get the position of the input
- rect = input.getBoundingClientRect()
- top = rect.top += window.scrollY
- left = rect.left += window.scrollX
-
- # Position the picker
- @_dom.picker.style.top = "#{top + rect.height}px"
- @_dom.picker.style.left = "#{left}px"
-
-
-class DatePicker extends BasePicker
-
- # A class that provides a date picker against a form field.
-
- @clsPrefix: 'data-mh-date-picker--'
-
- constructor: (input, options={}) ->
- super()
-
- # Configure the instance
- $.config(
- this,
- {
- # Flag indicating if the picker should close when a date is
- # picked.
- closeOnPick: false,
-
- # The format that dates should be displayed in
- format: 'human_en',
-
- # A list of date parsers that will be used to attempt to parse
- # dates in string format.
- parsers: ['human_en', 'dmy', 'iso']
- },
- options,
- input,
- @constructor.clsPrefix
- )
-
- # Set up and configure behaviours
- @_behaviours = {}
-
- $.config(
- @_behaviours,
- {
- input: 'set-value'
- },
- options,
- input,
- @constructor.clsPrefix
- )
-
- # Domain for related DOM elements
- @_dom = {}
-
- # Store a reference to the input the date picker is being applied to (we
- # also store a reverse reference to this instance against the input).
- @_dom.input = input
- @_dom.input.__mh_datePicker = this
-
- # Build the elements required for the picker
- @_dom.picker = $.create(
- 'div',
- {
- 'class': [
- @_bem('mh-date-picker'),
- @_bem('mh-date-picker', '', 'closed')
- ].join(' ')
- }
- )
- document.body.appendChild(@_dom.picker)
-
- # Setup the calendar for the date picker
- proxyOptions = Calendar.proxyOptions(options, input)
- @_calendar = new Calendar(@_dom.picker, proxyOptions)
-
- # Define read-only properties
- Object.defineProperty(this, 'calendar', {get: () => @_calendar})
- Object.defineProperty(this, 'input', {value: @_dom.input})
-
- # Set up event listeners for the date picker
- $.listen @input,
- 'blur': () =>
- @close('blur')
- 'click': () => @open()
- 'focus': () => @open()
-
- 'change': (ev) =>
- # Ignore the request if the caller is the date picker itself
- if ev.caller is this
- return
-
- # When the input changes attempt to parse its value as a date
- # and replace the value with a formatted date.
- date = Calendar.parseDate(@input.value, @parsers)
- if date
- @pick(date, 'input')
-
- # Set up event listeners for the calendar
- eventListeners = {}
- eventListeners[@calendar._et('pick')] = (ev) =>
- @pick(ev.date, 'calendar')
-
- $.listen(@calendar.calendar, eventListeners)
-
- # Public methods
-
- close: (reason) ->
- super(@input, 'mh-date-picker', reason)
-
- open: () =>
- # Open the date picker
-
- # Parse the input's value as a date and if valid select it in the
- # calendar.
- date = Calendar.parseDate(@input.value, @parsers)
- if date
- @calendar.goto(date.getMonth(), date.getFullYear())
- @calendar.select(date)
-
- # Track the position of the picker inline with the input
- @_track()
-
- # Display the date picker visually
- @_dom.picker.classList.remove(@_bem('mh-date-picker', '', 'closed'))
-
- # Flag the picker as open
- @_isOpen = true
-
- # Dispatch an open event
- $.dispatch(@input, @_et('open'))
-
- pick: (date, source='') ->
- # Pick a date
-
- # Select the date in the calendar
- @calendar.select(date)
-
- # Dispatch a pick event against the input
- if $.dispatch(@input, @_et('pick'), {'date': date, 'source': source})
-
- # Set the date value
- @constructor.behaviours.input[@_behaviours.input](this, date)
-
- # Dispatch a picked event
- $.dispatch(@input, @_et('picked'), {'date': date, 'source': source})
-
- # Close the date picker if configured to
- if @closeOnPick
- @close({'reason': 'pick'})
-
- # Private methods
-
- _et: (eventName) ->
- # Generate an event type name
- return "mh-date-picker--#{eventName}"
-
- _track: () ->
- super(@input)
-
- # Behaviours
-
- @behaviours:
-
- # The `input` behaviour is used to set the value of the input when a
- # date is selected.
- input:
- 'set-hidden': (datePicker, date) ->
- # Set the value of the input to one formatted date and the value
- # of an associated hidden field to another.
-
- # Set the input's value
- dateStr = Calendar.formats[datePicker.format](date)
- datePicker.input.value = dateStr
-
- # Find the associated hidden field
- hiddenSelector = datePicker.input.getAttribute(
- "#{datePicker.constructor.clsPrefix}hidden"
- )
- hidden = $.one(hiddenSelector)
-
- # Find the associated hidden format
- hiddenFormat = datePicker.input.getAttribute(
- "#{datePicker.constructor.clsPrefix}hidden-format"
- )
-
- # Set the hidden fields value
- hiddenDateStr = Calendar.formats[hiddenFormat](date)
- hidden.value = hiddenDateStr
- $.dispatch(hidden, 'change')
-
- 'set-value': (datePicker, date) ->
- # Set the value of the input to the formatted date
-
- # Set the input's value
- dateStr = Calendar.formats[datePicker.format](date)
- datePicker.input.value = dateStr
-
- # We trigger a change event to help other applications detect
- # the change to the input field, we send the caller argument
- # with the event to prevent the event trigger a infinite cycle.
- $.dispatch(datePicker.input, 'change', {caller: datePicker})
-
- console.log dateStr
-
-
-class DateRangePicker extends BasePicker
-
- # A class that provides a date range picker against a form field.
-
- @clsPrefix: 'data-mh-date-range-picker--'
-
- constructor: (startInput, endInput, options={}) ->
- super()
-
- # Configure the instance
- $.config(
- this,
- {
- # Flag indicating if the picker should close when a date is
- # picked.
- closeOnPick: false,
-
- # The format that dates should be displayed in
- format: 'human_en',
-
- # A list of date parsers that will be used to attempt to parse
- # dates in string format.
- parsers: ['human_en', 'dmy', 'iso'],
-
- # Flag indicating if the date range picker should always open
- # relative to the start date (even when the end date has focus).
- pinToStart: false
- },
- options,
- startInput,
- @constructor.clsPrefix
- )
-
- # Set up and configure behaviours
- @_behaviours = {}
-
- $.config(
- @_behaviours,
- {
- input: 'set-value'
- },
- options,
- startInput,
- @constructor.clsPrefix
- )
-
- # Domain for related DOM elements
- @_dom = {}
-
- # Build the elements required for the picker
- @_dom.picker = $.create(
- 'div',
- {
- 'class': [
- @_bem('mh-date-range-picker'),
- @_bem('mh-date-range-picker', '', 'closed')
- ].join(' ')
- }
- )
- document.body.appendChild(@_dom.picker)
-
- # Store a reference to the inputs the date range picker is being applied
- # to (we also store a reverse reference to this instance against the
- # inputs).
- @_dom.startInput = startInput
- @_dom.startInput.__mh_dateRangePicker = this
- @_dom.endInput = endInput
- @_dom.endInput.__mh_dateRangePicker = this
-
- # Setup the calendars for the date range picker
- proxyOptions = Calendar.proxyOptions(options, startInput)
- @_calendars = [
- new Calendar(@_dom.picker, proxyOptions)
- new Calendar(@_dom.picker, proxyOptions)
- ]
-
- # Flag indicating which date (start or end) we're picking in the range
- @_picking = 'start'
-
- # Define read-only properties
- Object.defineProperty(this, 'calendars', {get: () => @_calendars})
- Object.defineProperty(this, 'endInput', {value: @_dom.endInput})
- Object.defineProperty(this, 'startInput', {value: @_dom.startInput})
- Object.defineProperty(this, 'picking', {get: () => return @_picking})
-
- # Set up event listeners for the date picker
- for input in [@startInput, @endInput]
- $.listen input,
- 'click': (ev) ->
- ev.target.focus()
-
- 'focus': (ev) =>
- # Flag the date that's being picked
- if ev.target is @startInput
- @_picking = 'start'
- else
- @_picking = 'end'
- @open()
-
- 'blur': () =>
- # Check if the active element is one of the picker's inputs
- # (e.g when switching between date inputs), if so then we
- # don't want to close the picker.
- activeInput = document.activeElement
- if @startInput is activeInput or @endInput is activeInput
- return
-
- @close('blur')
-
- 'change': (ev) =>
- # When the input changes attempt to parse its value as a
- # date and replace the value with a fixed format date.
-
- # Ignore the request if the caller is the date picker itself
- if ev.caller is this
- return
-
- # Parse the date
- date = Calendar.parseDate(ev.target.value, @parsers)
- if date
-
- # Build the date range
- dateRange = @calendars[0].dateRange
- if @picking is 'start'
- dateRange[0] = date
- else
- dateRange[1] = date
-
- @pick(dateRange, {'source': 'input'})
-
- # Set up event listeners for the calendar
- eventListeners = {}
-
- eventListeners[@calendars[0]._et('pick')] = (ev) =>
-
- # Build the date range
- dateRange = @calendars[0].dateRange
- if @picking is 'start'
- dateRange[0] = ev.date
- else
- dateRange[1] = ev.date
-
- @pick(dateRange, {'source': 'calendar'})
-
- eventListeners[@calendars[0]._et('view')] = (ev) =>
- # Make sure the adjacent calendar is one month on
- if @calendars.indexOf(ev.calendar) is 0
- @calendars[1].sync(@calendars[0], 1)
- else
- @calendars[0].sync(@calendars[1], -1)
-
- $.listen(@calendars[0].calendar, eventListeners)
- $.listen(@calendars[1].calendar, eventListeners)
-
- # Public methods
-
- close: (reason) ->
- super(@startInput, 'mh-date-range-picker', reason)
-
- open: () ->
- # Open the date range picker
-
- # Determine which input the picker is being open against
- input = @startInput
- if @picking == 'end'
- input = @endInput
-
- # Parse the date inputs and build a date range to select in the
- # calendars.
- startDate = Calendar.parseDate(@startInput.value, @parsers)
- endDate = Calendar.parseDate(@endInput.value, @parsers)
- dateRange = @calendars[0].dateRange
- if startDate
- dateRange[0] = startDate
- if endDate
- dateRange[1] = endDate
-
- # If the start date is after the end date then set the value of the
- # start input and focus on the end input.
- if dateRange[1] < dateRange[0]
- @pick([dateRange[1], dateRange[0]])
- @endInput.focus()
- return
-
- # Select the current date range
- for calendar in @calendars
- calendar.select(dateRange[0], dateRange[1])
-
- # If neither calendar contains the start or end date in the range then
- # set the first calendar to show the start date.
- startStr = "#{dateRange[0].getMonth()}.#{dateRange[0].getFullYear()}"
- endStr = "#{dateRange[1].getMonth()}.#{dateRange[1].getFullYear()}"
- viewStrs = [
- "#{@calendars[0].month}.#{@calendars[0].year}",
- "#{@calendars[1].month}.#{@calendars[1].year}"
- ]
- if viewStrs.indexOf(startStr) is -1 and viewStrs.indexOf(endStr) is -1
- viewDate = dateRange[0]
- @calendars[0].goto(viewDate.getMonth(), viewDate.getFullYear())
-
- # Track the position of the picker inline with the input
- @_track(if @pinToStart then @startInput else input)
-
- # Display the date picker visually
- closedClass = @_bem('mh-date-range-picker', '', 'closed')
- @_dom.picker.classList.remove(closedClass)
-
- # Flag the picker as open
- @_isOpen = true
-
- # Dispatch an open event
- $.dispatch(@startInput, @_et('open'))
-
- pick: (dateRange, source) ->
- # Pick a date
-
- # Set the date range for both calendar
- for calendar in @calendars
- calendar.select(dateRange[0], dateRange[1])
-
- # Dispatch a pick event against the input
- evData = {'dateRange': dateRange, 'source': source}
- if $.dispatch(@startInput, @_et('pick'), evData)
-
- # Set the date value
- @constructor.behaviours.input[@_behaviours.input](this, dateRange)
-
- # Dispatch a picked event
- $.dispatch(@startInput, @_et('picked'), evData)
-
- # Switch the focus to the next date input
- if @picking is 'start'
- @endInput.focus()
- else
- @startInput.focus()
-
- # Close the date picker if configured to
- if @closeOnPick
- @close()
-
- # Private methods
-
- _et: (eventName) ->
- # Generate an event type name
- return "mh-date-range-picker--#{eventName}"
-
- # Behaviours
-
- @behaviours:
-
- # The `input` behaviour is used to set the value of the input when a
- # date is selected.
- input:
- 'set-value': (dateRangePicker, dateRange) ->
- # Set the input values
- format = Calendar.formats[dateRangePicker.format]
- dateRangePicker.startInput.value = format(dateRange[0])
- $.dispatch(
- dateRangePicker.startInput,
- 'change',
- {caller: datePicker}
- )
- dateRangePicker.endInput.value = format(dateRange[1])
- $.dispatch(
- dateRangePicker.endInput,
- 'change',
- {caller: datePicker}
- )
-
-
-module.exports = {
-
- # The calendar is exported to allow new behaviours, date formats and parsers
- # to be defined.
- Calendar: Calendar,
-
- # UI component classes
- DatePicker: DatePicker,
- DateRangePicker: DateRangePicker
- }
\ No newline at end of file
diff --git a/coffee/src/styles/date-picker.scss b/coffee/src/styles/date-picker.scss
deleted file mode 100644
index f13d9c4..0000000
--- a/coffee/src/styles/date-picker.scss
+++ /dev/null
@@ -1,206 +0,0 @@
-$date-size: 280 / 7;
-$half-date-size: $date-size / 2;
-
-.mh-calendar {
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -webkit-user-select: none;
-
- box-sizing: border-box;
- float: left;
- font-family: sans-serif;
- padding: 10px;
- user-select: none;
- width: 300px;
-
- * {
- box-sizing: border-box;
- }
-
- // Nav
- &__nav {
- position: relative;
- }
-
- &__month {
- color: #666;
- font-size: 18px;
- text-align: center;
- }
-
- &__next {
- border-bottom: 8px solid transparent;
- border-left: 12px solid #334144;
- border-radius: 3px;
- border-top: 8px solid transparent;
- cursor: pointer;
- height: 0;
- position: absolute;
- right: 10px;
- top: 2px;
- width: 0;
- }
-
- &__previous {
- border-bottom: 8px solid transparent;
- border-radius: 3px;
- border-right: 12px solid #334144;
- border-top: 8px solid transparent;
- cursor: pointer;
- height: 0;
- left: 10px;
- position: absolute;
- top: 2px;
- width: 0;
- }
-
- // Weekdays
- &__weekdays {
- margin-top: 10px;
-
- &::after {
- clear: both;
- content: ' ';
- display: table;
- }
- }
-
- &__weekday {
- color: #999;
- float: left;
- font-size: 11px;
- font-weight: bold;
- text-align: center;
- width: #{$date-size}px;
- }
-
- // Dates
- &__dates {
- margin-top: 10px;
-
- &::after {
- clear: both;
- content: ' ';
- display: table;
- }
- }
-
- &__date {
- color: #666;
- float: left;
- font-size: 14px;
- height: #{$date-size}px;
- line-height: #{$date-size}px;
- position: relative;
- text-align: center;
- width: #{$date-size}px;
-
- &:hover {
- cursor: pointer;
-
- &::after {
- background: rgba(226, 106, 106, 0.1);
- border-radius: #{$half-date-size}px;
- content: '';
- display: block;
- height: #{$date-size}px;
- left: 0;
- position: absolute;
- top: 0;
- width: #{$date-size}px;
- z-index: -1;
- }
- }
-
- &--in-range {
- background: rgba(226, 106, 106, 0.1);
- }
-
- &--range-start {
- background: #e26a6a;
- border-bottom-left-radius: #{$half-date-size}px;
- border-top-left-radius: #{$half-date-size}px;
- color: #fff;
- font-weight: bold;
-
- &:hover {
- cursor: default;
-
- &::after {
- display: none;
- }
- }
- }
-
- &--range-end {
- background: #e26a6a;
- border-bottom-right-radius: #{$half-date-size}px;
- border-top-right-radius: #{$half-date-size}px;
- color: #fff;
- font-weight: bold;
-
- &:hover {
- cursor: default;
-
- &::after {
- display: none;
- }
- }
- }
-
- &--today {
- text-decoration: underline;
- }
-
- &--blocked {
- color: #999;
- font-style: italic;
- font-weight: normal;
-
- &:hover {
- cursor: default;
-
- &::after {
- display: none;
- }
- }
- }
-
- &--range-start.mh-calendar__date--blocked,
- &--range-end.mh-calendar__date--blocked {
- color: #fff;
- }
- }
-}
-
-.mh-date-picker,
-.mh-date-range-picker {
- background: #fff;
- border: 1px solid #d4dce0;
- border-radius: 3px;
- margin-top: 10px;
- position: absolute;
- width: 300px;
- z-index: 4;
-
- &--closed {
- display: none;
- }
-}
-
-.mh-date-range-picker {
- width: 600px;
-
- .mh-calendar:first-child {
- .mh-calendar__next {
- display: none;
- }
- }
-
- .mh-calendar:nth-child(2) {
- .mh-calendar__previous {
- display: none;
- }
- }
-}
\ No newline at end of file
diff --git a/coffee/test/calendar.coffee b/coffee/test/calendar.coffee
deleted file mode 100644
index acdbe9c..0000000
--- a/coffee/test/calendar.coffee
+++ /dev/null
@@ -1,555 +0,0 @@
-# Imports
-
-chai = require 'chai'
-jsdom = require 'mocha-jsdom'
-sinon = require 'sinon'
-sinonChai = require 'sinon-chai'
-
-$ = require 'manhattan-essentials'
-Calendar = require('../src/scripts/calendar').Calendar
-
-
-# Set up
-
-should = chai.should()
-chai.use(sinonChai)
-
-
-# Tests
-
-describe 'Calendar (class)', ->
-
- jsdom()
-
- calendar = null
-
- beforeEach ->
- # Initialize a calendar
- calendar = new Calendar(document.body)
- calendar.goto(0, 2000)
-
- afterEach ->
- calendar.destroy()
-
- describe 'constructor', ->
-
- it 'should generate a new `Calendar` instance', ->
-
- calendar.should.be.an.instanceof Calendar
-
- it 'should add the calendar element to the body', ->
-
- $.one('.mh-calendar', document.body).should.exist
-
- describe 'destroy', ->
-
- it 'should remove the calendar element from the body', ->
-
- calendar.destroy()
- should.not.exist($.one('.mh-calendar', document.body))
-
- describe 'goto', ->
-
- it 'should set the month and year for the calendar to those given', ->
- calendar.goto(5, 1979)
- calendar.month.should.equal 5
- calendar.year.should.equal 1979
-
- it 'should dispatch a view event against the calendar DOM element', ->
-
- listener = sinon.spy()
- calendar.calendar.addEventListener('mh-calendar--view', listener)
- calendar.goto(5, 1979)
- listener.should.have.been.calledOn calendar.calendar
-
- ev = listener.args[0][0]
- ev.calendar.should.equal calendar
- ev.month.should.equal 5
- ev.year.should.equal 1979
-
- describe 'next', ->
-
- it 'should advance the month and year the calendar displays by one
- month', ->
- calendar.next()
- calendar.month.should.equal 1
- calendar.year.should.equal 2000
-
- describe 'offset', ->
-
- it 'should move the month and year the calendar displays by the given
- number of months and years', ->
- calendar.offset(-7, -20)
- calendar.month.should.equal 5
- calendar.year.should.equal 1979
-
- describe 'previous', ->
-
- it 'should move the month and year the calendar displays back by one
- month', ->
- calendar.previous()
- calendar.month.should.equal 11
- calendar.year.should.equal 1999
-
- describe 'select', ->
-
- it 'should select the given date', ->
- date = new Date(1979, 5, 11)
- calendar.select(date)
- calendar.dateRange[0].getTime().should.equal date.getTime()
- calendar.dateRange[1].getTime().should.equal date.getTime()
-
- it 'should select the given date range', ->
- dateRange = [new Date(1979, 5, 11), new Date(1978, 6, 25)]
- calendar.select(dateRange[0], dateRange[1])
- calendar.dateRange[0].getTime().should.equal dateRange[0].getTime()
- calendar.dateRange[1].getTime().should.equal dateRange[1].getTime()
-
- describe 'sync', ->
-
- otherCalendar = null
-
- before ->
- otherCalendar = new Calendar(document.body)
- otherCalendar.goto(11, 2001)
-
- after ->
- otherCalendar.destroy()
-
- it "it should sync the calendar view with another calendar's view at the
- given offset", ->
-
- calendar.sync(otherCalendar, 1)
- calendar.month.should.equal 0
- calendar.year.should.equal 2002
-
- describe 'update', ->
-
- before ->
- calendar.test = 'excluding'
- calendar.dates = [
- new Date(2000, 1, 1),
- new Date(2000, 1, 2),
- new Date(2000, 1, 3)
- ]
-
- after ->
- calendar.test = 'any'
- calendar.dates = []
-
- it 'should update the view to display the given month and year', ->
- calendar.goto(5, 1979)
-
- dom = calendar._dom
- dom.month.textContent.should.equal 'June, 1979'
-
- # Check the first and last day of the month are displayed in the
- # correct slots.
- dom.dates.childNodes[4].textContent == '1'
- dom.dates.childNodes[(4 * 7) + 5].textContent == '1'
-
- it 'should flag dates in the current date range', ->
- startDate = new Date(2000, 0, 2)
- endDate = new Date(2000, 0, 11)
- calendar.goto(0, 2000)
- calendar.select(startDate, endDate)
-
- startTime = startDate.getTime()
- endTime = endDate.getTime()
- for dateElm in calendar._dom.dates.childNodes
- thisTime = dateElm.__mh_date.getTime()
-
- if thisTime is startTime
- dateElm.classList.contains(
- 'mh-calendar__date--range-start').should.be.true
-
- if thisTime is endTime
- dateElm.classList.contains(
- 'mh-calendar__date--range-end').should.be.true
-
- if thisTime > startTime and thisTime < endTime
- dateElm.classList.contains(
- 'mh-calendar__date--in-range').should.be.true
-
- it 'should flag dates outside of the month as blocked', ->
- calendar.goto(0, 2000)
-
- for dateElm in calendar._dom.dates.childNodes
- if dateElm.__mh_date.getMonth() isnt 0
- dateElm.classList.contains(
- 'mh-calendar__date--blocked').should.be.true
-
- it 'should flag the current date as today', ->
- today = new Date()
- calendar.goto(today.getMonth(), new Date().getFullYear())
-
- for dateElm in calendar._dom.dates.childNodes
- if dateElm.__mh_date.getTime() is today.getTime()
- dateElm.classList.contains(
- 'mh-calendar__date--today').should.be.true
-
- it "should flag dates that don't pass the test behaviour as blocked", ->
- calendar.goto(0, 2000)
- excludedTimes = (d.getTime() for d in calendar.dates)
-
- for dateElm in calendar._dom.dates.childNodes
- if excludedTimes.indexOf(dateElm.__mh_date.getTime()) > -1
- dateElm.classList.contains(
- 'mh-calendar__date--blocked').should.be.true
-
- describe '@parseDate', ->
-
- it 'should attempt to parse a date string using the list of named
- parsers', ->
-
- # Spy on the parsers we'll be calling
- human_en = sinon.spy(Calendar.parsers, 'human_en')
- dmy = sinon.spy(Calendar.parsers, 'dmy')
- iso = sinon.spy(Calendar.parsers, 'iso')
-
- date = Calendar.parseDate('1979-06-11', ['human_en', 'dmy', 'iso'])
-
- human_en.should.have.been.called
- dmy.should.have.been.called
- iso.should.have.been.called
-
- date.getTime().should.equal new Date(1979, 5, 11).getTime()
-
- describe '@proxyOptions', ->
-
- input = null
-
- before ->
-
- input = $.create('input', {
- 'data-mh-calendar--dates': '2000-01-02,Jan 3rd 2000,4.1.00',
- 'data-mh-calendar--min-date': '1990-01-01',
- 'data-mh-calendar--max-date': '2nd February 2010',
- 'data-mh-calendar--first-weekday': '0',
- 'data-mh-calendar--month-names': \
- 'Ja,Fe,Ma,Ap,Ma,Ju,Ju,Au,Se,Oc,No,De',
- 'data-mh-calendar--weekday-names': 'Su,Mo,Tu,We,Th,Fr,Sa'
- })
-
- it 'Return a set of config options for the calendar based on a set of
- user defined options and an input element', ->
-
- # Defaults (no options, no input)
- proxy = Calendar.proxyOptions(
- 'data-mh-calendar--',
- {},
- null
- )
- proxy.should.deep.equal Calendar.getDefaultConfig()
-
- # Options (no input)
- options = {
- dates: [new Date(2000, 2, 10), new Date(2000, 2, 11)],
- minDate: new Date(2000, 1, 10),
- maxDate: new Date(2000, 3, 10),
- firstWeekday: 2,
- monthNames: 'J,F,M,A,M,J,J,A,S,O,N,D'.split(','),
- weekdayNames: 'S,M,T,W,T,F,S'.split(','),
- parsers: ['human_en', 'dmy', 'iso']
- }
- proxy = Calendar.proxyOptions(
- 'data-mh-calendar--',
- options,
- null
- )
- proxy.should.deep.equal {
- dates: [new Date(2000, 2, 10), new Date(2000, 2, 11)],
- minDate: new Date(2000, 1, 10),
- maxDate: new Date(2000, 3, 10),
- firstWeekday: 2,
- monthNames: 'J,F,M,A,M,J,J,A,S,O,N,D'.split(','),
- weekdayNames: 'S,M,T,W,T,F,S'.split(',')
- }
-
- # Options and input
- proxy = Calendar.proxyOptions(
- 'data-mh-calendar--',
- options,
- input
- )
- proxy.should.deep.equal {
- dates: [
- new Date(2000, 0, 2),
- new Date(2000, 0, 3),
- new Date(2000, 0, 4)
- ],
- minDate: new Date(1990, 0, 1),
- maxDate: new Date(2010, 1, 2),
- firstWeekday: 0,
- monthNames: 'Ja,Fe,Ma,Ap,Ma,Ju,Ju,Au,Se,Oc,No,De'.split(','),
- weekdayNames: 'Su,Mo,Tu,We,Th,Fr,Sa'.split(',')
- }
-
-
-describe 'Calendar (options)', ->
-
- jsdom()
-
- describe 'dates', ->
-
- # `dates` isn't tested as an option as it is covered under tests for the
- # `test` behaviour.
-
- describe 'minDate', ->
-
- it 'should set all dates before the minimum date as blocked', ->
-
- minDate = new Date(10, 0, 2000)
- calendar = new Calendar(document.body, {minDate: minDate})
- calendar.goto(0, 2000)
-
- for dateElm in calendar._dom.dates.childNodes
- if dateElm.__mh_date.getTime() < minDate.getTime()
- dateElm.classList.contains(
- 'mh-calendar__date--blocked').should.be.true
-
- describe 'maxDate', ->
-
- it 'should set all dates after the maximum date as blocked', ->
-
- maxDate = new Date(20, 0, 2000)
- calendar = new Calendar(document.body, {maxDate: maxDate})
- calendar.goto(0, 2000)
-
- for dateElm in calendar._dom.dates.childNodes
- if dateElm.__mh_date.getTime() > maxDate.getTime()
- dateElm.classList.contains(
- 'mh-calendar__date--blocked').should.be.true
-
- describe 'firstWeekday', ->
-
- it 'should set first weekday displayed in the calendar view', ->
-
- maxDate = new Date(20, 0, 2000)
- calendar = new Calendar(document.body, {firstWeekday: 0})
- calendar.goto(0, 2000)
-
- # Check the order of the weekdays
- weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
- for weekdayElm, i in calendar._dom.weekdays
- weekdayElm.textContent.should.equal weekdays[i]
-
- # Check that every 7th date is a Sunday
- for weekdayElm, i in calendar._dom.weekdays
- if i % 7 is 0
- weekdayElm.__mh_date.getDay().should.equal 0
-
- describe 'monthNames', ->
-
- it 'should set the month names displayed in the calendar view', ->
-
- monthNames = 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'
- monthNames = monthNames.split(',')
- calendar = new Calendar(document.body, {monthNames: monthNames})
-
- monthElm = calendar._dom.month
- for name, i in monthNames
- calendar.goto(i, 2000)
- monthElm.textContent.should.equal "#{name}, 2000"
-
- describe 'weekdayNames', ->
-
- it 'should set the weekday names displayed in the calendar view', ->
-
- weekdayNames = 'Su,Mo,Tu,We,Th,Fr,Sa'.split(',')
- calendar = new Calendar(
- document.body,
- {
- firstWeekday: 0,
- weekdayNames: weekdayNames
- }
- )
-
- weekdaysElm = calendar._dom.weekdays
- for name, i in weekdayNames
- calendar.goto(i, 2000)
- weekdayElm = weekdaysElm.childNodes[i]
- weekdayElm.textContent.should.equal name
-
-
-describe 'Calendar (behaviours)', ->
-
- jsdom()
-
- calendar = null
-
- beforeEach ->
- # Initialize a calendar
- calendar = new Calendar(document.body)
- calendar.goto(0, 2000)
-
- describe 'test', ->
-
- describe 'any', ->
-
- it 'should return true for any date', ->
-
- behaviour = Calendar.behaviours.test.any
- date = new Date(2000, 0, 1)
- for i in [0..365]
- behaviour(calendar, [], date).should.be.true
- date.setDate(date.getDate() + 1)
-
-
- describe 'excluding', ->
-
- it 'should return true only for dates not in the `dates` config
- option', ->
-
- behaviour = Calendar.behaviours.test.excluding
- date = new Date(2000, 0, 1)
- dates = [
- new Date(2000, 1, 1),
- new Date(2000, 2, 2),
- new Date(2000, 3, 3)
- ]
- times = (d.getTime() for d in dates)
-
- for i in [0..365]
- if times.indexOf(date.getTime()) > -1
- behaviour(calendar, dates, date).should.be.false
- else
- behaviour(calendar, dates, date).should.be.true
- date.setDate(date.getDate() + 1)
-
- describe 'only', ->
-
- it 'should return true only for dates in the `dates` config
- option', ->
-
- behaviour = Calendar.behaviours.test.only
- date = new Date(2000, 0, 1)
- dates = [
- new Date(2000, 1, 1),
- new Date(2000, 2, 2),
- new Date(2000, 3, 3)
- ]
- times = (d.getTime() for d in dates)
-
- for i in [0..365]
- if times.indexOf(date.getTime()) > -1
- behaviour(calendar, dates, date).should.be.true
- else
- behaviour(calendar, dates, date).should.be.false
- date.setDate(date.getDate() + 1)
-
- describe 'weekdays', ->
-
- it 'should return true only for dates in that fall on the weekdays
- in the `dates` config option', ->
-
- behaviour = Calendar.behaviours.test.weekdays
- date = new Date(2000, 0, 1)
- weekdays = [0, 6]
-
- for i in [0..365]
- if weekdays.indexOf(date.getDay()) > -1
- behaviour(calendar, weekdays, date).should.be.true
- else
- behaviour(calendar, weekdays, date).should.be.false
- date.setDate(date.getDate() + 1)
-
-
-describe 'Calendar (formats)', ->
-
- describe 'dmy', ->
-
- it 'should format a date as `dd/mm/yyyy`', ->
-
- Calendar.formats.dmy(new Date(2000, 0, 2)).should.equal '02/01/2000'
-
- describe 'human_en', ->
-
- it 'should format a date as `{day} {full month name} {full year}`, e.g
- `22 January 2011`', ->
-
- s = Calendar.formats.human_en(new Date(2000, 0, 2))
- s.should.equal '2 January 2000'
-
- describe 'human_abbr_en', ->
-
- it 'should format a date as
- `{day} {abbreviated month name} {full year}`, e.g `22 Jan 2011`', ->
-
- s = Calendar.formats.human_abbr_en(new Date(2000, 0, 2))
- s.should.equal '2 Jan 2000'
-
- describe 'dmy', ->
-
- it 'should format a date as ISO 8601 (e.g `yyyy-mm-dd`)', ->
-
- s = Calendar.formats.iso(new Date(2000, 0, 2))
- s.should.equal '2000-01-02'
-
- describe 'mdy', ->
-
- it 'should format a date as `mm/dd/yyyy`', ->
-
- Calendar.formats.mdy(new Date(2000, 0, 2)).should.equal '01/02/2000'
-
-
-describe 'Calendar (parsers)', ->
-
- month = new Date().getMonth()
- time = new Date(2000, 0, 2).getTime()
- year = new Date().getFullYear()
-
- describe 'dmy', ->
-
- it 'should parse a date string using the format `d/m/y`', ->
- Calendar.parsers.dmy('2/1/00').getTime().should.equal time
- Calendar.parsers.dmy('2/1/2000').getTime().should.equal time
- Calendar.parsers.dmy('02/01/2000').getTime().should.equal time
-
- it 'should parse a date string using the format `d.m.y`', ->
- Calendar.parsers.dmy('2.01.00').getTime().should.equal time
-
- it 'should parse a date string using the format `d-m-y`', ->
- Calendar.parsers.dmy('2-1-00').getTime().should.equal time
-
- describe 'human_en', ->
-
- # A series of human readable dates formats that must be parsed
-
- it 'should parse `2nd`', ->
- date = Calendar.parsers.human_en('2nd')
- date.getTime().should.equal (new Date(year, month, 2)).getTime()
-
- it 'should parse `1 Aug`', ->
- date = Calendar.parsers.human_en('1 Aug')
- date.getTime().should.equal (new Date(year, 7, 1)).getTime()
-
- it 'should parse `15 Feb 17`', ->
- date = Calendar.parsers.human_en('15 Feb 17')
- date.getTime().should.equal (new Date(2017, 1, 15)).getTime()
-
- it 'should parse `January 22, 2011`', ->
- date = Calendar.parsers.human_en('January 22, 2011')
- date.getTime().should.equal (new Date(2011, 0, 22)).getTime()
-
- it 'should parse `Nov 22`', ->
- date = Calendar.parsers.human_en('Nov 22')
- date.getTime().should.equal (new Date(year, 10, 22)).getTime()
-
- describe 'iso', ->
-
- it 'should parse a date string using the format `yyyy-mm-dd`', ->
- Calendar.parsers.iso('2000-01-02').getTime().should.equal time
-
- describe 'mdy', ->
-
- it 'should parse a date string using the format `m/d/y`', ->
- Calendar.parsers.mdy('1/2/00').getTime().should.equal time
- Calendar.parsers.mdy('1/2/2000').getTime().should.equal time
- Calendar.parsers.mdy('01/02/2000').getTime().should.equal time
-
- it 'should parse a date string using the format `m.d.y`', ->
- Calendar.parsers.mdy('1.2.00').getTime().should.equal time
-
- it 'should parse a date string using the format `m-d-y`', ->
- Calendar.parsers.mdy('1-2-00').getTime().should.equal time
diff --git a/coffee/test/date-picker.coffee b/coffee/test/date-picker.coffee
deleted file mode 100644
index 8a0b8dd..0000000
--- a/coffee/test/date-picker.coffee
+++ /dev/null
@@ -1,311 +0,0 @@
-# Imports
-
-chai = require 'chai'
-jsdom = require 'mocha-jsdom'
-sinon = require 'sinon'
-sinonChai = require 'sinon-chai'
-
-$ = require 'manhattan-essentials'
-DatePicker = require('../src/scripts/date-picker').DatePicker
-
-
-# Set up
-
-should = chai.should()
-chai.use(sinonChai)
-
-
-# Tests
-
-describe 'DatePicker (class)', ->
-
- jsdom()
-
- form = null
- input = null
- datePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- input = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-picker': true
- }
- )
- input.getBoundingClientRect = ->
- return {
- bottom: 20,
- height: 10,
- left: 10,
- right: 110,
- top: 10,
- width: 100
- }
-
- document.body.appendChild(form)
- form.appendChild(input)
-
- # Initialize a date picker for the input field
- datePicker = new DatePicker(input)
-
- describe 'constructor', ->
-
- it 'should generate a new `DatePicker` instance', ->
-
- datePicker.should.be.an.instanceof DatePicker
-
- it 'should add the date picker element to the body', ->
-
- $.one('.mh-date-picker', document.body).should.exist
-
- describe 'close', ->
-
- beforeEach ->
- datePicker.open()
-
- it 'should flag the date picker as closed', ->
-
- datePicker.close()
- datePicker.isOpen.should.be.false
-
- it 'should add a closed CSS class to the date picker', ->
-
- datePicker.close()
- pickerElm = datePicker._dom.picker
- closed = 'mh-date-picker--closed'
- pickerElm.classList.contains(closed).should.be.true
-
- it 'should dispatch a close event against the input', ->
-
- listener = sinon.spy()
- input.addEventListener('mh-date-picker--close', listener)
- datePicker.close('test')
- listener.should.have.been.calledOn input
-
- ev = listener.args[0][0]
- ev.reason.should.equal 'test'
-
- describe 'open', ->
-
- beforeEach ->
- datePicker.close()
-
- it 'should flag the date picker as open', ->
-
- datePicker.open()
- datePicker.isOpen.should.be.true
-
- it 'should remove the closed CSS class from the date picker', ->
-
- datePicker.open()
- pickerElm = datePicker._dom.picker
- closed = 'mh-date-picker--closed'
- pickerElm.classList.contains(closed).should.be.false
-
- it 'should position the date picker in-line with the input', ->
-
- datePicker.open()
-
- pickerElm = datePicker._dom.picker
- pickerElm.style.left.should.equal '10px'
- pickerElm.style.top.should.equal '20px'
-
- it 'should dispatch an open event against the input', ->
-
- listener = sinon.spy()
- input.addEventListener('mh-date-picker--open', listener)
- datePicker.open()
- listener.should.have.been.calledOn input
-
- it 'should show a calendar view for the date value in the input', ->
-
- datePicker.open()
- datePicker.calendar.month.should.equal 0
- datePicker.calendar.year.should.equal 2000
-
- describe 'pick', ->
-
- date = new Date(2001, 2, 3)
-
- beforeEach ->
- input.value = '1 Jan 2000'
- datePicker.calendar.select(new Date(2000, 0, 1))
-
- it 'should select the date in the calendar', ->
-
- datePicker.pick(date)
- dateRange = datePicker.calendar.dateRange
- dateRange[0].getTime().should.deep.equal date.getTime()
- dateRange[1].getTime().should.deep.equal date.getTime()
-
- it 'should set the value of the input to the picked date', ->
-
- datePicker.pick(date)
- input.value.should.equal '3 March 2001'
-
- it 'should dispatch a pick and picked event against the input', ->
-
- pickListener = sinon.spy()
- pickedListener = sinon.spy()
- input.addEventListener('mh-date-picker--pick', pickListener)
- input.addEventListener('mh-date-picker--picked', pickedListener)
-
- datePicker.pick(date, 'test')
-
- pickEv = pickListener.args[0][0]
- pickedEv = pickedListener.args[0][0]
-
- pickListener.should.have.been.calledOn input
- pickEv.date.should.equal date
- pickEv.source.should.equal 'test'
-
- pickedListener.should.have.been.calledOn input
- pickedEv.date.should.equal date
- pickedEv.source.should.equal 'test'
-
-
-describe 'DatePicker (options)', ->
-
- jsdom()
-
- form = null
- input = null
- datePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- input = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-picker': true
- }
- )
- document.body.appendChild(form)
- form.appendChild(input)
-
- afterEach ->
- document.body.removeChild(datePicker._dom.picker)
-
- describe 'closeOnPick', ->
-
- describe 'when false', ->
-
- before ->
- datePicker = new DatePicker(input, {closeOnPick: false})
-
- it 'should keep the date picker open once a date has been
- picked', ->
-
- datePicker.open()
- datePicker.pick(new Date(2000, 0, 2))
- datePicker.isOpen.should.be.true
-
- describe 'when true', ->
-
- before ->
- datePicker = new DatePicker(input, {closeOnPick: true})
-
- it 'should close the date picker once a date has been picked', ->
-
- datePicker.open()
- datePicker.pick(new Date(2000, 0, 2))
- datePicker.isOpen.should.be.false
-
- describe 'format', ->
-
- describe 'when iso', ->
-
- before ->
- datePicker = new DatePicker(input, {format: 'iso'})
-
- it 'should set the input value as an ISO 8601 format date when a
- date is picked', ->
-
- datePicker.pick(new Date(2000, 0, 2))
- input.value.should.equal '2000-01-02'
-
- describe 'parsers', ->
-
- describe 'when ["mdy"]', ->
-
- before ->
- datePicker = new DatePicker(input, {
- format: 'mdy',
- parsers: ['mdy']
- })
-
- it 'should only parse dates in m/d/y format when the input value is
- changed', ->
-
- # Date should not be parsed and therefore the selected date and
- # input value should not have changed.
- input.value = '2000-01-02'
- $.dispatch(input, 'changed')
-
- input.value.should.equal '2000-01-02'
-
- # Date should be parsed and therefore the selected date and
- # input should have changed.
- input.value = '02/01/2000'
- $.dispatch(input, 'changed')
-
- input.value.should.equal '02/01/2000'
-
-
-describe 'DatePicker (behaviours)', ->
-
- jsdom()
-
- form = null
- hidden = null
- input = null
- datePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- hidden = $.create('input', {'class': 'foo-hidden'})
- input = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-picker': true,
- 'data-mh-date-picker--hidden': '.foo-hidden',
- 'data-mh-date-picker--hidden-format': 'iso'
- }
- )
- document.body.appendChild(form)
- form.appendChild(hidden)
- form.appendChild(input)
- datePicker = new DatePicker(input)
-
- describe 'input', ->
-
- date = new Date(2000, 0, 1)
-
- describe 'set-hidden', ->
-
- before ->
- hidden.value = ''
-
- it 'should set the value of an associated hidden input', ->
-
- behaviour = DatePicker.behaviours.input['set-hidden']
- behaviour(datePicker, date)
- hidden.value.should.equal '2000-01-01'
-
- describe 'set-value', ->
-
- before ->
- input.value = ''
-
- it 'should set the value of the input field', ->
-
- behaviour = DatePicker.behaviours.input['set-value']
- behaviour(datePicker, date)
- input.value.should.equal '1 January 2000'
\ No newline at end of file
diff --git a/coffee/test/date-range-picker.coffee b/coffee/test/date-range-picker.coffee
deleted file mode 100644
index 75ee6e8..0000000
--- a/coffee/test/date-range-picker.coffee
+++ /dev/null
@@ -1,437 +0,0 @@
-# Imports
-
-chai = require 'chai'
-jsdom = require 'mocha-jsdom'
-sinon = require 'sinon'
-sinonChai = require 'sinon-chai'
-
-$ = require 'manhattan-essentials'
-DateRangePicker = require('../src/scripts/date-picker').DateRangePicker
-
-
-# Set up
-
-should = chai.should()
-chai.use(sinonChai)
-
-
-# Tests
-
-describe 'DateRangePicker (class)', ->
-
- jsdom()
-
- form = null
- startInput = null
- endInput = null
- dateRangePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- startInput = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-range-picker': true
- }
- )
- startInput.getBoundingClientRect = ->
- return {
- bottom: 20,
- height: 10,
- left: 10,
- right: 110,
- top: 10,
- width: 100
- }
- endInput = $.create('input', {'value': '5 Jan 2000'})
- endInput.getBoundingClientRect = ->
- return {
- bottom: 20,
- height: 10,
- left: 50,
- right: 150,
- top: 10,
- width: 100
- }
- document.body.appendChild(form)
- form.appendChild(startInput)
- form.appendChild(endInput)
-
- # Initialize a date range picker for the input fields
- dateRangePicker = new DateRangePicker(startInput, endInput)
-
- describe 'constructor', ->
-
- it 'should generate a new `DateRangePicker` instance', ->
-
- dateRangePicker.should.be.an.instanceof DateRangePicker
-
- it 'should add the date range picker element to the body', ->
-
- $.one('.mh-date-range-picker', document.body).should.exist
-
- describe 'close', ->
-
- beforeEach ->
- dateRangePicker.open()
-
- it 'should flag the date range picker as closed', ->
-
- dateRangePicker.close()
- dateRangePicker.isOpen.should.be.false
-
- it 'should add a closed CSS class to the date range picker', ->
-
- dateRangePicker.close()
- pickerElm = dateRangePicker._dom.picker
- closed = 'mh-date-range-picker--closed'
- pickerElm.classList.contains(closed).should.be.true
-
- it 'should dispatch a close event against the start input', ->
-
- listener = sinon.spy()
- startInput.addEventListener('mh-date-range-picker--close', listener)
- dateRangePicker.close('test')
- listener.should.have.been.calledOn startInput
-
- ev = listener.args[0][0]
- ev.reason.should.equal 'test'
-
- describe 'open', ->
-
- beforeEach ->
- dateRangePicker.close()
-
- it 'should flag the date range picker as open', ->
-
- dateRangePicker.open()
- dateRangePicker.isOpen.should.be.true
-
- it 'should remove the closed CSS class from the date range picker', ->
-
- dateRangePicker.open()
- pickerElm = dateRangePicker._dom.picker
- closed = 'mh-date-range-picker--closed'
- pickerElm.classList.contains(closed).should.be.false
-
- it 'should dispatch an open event against the start input', ->
-
- listener = sinon.spy()
- startInput.addEventListener('mh-date-range-picker--open', listener)
- dateRangePicker.open()
- listener.should.have.been.calledOn startInput
-
- describe 'when the start date is greater than the end date', ->
-
- it 'should set the start input to the end input (and visa-versa) and
- focus the end input', ->
-
- startInput.value = '10 Jan 2000'
- startInput.focus()
-
- startInput.value.should.equal '5 January 2000'
- endInput.value.should.equal '10 January 2000'
- document.activeElement.should.equal endInput
-
- describe 'when the start input is focused', ->
-
- it 'should position the date range picker in-line with the start
- input', ->
-
- startInput.focus()
-
- pickerElm = dateRangePicker._dom.picker
- pickerElm.style.left.should.equal '10px'
- pickerElm.style.top.should.equal '20px'
-
- describe 'when the end input is focused', ->
-
- it 'should position the date range picker in-line with the end
- input', ->
-
- endInput.focus()
-
- pickerElm = dateRangePicker._dom.picker
- pickerElm.style.left.should.equal '50px'
- pickerElm.style.top.should.equal '20px'
-
- describe 'pick', ->
-
- dateRange = [new Date(2001, 1, 5), new Date(2001, 1, 10)]
-
- beforeEach ->
- startInput.value = '1 Jan 2000'
- endInput.value = '5 Jan 2000'
- for calendar in dateRangePicker.calendars
- calendar.select(new Date(2000, 0, 1), new Date(2000, 0, 5))
-
- it 'should select the date range in the calendar', ->
-
- dateRangePicker.pick(dateRange)
- for calendar in dateRangePicker.calendars
- dates = calendar.dateRange
- dates[0].getTime().should.deep.equal dateRange[0].getTime()
- dates[1].getTime().should.deep.equal dateRange[1].getTime()
-
- it 'should set the value of the start and end inputs to the picked
- date range', ->
-
- dateRangePicker.pick(dateRange)
- startInput.value.should.equal = '5 February 2001'
- endInput.value.should.equal '10 February 2001'
-
- it 'should dispatch a pick and picked event against the start input', ->
-
- pickListener = sinon.spy()
- pickedListener = sinon.spy()
- startInput.addEventListener(
- 'mh-date-range-picker--pick',
- pickListener
- )
- startInput.addEventListener(
- 'mh-date-range-picker--picked',
- pickedListener
- )
-
- dateRangePicker.pick(dateRange, 'test')
-
- pickEv = pickListener.args[0][0]
- pickedEv = pickedListener.args[0][0]
-
- pickListener.should.have.been.calledOn startInput
- pickEv.dateRange.should.equal dateRange
- pickEv.source.should.equal 'test'
-
- pickedListener.should.have.been.calledOn startInput
- pickedEv.dateRange.should.equal dateRange
- pickedEv.source.should.equal 'test'
-
- describe 'when the start input is focused', ->
-
- it 'should set the focus to the end input', ->
-
- startInput.focus()
- dateRangePicker.pick(dateRange)
- document.activeElement.should.equal endInput
-
- describe 'when the end input is focused', ->
-
- it 'should set the focus to the start input', ->
-
- endInput.focus()
- dateRangePicker.pick(dateRange)
- document.activeElement.should.equal startInput
-
-
-describe 'DateRangePicker (options)', ->
-
- jsdom()
-
- form = null
- input = null
- dateRangePicker = null
-
- form = null
- startInput = null
- endInput = null
- dateRangePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- startInput = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-range-picker': true
- }
- )
- startInput.getBoundingClientRect = ->
- return {
- bottom: 20,
- height: 10,
- left: 10,
- right: 110,
- top: 10,
- width: 100
- }
- endInput = $.create('input', {'value': '5 Jan 2000'})
- endInput.getBoundingClientRect = ->
- return {
- bottom: 20,
- height: 10,
- left: 50,
- right: 150,
- top: 10,
- width: 100
- }
- document.body.appendChild(form)
- form.appendChild(startInput)
- form.appendChild(endInput)
-
- afterEach ->
- document.body.removeChild(dateRangePicker._dom.picker)
-
- describe 'closeOnPick', ->
-
- describe 'when false', ->
-
- before ->
- dateRangePicker = new DateRangePicker(
- startInput,
- endInput,
- {closeOnPick: false}
- )
-
- it 'should keep the date picker open once a date has been
- picked', ->
-
- dateRangePicker.open()
- dateRangePicker.pick([
- new Date(2000, 0, 5),
- new Date(2000, 0, 10)
- ])
- dateRangePicker.isOpen.should.be.true
-
- describe 'when true', ->
-
- before ->
- dateRangePicker = new DateRangePicker(
- startInput,
- endInput,
- {closeOnPick: true}
- )
-
- it 'should close the date picker once a date has been picked', ->
-
- dateRangePicker.open()
- dateRangePicker.pick([
- new Date(2000, 0, 5),
- new Date(2000, 0, 10)
- ])
- dateRangePicker.isOpen.should.be.false
-
- describe 'format', ->
-
- describe 'when iso', ->
-
- before ->
- dateRangePicker = new DateRangePicker(
- startInput,
- endInput,
- {format: 'iso'}
- )
-
- it 'should set the input values as ISO 8601 format dates when a date
- range is picked', ->
-
- dateRangePicker.pick([
- new Date(2000, 0, 5),
- new Date(2000, 0, 10)
- ])
- startInput.value.should.equal '2000-01-05'
- endInput.value.should.equal '2000-01-10'
-
- describe 'parsers', ->
-
- describe 'when ["mdy"]', ->
-
- before ->
- dateRangePicker = new DateRangePicker(
- startInput,
- endInput,
- {
- format: 'mdy',
- parsers: ['mdy']
- }
- )
-
- it 'should only parse dates in m/d/y format when the input value is
- changed', ->
-
- # Date should not be parsed and therefore the selected date and
- # input value should not have changed.
- startInput.value = '2001-01-05'
- endInput.value = '2001-01-10'
- $.dispatch(startInput, 'changed')
- $.dispatch(endInput, 'changed')
-
- startInput.value.should.equal '2001-01-05'
- endInput.value.should.equal '2001-01-10'
-
- # Date should be parsed and therefore the selected date and
- # input should have changed.
- startInput.value = '05/01/2001'
- endInput.value = '10/01/2001'
- $.dispatch(startInput, 'changed')
- $.dispatch(endInput, 'changed')
-
- startInput.value.should.equal '05/01/2001'
- endInput.value.should.equal '10/01/2001'
-
- describe 'pinToStart', ->
-
- describe 'when true and the end input is focused', ->
-
- before ->
- dateRangePicker = new DateRangePicker(
- startInput,
- endInput,
- {'pinToStart': true}
- )
-
- it 'should position the date range picker in-line with the start
- input', ->
-
- endInput.focus()
-
- pickerElm = dateRangePicker._dom.picker
- pickerElm.style.left.should.equal '10px'
- pickerElm.style.top.should.equal '20px'
-
-
-describe 'DateRangePicker (behaviours)', ->
-
- jsdom()
-
- form = null
- startInput = null
- endInput = null
- dateRangePicker = null
-
- before ->
- # Build a form with an input field
- form = $.create('form')
- startInput = $.create(
- 'input',
- {
- 'value': '1 Jan 2000',
- 'data-mh-date-range-picker': true
- }
- )
- endInput = $.create('input', {'value': '5 Jan 2000'})
- document.body.appendChild(form)
- form.appendChild(startInput)
- form.appendChild(endInput)
-
- # Initialize a date range picker for the input fields
- dateRangePicker = new DateRangePicker(startInput, endInput)
-
- describe 'input', ->
-
- dateRange = [new Date(2001, 1, 5), new Date(2001, 1, 10)]
-
- describe 'set-value', ->
-
- before ->
- startInput.value = ''
- endInput.value = ''
-
- it 'should set the value of the start and end input fields', ->
-
- behaviour = DateRangePicker.behaviours.input['set-value']
- behaviour(dateRangePicker, dateRange)
- startInput.value.should.equal '5 February 2001'
- endInput.value.should.equal '10 February 2001'
\ No newline at end of file
diff --git a/coffee/webpack.config.js b/coffee/webpack.config.js
deleted file mode 100644
index e3b4563..0000000
--- a/coffee/webpack.config.js
+++ /dev/null
@@ -1,118 +0,0 @@
-// Imports
-const path = require('path')
-const webpack = require('webpack')
-
-// Plugin config
-const plugins = [
-
- new webpack.DefinePlugin({
- 'process.env': {
-
- // The `NODE_ENV` flag indicates which environment web pack is compiling
- // in/for (defaults to the local environment).
- 'NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'dev')
-
- }
- }),
-
- new webpack.optimize.DedupePlugin()
-];
-
-// Environment specific config
-switch (process.env.NODE_ENV) {
-
- case 'dist':
- var uglifyPlugin = new webpack.optimize.UglifyJsPlugin({
- beautify: false,
- comments: false,
- compress: {
- drop_console: true,
- warnings: false
- },
- mangle: {
- except: ['webpackJsonp'],
- screw_ie8 : true,
- keep_fnames: true
- }
- })
-
- plugins.push(uglifyPlugin);
- break;
-
- default:
- break;
-
-}
-
-// Project config
-module.exports = {
- plugins: plugins,
-
- entry: {
- 'index': [
- path.resolve(__dirname, 'src/styles', 'date-picker.scss'),
- path.resolve(__dirname, 'src/scripts', 'date-picker.coffee')
- ]
- },
-
- output: {
- library: 'ManhattanDatePicker',
- libraryTarget: 'umd',
- path: path.join(__dirname, 'dist'),
- filename: 'index.js'
- },
-
- module: {
- preLoaders: [
- // CoffeeScript (lint)
- {
- test: /\.coffee$/,
- exclude: /node_modules/,
- loader: 'coffeelint-loader'
- },
-
- // SASS (lint)
- {
- test: /\.scss$/,
- exclude: /node_modules/,
- loader: 'sasslint'
- }
- ],
-
- loaders: [
- // CoffeeScript (to JavaScript)
- {
- test: /\.coffee$/,
- loaders: ['coffee']
- },
-
- // SASS (to CSS)
- {
- test: /\.scss$/,
- loaders: [
- 'file?name=date-picker.css',
- 'extract',
- 'css',
- 'sass'
- ]
- }
- ]
- },
-
- stats: {
- // Prevent duplicate output of SASS lint reports
- children: false
- },
-
- // Loader config
- sasslint: {
- configFile: '.sass-lint.yml'
- },
-
- // Dev server
- devServer: {
- contentBase: path.resolve(__dirname, 'dist'),
- inline: true,
- port: 5999
- }
-};
\ No newline at end of file