vendor/assets/javascripts/kalendae.js in kalendae_assets-0.2.1 vs vendor/assets/javascripts/kalendae.js in kalendae_assets-0.4.1

- old
+ new

@@ -1,19 +1,28 @@ /******************************************************************** * Kalendae, a framework agnostic javascript date picker * - * Copyright(c) 2012 Jarvis Badgley (chipersoft@gmail.com) * + * Copyright(c) 2013 Jarvis Badgley (chipersoft@gmail.com) * * http://github.com/ChiperSoft/Kalendae * - * Version 0.2 * + * Version 0.4.1 * ********************************************************************/ (function (undefined) { -var today; +var today, moment; var Kalendae = function (targetElement, options) { + if (typeof document.addEventListener !== 'function' && !util.isIE8()) return; + //if the first argument isn't an element and isn't a string, assume that it is the options object - if (!(targetElement instanceof Element || typeof targetElement === 'string')) options = targetElement; + var is_element = false; + try { + is_element = targetElement instanceof Element; + } + catch (err) { + is_element = !!targetElement && is_element.nodeType === 1; + } + if (!(is_element || typeof(targetElement) === 'string')) options = targetElement; var self = this, classes = self.classes, opts = self.settings = util.merge(self.defaults, {attachTo:targetElement}, options || {}), $container = self.container = util.make('div', {'class':classes.container}), @@ -33,11 +42,11 @@ if (util.isIE8()) util.addClassName($container, 'ie8'); //generate the column headers (Su, Mo, Tu, etc) i = 7; while (i--) { - columnHeaders.push( startDay.format('ddd').substr(0,opts.columnHeaderLength) ); + columnHeaders.push( startDay.format(opts.columnHeaderFormat) ); startDay.add('days',1); } //setup publish/subscribe and apply any subscriptions passed in settings MinPubSub(self); @@ -60,15 +69,15 @@ vsd = moment(); } self.viewStartDate = vsd.date(1); var viewDelta = ({ - 'past' : opts.months-1, - 'today-past' : opts.months-1, - 'any' : opts.months>2?Math.floor(opts.months/2):0, - 'today-future' : 0, - 'future' : 0 + 'past' : opts.months-1, + 'today-past' : opts.months-1, + 'any' : opts.months>2?Math.floor(opts.months/2):0, + 'today-future' : 0, + 'future' : 0 })[this.settings.direction]; if (viewDelta && moment().month()==moment(self.viewStartDate).month()){ self.viewStartDate = moment(self.viewStartDate).subtract({M:viewDelta}).date(1); @@ -76,20 +85,20 @@ if (typeof opts.blackout === 'function') { self.blackout = opts.blackout; } else if (!!opts.blackout) { - var bdates = parseDates(opts.blackout, opts.parseSplitDelimiter); + var bdates = parseDates(opts.blackout, opts.parseSplitDelimiter, opts.format); self.blackout = function (input) { input = moment(input).yearDay(); - if (input < 1 || !self._sel || self._sel.length < 1) return false; + if (input < 1 || !self._sel) return false; var i = bdates.length; while (i--) if (bdates[i].yearDay() === input) return true; return false; - } + }; } else { - self.blackout = function () {return false;} + self.blackout = function () {return false;}; } self.direction = self.directions[opts.direction] ? self.directions[opts.direction] : self.directions['any']; @@ -106,23 +115,26 @@ else util.addClassName($cal, classes.monthMiddle); } //title bar $title = util.make('div', {'class':classes.title}, $cal); - util.make('a', {'class':classes.previousYear}, $title); //previous button - util.make('a', {'class':classes.previousMonth}, $title); //previous button - util.make('a', {'class':classes.nextYear}, $title); //next button - util.make('a', {'class':classes.nextMonth}, $title); //next button - $caption = util.make('span', {'class':classes.caption}, $title); //title caption + if(!opts.useYearNav){ + util.addClassName($title, classes.disableYearNav); + } + util.make('a', {'class':classes.previousYear}, $title); //previous button + util.make('a', {'class':classes.previousMonth}, $title); //previous button + util.make('a', {'class':classes.nextYear}, $title); //next button + util.make('a', {'class':classes.nextMonth}, $title); //next button + $caption = util.make('span', {'class':classes.caption}, $title); //title caption //column headers $header = util.make('div', {'class':classes.header}, $cal); i = 0; do { $span = util.make('span', {}, $header); $span.innerHTML = columnHeaders[i]; - } while (++i < 7) + } while (++i < 7); //individual day cells $days = util.make('div', {'class':classes.days}, $cal); i = 0; dayNodes = []; @@ -210,69 +222,73 @@ }; Kalendae.prototype = { defaults : { - attachTo: null, /* the element to attach the root container to. can be string or DOMElement */ - months: 1, /* total number of months to display side by side */ - weekStart: 0, /* day to use for the start of the week. 0 is Sunday */ - direction: 'any', /* past, today-past, any, today-future, future */ - directionScrolling: true, /* if a direction other than any is defined, prevent scrolling out of range */ - viewStartDate: null, /* date in the month to display. When multiple months, this is the left most */ - blackout: null, /* array of dates, or function to be passed a date */ - selected: null, /* dates already selected. can be string, date, or array of strings or dates. */ - mode: 'single', /* single, multiple, range */ - format: null, /* string used for parsing dates. */ - subscribe: null, /* object containing events to subscribe to */ + attachTo :null, /* the element to attach the root container to. can be string or DOMElement */ + months :1, /* total number of months to display side by side */ + weekStart :0, /* day to use for the start of the week. 0 is Sunday */ + direction :'any', /* past, today-past, any, today-future, future */ + directionScrolling :true, /* if a direction other than any is defined, prevent scrolling out of range */ + viewStartDate :null, /* date in the month to display. When multiple months, this is the left most */ + blackout :null, /* array of dates, or function to be passed a date */ + selected :null, /* dates already selected. can be string, date, or array of strings or dates. */ + mode :'single', /* single, multiple, range */ + dayOutOfMonthClickable:false, + format :null, /* string used for parsing dates. */ + subscribe :null, /* object containing events to subscribe to */ - columnHeaderLength: 2, /* number of characters to show in the column headers */ - titleFormat: 'MMMM, YYYY', /* format mask for month titles. See momentjs.com for rules */ - dayNumberFormat: 'D', /* format mask for individual days */ - dayAttributeFormat: 'YYYY-MM-DD', /* format mask for the data-date attribute set on every span */ - parseSplitDelimiter: /,\s*|\s+-\s+/, /* regex to use for splitting multiple dates from a passed string */ - rangeDelimiter: ' - ', /* string to use between dates when outputting in range mode */ - multipleDelimiter: ', ', /* string to use between dates when outputting in multiple mode */ + columnHeaderFormat :'dd', /* number of characters to show in the column headers */ + titleFormat :'MMMM, YYYY', /* format mask for month titles. See momentjs.com for rules */ + dayNumberFormat :'D', /* format mask for individual days */ + dayAttributeFormat :'YYYY-MM-DD', /* format mask for the data-date attribute set on every span */ + parseSplitDelimiter : /,\s*|\s+-\s+/, /* regex to use for splitting multiple dates from a passed string */ + rangeDelimiter :' - ', /* string to use between dates when outputting in range mode */ + multipleDelimiter :', ', /* string to use between dates when outputting in multiple mode */ + useYearNav :true, - dateClassMap: {} + dateClassMap :{} }, classes : { - container :'kalendae', - calendar :'k-calendar', - monthFirst :'k-first-month', - monthMiddle :'k-middle-month', - monthLast :'k-last-month', - title :'k-title', - previousMonth :'k-btn-previous-month', - nextMonth :'k-btn-next-month', - previousYear :'k-btn-previous-year', - nextYear :'k-btn-next-year', - caption :'k-caption', - header :'k-header', - days :'k-days', - dayOutOfMonth :'k-out-of-month', - dayActive :'k-active', - daySelected :'k-selected', - dayInRange :'k-range', - dayToday :'k-today', - monthSeparator :'k-separator', - disablePreviousMonth :'k-disable-previous-month-btn', - disableNextMonth :'k-disable-next-month-btn', - disablePreviousYear :'k-disable-previous-year-btn', - disableNextYear :'k-disable-next-year-btn' + container :'kalendae', + calendar :'k-calendar', + monthFirst :'k-first-month', + monthMiddle :'k-middle-month', + monthLast :'k-last-month', + title :'k-title', + previousMonth :'k-btn-previous-month', + nextMonth :'k-btn-next-month', + previousYear :'k-btn-previous-year', + nextYear :'k-btn-next-year', + caption :'k-caption', + header :'k-header', + days :'k-days', + dayOutOfMonth :'k-out-of-month', + dayInMonth :'k-in-month', + dayActive :'k-active', + daySelected :'k-selected', + dayInRange :'k-range', + dayToday :'k-today', + monthSeparator :'k-separator', + disablePreviousMonth :'k-disable-previous-month-btn', + disableNextMonth :'k-disable-next-month-btn', + disablePreviousYear :'k-disable-previous-year-btn', + disableNextYear :'k-disable-next-year-btn', + disableYearNav :'k-disable-year-nav' }, disablePreviousMonth: false, disableNextMonth: false, disablePreviousYear: false, disableNextYear: false, directions: { - 'past' :function (date) {return moment(date).yearDay() >= today.yearDay();}, - 'today-past' :function (date) {return moment(date).yearDay() > today.yearDay();}, - 'any' :function (date) {return false;}, - 'today-future' :function (date) {return moment(date).yearDay() < today.yearDay();}, - 'future' :function (date) {return moment(date).yearDay() <= today.yearDay();} + 'past' :function (date) {return moment(date).yearDay() >= today.yearDay();}, + 'today-past' :function (date) {return moment(date).yearDay() > today.yearDay();}, + 'any' :function (date) {return false;}, + 'today-future' :function (date) {return moment(date).yearDay() < today.yearDay();}, + 'future' :function (date) {return moment(date).yearDay() <= today.yearDay();} }, getSelectedAsDates : function () { var out = []; var i=0, c = this._sel.length; @@ -284,20 +300,20 @@ getSelectedAsText : function (format) { var out = []; var i=0, c = this._sel.length; for (;i<c;i++) { - out.push(this._sel[i].format(format || this.settings.format || 'YYYY-MM-DD')) + out.push(this._sel[i].format(format || this.settings.format || 'YYYY-MM-DD')); } return out; }, getSelectedRaw : function () { var out = []; var i=0, c = this._sel.length; for (;i<c;i++) { - out.push(moment(this._sel[i])) + out.push(moment(this._sel[i])); } return out; }, getSelected : function (format) { @@ -350,18 +366,28 @@ return false; }, setSelected : function (input, draw) { - this._sel = parseDates(input, this.settings.parseSplitDelimiter, this.settings.format); - this._sel.sort(function (a,b) {return a.yearDay() - b.yearDay();}); + var i, + new_dates = parseDates(input, this.settings.parseSplitDelimiter, this.settings.format), + old_dates = parseDates(this.getSelected(), this.settings.parseSplitDelimiter, this.settings.format); + i = old_dates.length; + while(i--) { this.removeSelected(old_dates[i], draw); } + + i = new_dates.length; + while(i--) { this.addSelected(new_dates[i], draw); } + if (draw !== false) this.draw(); }, addSelected : function (date, draw) { - date = moment(date).hours(12); + date = moment(date, this.settings.format).hours(12); + + if(this.settings.dayOutOfMonthClickable && this.settings.mode !== 'range'){ this.makeSelectedDateVisible(date); } + switch (this.settings.mode) { case 'multiple': if (!this.isSelected(date)) this._sel.push(date); else return false; break; @@ -378,22 +404,33 @@ default: this._sel = [date]; break; } this._sel.sort(function (a,b) {return a.yearDay() - b.yearDay();}); - this.publish('change', this); + this.publish('change', this, [date]); if (draw !== false) this.draw(); return true; }, + makeSelectedDateVisible: function (date) { + outOfViewMonth = moment(date).date('1').diff(this.viewStartDate,'months'); + + if(outOfViewMonth < 0){ + this.viewStartDate.subtract('months',1); + } + else if(outOfViewMonth > 0 && outOfViewMonth >= this.settings.months){ + this.viewStartDate.add('months',1); + } + }, + removeSelected : function (date, draw) { - date = moment(date).yearDay(); + date = moment(date, this.settings.format).hours(12); var i = this._sel.length; while (i--) { - if (this._sel[i].yearDay() === date) { + if (this._sel[i].yearDay() === date.yearDay()) { this._sel.splice(i,1); - this.publish('change', this); + this.publish('change', this, [date]); if (draw !== false) this.draw(); return true; } } return false; @@ -409,11 +446,12 @@ klass, i=0, c, j=0, k, s, dateString, - opts = this.settings; + opts = this.settings, + diff; c = this.calendars.length; do { day = moment(month).date(1); @@ -431,12 +469,14 @@ s = this.isSelected(day); if (s) klass.push(({'-1':classes.dayInRange,'1':classes.daySelected, 'true':classes.daySelected})[s]); if (day.month() != month.month()) klass.push(classes.dayOutOfMonth); - else if (!(this.blackout(day) || this.direction(day)) || s>0) klass.push(classes.dayActive); + else klass.push(classes.dayInMonth); + if (!(this.blackout(day) || this.direction(day) || (day.month() != month.month() && opts.dayOutOfMonthClickable === false)) || s>0) klass.push(classes.dayActive); + if (day.yearDay() === today.yearDay()) klass.push(classes.dayToday); dateString = day.format(this.settings.dayAttributeFormat); if (opts.dateClassMap[dateString]) klass.push(opts.dateClassMap[dateString]); @@ -449,23 +489,22 @@ } while (++j < 42); month.add('months',1); } while (++i < c); if (opts.directionScrolling) { - var diff = -(moment().diff(month, 'months')); if (opts.direction==='today-past' || opts.direction==='past') { - + diff = month.add({m:1}).diff(moment(), 'months', true); if (diff <= 0) { this.disableNextMonth = false; util.removeClassName(this.container, classes.disableNextMonth); } else { this.disableNextMonth = true; util.addClassName(this.container, classes.disableNextMonth); } } else if (opts.direction==='today-future' || opts.direction==='future') { - + diff = month.subtract({m:1}).diff(moment(), 'months', true); if (diff > opts.months) { this.disablePreviousMonth = false; util.removeClassName(this.container, classes.disablePreviousMonth); } else { this.disablePreviousMonth = true; @@ -474,20 +513,22 @@ } if (opts.direction==='today-past' || opts.direction==='past') { - if (month.add({Y:1}).diff(moment(), 'years') < 0) { + diff = month.add({m:12}).diff(moment(), 'months', true); + if (diff <= -11) { this.disableNextYear = false; util.removeClassName(this.container, classes.disableNextYear); } else { this.disableNextYear = true; util.addClassName(this.container, classes.disableNextYear); } } else if (opts.direction==='today-future' || opts.direction==='future') { - if (month.subtract({Y:1}).diff(moment(), 'years') > 0) { + diff = month.subtract({m:12}).diff(moment(), 'months', true); + if (diff > (11 + opts.months)) { this.disablePreviousYear = false; util.removeClassName(this.container, classes.disablePreviousYear); } else { this.disablePreviousYear = true; util.addClassName(this.container, classes.disablePreviousYear); @@ -495,38 +536,39 @@ } } } -} +}; var parseDates = function (input, delimiter, format) { var output = []; if (typeof input === 'string') { input = input.split(delimiter); } else if (!util.isArray(input)) { input = [input]; } - var c = input.length; - i = 0; + var c = input.length, + i = 0; + do { if (input[i]) output.push( moment(input[i], format).hours(12) ); } while (++i < c); return output; -} +}; window.Kalendae = Kalendae; var util = Kalendae.util = { isIE8: function() { - return !!( (/msie 8./i).test(navigator.appVersion) && !(/opera/i).test(navigator.userAgent) && window.ActiveXObject && XDomainRequest && !window.msPerformance ); + return !!( (/msie 8./i).test(navigator.appVersion) && !(/opera/i).test(navigator.userAgent) && window.ActiveXObject && XDomainRequest && !window.msPerformance ); }, // ELEMENT FUNCTIONS $: function (elem) { @@ -618,10 +660,18 @@ if (util.getStyle(elem, 'position') === 'fixed') return true; } while ((elem = elem.offsetParent)); return false; }, + scrollContainer: function (elem) { + do { + var overflow = util.getStyle(elem, 'overflow'); + if (overflow === 'auto' || overflow === 'scroll') return elem; + } while ((elem = elem.parentNode) && elem != window.document.body); + return null; + }, + getPosition: function (elem, isInner) { var x = elem.offsetLeft, y = elem.offsetTop, r = {}; @@ -671,58 +721,58 @@ //if property is an object or array, merge the contents instead of overwriting, if extend() was called as such if (deep && typeof a[k] === 'object' && typeof b[k] === 'object') _update(a[k], b[k]); else a[k] = b[k]; } return a; - } + }; for (; i < arguments.length; i++) { _c(d, arguments[i]); } return d; }, isArray: function (array) { - return !( - !array || - (!array.length || array.length === 0) || - typeof array !== 'object' || - !array.constructor || - array.nodeType || - array.item - ); + return Object.prototype.toString.call(array) == "[object Array]" } }; //auto-initializaiton code -Kalendae.util.domReady(function () { +if (typeof document.addEventListener === 'function') Kalendae.util.domReady(function () { var els = util.$$('.auto-kal'), i = els.length, - e; + e, + options, + optionsRaw; while (i--) { e = els[i]; + optionsRaw = e.getAttribute('data-kal'); + options = (optionsRaw == null || optionsRaw == "") ? {} : (new Function('return {' + optionsRaw + '};'))(); + if (e.tagName === 'INPUT') { //if element is an input, bind a popup calendar to the input. - new Kalendae.Input(e); + new Kalendae.Input(e, options); } else { //otherwise, insert a flat calendar into the element. - new Kalendae({attachTo:e}); + new Kalendae(util.merge(options, {attachTo:e})); } } }); - Kalendae.Input = function (targetElement, options) { + if (typeof document.addEventListener !== 'function' && !util.isIE8()) return; + var $input = this.input = util.$(targetElement), - overwriteInput; + overwriteInput, + $closeButton; if (!$input || $input.tagName !== 'INPUT') throw "First argument for Kalendae.Input must be an <input> element or a valid element id."; var self = this, - classes = self.classes + classes = self.classes, opts = self.settings = util.merge(self.defaults, options); //force attachment to the body opts.attachTo = window.document.body; @@ -733,11 +783,11 @@ //call our parent constructor Kalendae.call(self, opts); //create the close button if (opts.closeButton) { - var $closeButton = util.make('a', {'class':classes.closeButton}, self.container) + $closeButton = util.make('a', {'class':classes.closeButton}, self.container); util.addEvent($closeButton, 'click', function () { $input.blur(); }); } @@ -760,20 +810,30 @@ self.setSelected(this.value); self.show(); }); util.addEvent($input, 'blur', function () { - if (noclose) { + if (noclose && util.isIE8()) { noclose = false; $input.focus(); } else self.hide(); }); util.addEvent($input, 'keyup', function (event) { self.setSelected(this.value); }); + var $scrollContainer = util.scrollContainer($input); + + if( $scrollContainer ) { + + // Hide calendar when $scrollContainer is scrolled + util.addEvent($scrollContainer, 'scroll', function (event) { + $input.blur(); + }); + } + self.subscribe('change', function () { $input.value = self.getSelected(); }); }; @@ -793,40 +853,45 @@ show : function () { var $container = this.container, style = $container.style, $input = this.input, - pos = util.getPosition($input); + pos = util.getPosition($input), + $scrollContainer = util.scrollContainer($input), + scrollTop = $scrollContainer ? $scrollContainer.scrollTop : 0, + opts = this.settings; style.display = ''; switch (opts.side) { case 'left': - style.left = (pos.left - util.getWidth($container) + this.settings.offsetLeft) + 'px'; - style.top = (pos.top + this.settings.offsetTop) + 'px'; + style.left = (pos.left - util.getWidth($container) + opts.offsetLeft) + 'px'; + style.top = (pos.top + opts.offsetTop - scrollTop) + 'px'; break; case 'right': style.left = (pos.left + util.getWidth($input)) + 'px'; - style.top = (pos.top + this.settings.offsetTop) + 'px'; + style.top = (pos.top + opts.offsetTop - scrollTop) + 'px'; break; case 'top': - style.left = (pos.left + this.settings.offsetLeft) + 'px'; - style.top = (pos.top - util.getHeight($container) + this.settings.offsetTop) + 'px'; + style.left = (pos.left + opts.offsetLeft) + 'px'; + style.top = (pos.top - util.getHeight($container) + opts.offsetTop - scrollTop) + 'px'; break; case 'bottom': /* falls through */ default: - style.left = (pos.left + this.settings.offsetLeft) + 'px'; - style.top = (pos.top + util.getHeight($input) + this.settings.offsetTop) + 'px'; + style.left = (pos.left + opts.offsetLeft) + 'px'; + style.top = (pos.top + util.getHeight($input) + opts.offsetTop - scrollTop) + 'px'; break; } style.position = util.isFixed($input) ? 'fixed' : 'absolute'; + this.publish('show', this); }, hide : function () { this.container.style.display = 'none'; + this.publish('hide', this); } }); @@ -914,752 +979,38 @@ subs.splice(len, 1); } } }; -};// moment.js -// Altered slightly for use in Kalendae.js -// version : 1.5.0 -// author : Tim Wood -// license : MIT -// momentjs.com +}; +if (!Kalendae.moment) { + if (window.moment) { + Kalendae.moment = window.moment; + } else { + throw "Kalendae requires moment.js. You must use kalendae.standalone.js if moment is not available on the page."; + } +} -var moment = Kalendae.moment = (function (Date, undefined) { +moment = Kalendae.moment; - var moment, - round = Math.round, - languages = {}, - hasModule = (typeof module !== 'undefined'), - paramsToParse = 'months|monthsShort|monthsParse|weekdays|weekdaysShort|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'), - i, - jsonRegex = /^\/?Date\((\-?\d+)/i, - charactersToReplace = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?|ZZ?|LT|LL?L?L?)/g, - nonuppercaseLetters = /[^A-Z]/g, - timezoneRegex = /\([A-Za-z ]+\)|:[0-9]{2} [A-Z]{3} /g, - tokenCharacters = /(\\)?(MM?M?M?|dd?d?d|DD?D?D?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|ZZ?|T)/g, - inputCharacters = /(\\)?([0-9]+|([a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|([\+\-]\d\d:?\d\d))/gi, - isoRegex = /\d{4}.\d\d.\d\d(T(\d\d(.\d\d(.\d\d)?)?)?([\+\-]\d\d:?\d\d)?)?/, - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - isoTimes = [ - ['HH:mm:ss', /T\d\d:\d\d:\d\d/], - ['HH:mm', /T\d\d:\d\d/], - ['HH', /T\d\d/] - ], - timezoneParseRegex = /([\+\-]|\d\d)/gi, - VERSION = "1.5.0", - shortcuts = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'); - - // Moment prototype object - function Moment(date, isUTC) { - this._d = date; - this._isUTC = !!isUTC; - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength) { - var output = number + ''; - while (output.length < targetLength) { - output = '0' + output; - } - return output; - } - - // helper function for _.addTime and _.subtractTime - function dateAddRemove(date, _input, adding, val) { - var isString = (typeof _input === 'string'), - input = isString ? {} : _input, - ms, d, M, currentDate; - if (isString && val) { - input[_input] = +val; - } - ms = (input.ms || input.milliseconds || 0) + - (input.s || input.seconds || 0) * 1e3 + // 1000 - (input.m || input.minutes || 0) * 6e4 + // 1000 * 60 - (input.h || input.hours || 0) * 36e5; // 1000 * 60 * 60 - d = (input.d || input.days || 0) + - (input.w || input.weeks || 0) * 7; - M = (input.M || input.months || 0) + - (input.y || input.years || 0) * 12; - if (ms) { - date.setTime(+date + ms * adding); - } - if (d) { - date.setDate(date.getDate() + d * adding); - } - if (M) { - currentDate = date.getDate(); - date.setDate(1); - date.setMonth(date.getMonth() + M * adding); - date.setDate(Math.min(new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(), currentDate)); - } - return date; - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromArray(input) { - return new Date(input[0], input[1] || 0, input[2] || 1, input[3] || 0, input[4] || 0, input[5] || 0, input[6] || 0); - } - - // format date using native date object - function formatMoment(m, inputString) { - var currentMonth = m.month(), - currentDate = m.date(), - currentYear = m.year(), - currentDay = m.day(), - currentHours = m.hours(), - currentMinutes = m.minutes(), - currentSeconds = m.seconds(), - currentZone = -m.zone(), - ordinal = moment.ordinal, - meridiem = moment.meridiem; - // check if the character is a format - // return formatted string or non string. - // - // uses switch/case instead of an object of named functions (like http://phpjs.org/functions/date:380) - // for minification and performance - // see http://jsperf.com/object-of-functions-vs-switch for performance comparison - function replaceFunction(input) { - // create a couple variables to be used later inside one of the cases. - var a, b; - switch (input) { - // MONTH - case 'M' : - return currentMonth + 1; - case 'Mo' : - return (currentMonth + 1) + ordinal(currentMonth + 1); - case 'MM' : - return leftZeroFill(currentMonth + 1, 2); - case 'MMM' : - return moment.monthsShort[currentMonth]; - case 'MMMM' : - return moment.months[currentMonth]; - // DAY OF MONTH - case 'D' : - return currentDate; - case 'Do' : - return currentDate + ordinal(currentDate); - case 'DD' : - return leftZeroFill(currentDate, 2); - // DAY OF YEAR - case 'DDD' : - a = new Date(currentYear, currentMonth, currentDate); - b = new Date(currentYear, 0, 1); - return ~~ (((a - b) / 864e5) + 1.5); - case 'DDDo' : - a = replaceFunction('DDD'); - return a + ordinal(a); - case 'DDDD' : - return leftZeroFill(replaceFunction('DDD'), 3); - // WEEKDAY - case 'd' : - return currentDay; - case 'do' : - return currentDay + ordinal(currentDay); - case 'ddd' : - return moment.weekdaysShort[currentDay]; - case 'dddd' : - return moment.weekdays[currentDay]; - // WEEK OF YEAR - case 'w' : - a = new Date(currentYear, currentMonth, currentDate - currentDay + 5); - b = new Date(a.getFullYear(), 0, 4); - return ~~ ((a - b) / 864e5 / 7 + 1.5); - case 'wo' : - a = replaceFunction('w'); - return a + ordinal(a); - case 'ww' : - return leftZeroFill(replaceFunction('w'), 2); - // YEAR - case 'YY' : - return leftZeroFill(currentYear % 100, 2); - case 'YYYY' : - return currentYear; - // AM / PM - case 'a' : - return currentHours > 11 ? meridiem.pm : meridiem.am; - case 'A' : - return currentHours > 11 ? meridiem.PM : meridiem.AM; - // 24 HOUR - case 'H' : - return currentHours; - case 'HH' : - return leftZeroFill(currentHours, 2); - // 12 HOUR - case 'h' : - return currentHours % 12 || 12; - case 'hh' : - return leftZeroFill(currentHours % 12 || 12, 2); - // MINUTE - case 'm' : - return currentMinutes; - case 'mm' : - return leftZeroFill(currentMinutes, 2); - // SECOND - case 's' : - return currentSeconds; - case 'ss' : - return leftZeroFill(currentSeconds, 2); - // TIMEZONE - case 'zz' : - // depreciating 'zz' fall through to 'z' - case 'z' : - return (m._d.toString().match(timezoneRegex) || [''])[0].replace(nonuppercaseLetters, ''); - case 'Z' : - return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(Math.abs(currentZone) / 60), 2) + ':' + leftZeroFill(~~(Math.abs(currentZone) % 60), 2); - case 'ZZ' : - return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(10 * Math.abs(currentZone) / 6), 4); - // LONG DATES - case 'L' : - case 'LL' : - case 'LLL' : - case 'LLLL' : - case 'LT' : - return formatMoment(m, moment.longDateFormat[input]); - // DEFAULT - default : - return input.replace(/(^\[)|(\\)|\]$/g, ""); - } - } - return inputString.replace(charactersToReplace, replaceFunction); - } - - // date from string and format string - function makeDateFromStringAndFormat(string, format) { - var inArray = [0, 0, 1, 0, 0, 0, 0], - timezoneHours = 0, - timezoneMinutes = 0, - isUsingUTC = false, - inputParts = string.match(inputCharacters), - formatParts = format.match(tokenCharacters), - len = Math.min(inputParts.length, formatParts.length), - i, - isPm; - - // function to convert string input to date - function addTime(format, input) { - var a; - switch (format) { - // MONTH - case 'M' : - // fall through to MM - case 'MM' : - inArray[1] = ~~input - 1; - break; - case 'MMM' : - // fall through to MMMM - case 'MMMM' : - for (a = 0; a < 12; a++) { - if (moment.monthsParse[a].test(input)) { - inArray[1] = a; - break; - } - } - break; - // DAY OF MONTH - case 'D' : - // fall through to DDDD - case 'DD' : - // fall through to DDDD - case 'DDD' : - // fall through to DDDD - case 'DDDD' : - inArray[2] = ~~input; - break; - // YEAR - case 'YY' : - input = ~~input; - inArray[0] = input + (input > 70 ? 1900 : 2000); - break; - case 'YYYY' : - inArray[0] = ~~Math.abs(input); - break; - // AM / PM - case 'a' : - // fall through to A - case 'A' : - isPm = (input.toLowerCase() === 'pm'); - break; - // 24 HOUR - case 'H' : - // fall through to hh - case 'HH' : - // fall through to hh - case 'h' : - // fall through to hh - case 'hh' : - inArray[3] = ~~input; - break; - // MINUTE - case 'm' : - // fall through to mm - case 'mm' : - inArray[4] = ~~input; - break; - // SECOND - case 's' : - // fall through to ss - case 'ss' : - inArray[5] = ~~input; - break; - // TIMEZONE - case 'Z' : - // fall through to ZZ - case 'ZZ' : - isUsingUTC = true; - a = (input || '').match(timezoneParseRegex); - if (a && a[1]) { - timezoneHours = ~~a[1]; - } - if (a && a[2]) { - timezoneMinutes = ~~a[2]; - } - // reverse offsets - if (a && a[0] === '+') { - timezoneHours = -timezoneHours; - timezoneMinutes = -timezoneMinutes; - } - break; - } - } - for (i = 0; i < len; i++) { - addTime(formatParts[i], inputParts[i]); - } - // handle am pm - if (isPm && inArray[3] < 12) { - inArray[3] += 12; - } - // if is 12 am, change hours to 0 - if (isPm === false && inArray[3] === 12) { - inArray[3] = 0; - } - // handle timezone - inArray[3] += timezoneHours; - inArray[4] += timezoneMinutes; - // return - return isUsingUTC ? new Date(Date.UTC.apply({}, inArray)) : dateFromArray(inArray); - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if (~~array1[i] !== ~~array2[i]) { - diffs++; - } - } - return diffs + lengthDiff; - } - - // date from string and array of format strings - function makeDateFromStringAndArray(string, formats) { - var output, - inputParts = string.match(inputCharacters), - scores = [], - scoreToBeat = 99, - i, - curDate, - curScore; - for (i = 0; i < formats.length; i++) { - curDate = makeDateFromStringAndFormat(string, formats[i]); - curScore = compareArrays(inputParts, formatMoment(new Moment(curDate), formats[i]).match(inputCharacters)); - if (curScore < scoreToBeat) { - scoreToBeat = curScore; - output = curDate; - } - } - return output; - } - - // date from iso format - function makeDateFromString(string) { - var format = 'YYYY-MM-DDT', - i; - if (isoRegex.exec(string)) { - for (i = 0; i < 3; i++) { - if (isoTimes[i][1].exec(string)) { - format += isoTimes[i][0]; - break; - } - } - return makeDateFromStringAndFormat(string, format + 'Z'); - } - return new Date(string); - } - - // helper function for _date.from() and _date.fromNow() - function substituteTimeAgo(string, number, withoutSuffix) { - var rt = moment.relativeTime[string]; - return (typeof rt === 'function') ? - rt(number || 1, !!withoutSuffix, string) : - rt.replace(/%d/i, number || 1); - } - - function relativeTime(milliseconds, withoutSuffix) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - return substituteTimeAgo.apply({}, args); - } - - moment = function (input, format) { - if (input === null || input === '') { - return null; - } - var date, - matched; - // parse Moment object - if (input && input._d instanceof Date) { - date = new Date(+input._d); - // parse string and format - } else if (format) { - if (isArray(format)) { - date = makeDateFromStringAndArray(input, format); - } else { - date = makeDateFromStringAndFormat(input, format); - } - // evaluate it as a JSON-encoded date - } else { - matched = jsonRegex.exec(input); - date = input === undefined ? new Date() : - matched ? new Date(+matched[1]) : - input instanceof Date ? input : - isArray(input) ? dateFromArray(input) : - typeof input === 'string' ? makeDateFromString(input) : - new Date(input); - } - return new Moment(date); - }; - - // creating with utc - moment.utc = function (input, format) { - if (isArray(input)) { - return new Moment(new Date(Date.UTC.apply({}, input)), true); - } - return (format && input) ? moment(input + ' 0', format + ' Z').utc() : moment(input).utc(); - }; - - // humanizeDuration - moment.humanizeDuration = function (num, type, withSuffix) { - var difference = +num, - rel = moment.relativeTime, - output; - switch (type) { - case "seconds" : - difference *= 1000; // 1000 - break; - case "minutes" : - difference *= 60000; // 60 * 1000 - break; - case "hours" : - difference *= 3600000; // 60 * 60 * 1000 - break; - case "days" : - difference *= 86400000; // 24 * 60 * 60 * 1000 - break; - case "weeks" : - difference *= 604800000; // 7 * 24 * 60 * 60 * 1000 - break; - case "months" : - difference *= 2592000000; // 30 * 24 * 60 * 60 * 1000 - break; - case "years" : - difference *= 31536000000; // 365 * 24 * 60 * 60 * 1000 - break; - default : - withSuffix = !!type; - break; - } - output = relativeTime(difference, !withSuffix); - return withSuffix ? (difference <= 0 ? rel.past : rel.future).replace(/%s/i, output) : output; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // language switching and caching - moment.lang = function (key, values) { - var i, - param, - req, - parse = []; - if (values) { - for (i = 0; i < 12; i++) { - parse[i] = new RegExp('^' + values.months[i] + '|^' + values.monthsShort[i].replace('.', ''), 'i'); - } - values.monthsParse = values.monthsParse || parse; - languages[key] = values; - } - if (languages[key]) { - for (i = 0; i < paramsToParse.length; i++) { - param = paramsToParse[i]; - moment[param] = languages[key][param] || moment[param]; - } - } else { - if (hasModule) { - req = require('./lang/' + key); - moment.lang(key, req); - } - } - }; - - // set default language - moment.lang('en', { - months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), - monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), - weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), - weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), - longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" - }, - meridiem : { - AM : 'AM', - am : 'am', - PM : 'PM', - pm : 'pm' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" - }, - ordinal : function (number) { - var b = number % 10; - return (~~ (number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - } - }); - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment; - }; - - // shortcut for prototype - moment.fn = Moment.prototype = { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d; - }, - - 'native' : function () { - return this._d; - }, - - toString : function () { - return this._d.toString(); - }, - - toDate : function () { - return this._d; - }, - - utc : function () { - this._isUTC = true; - return this; - }, - - local : function () { - this._isUTC = false; - return this; - }, - - format : function (inputString) { - return formatMoment(this, inputString ? inputString : moment.defaultFormat); - }, - - add : function (input, val) { - this._d = dateAddRemove(this._d, input, 1, val); - return this; - }, - - subtract : function (input, val) { - this._d = dateAddRemove(this._d, input, -1, val); - return this; - }, - - diff : function (input, val, asFloat) { - var inputMoment = moment(input), - zoneDiff = (this.zone() - inputMoment.zone()) * 6e4, - diff = this._d - inputMoment._d - zoneDiff, - year = this.year() - inputMoment.year(), - month = this.month() - inputMoment.month(), - date = this.date() - inputMoment.date(), - output; - if (val === 'months') { - output = year * 12 + month + date / 30; - } else if (val === 'years') { - output = year + month / 12; - } else { - output = val === 'seconds' ? diff / 1e3 : // 1000 - val === 'minutes' ? diff / 6e4 : // 1000 * 60 - val === 'hours' ? diff / 36e5 : // 1000 * 60 * 60 - val === 'days' ? diff / 864e5 : // 1000 * 60 * 60 * 24 - val === 'weeks' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7 - diff; - } - return asFloat ? output : round(output); - }, - - from : function (time, withoutSuffix) { - return moment.humanizeDuration(this.diff(time), !withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function () { - var diff = this.diff(moment().sod(), 'days', true), - calendar = moment.calendar, - allElse = calendar.sameElse, - format = diff < -6 ? allElse : - diff < -1 ? calendar.lastWeek : - diff < 0 ? calendar.lastDay : - diff < 1 ? calendar.sameDay : - diff < 2 ? calendar.nextDay : - diff < 7 ? calendar.nextWeek : allElse; - return this.format(typeof format === 'function' ? format.apply(this) : format); - }, - - isLeapYear : function () { - var year = this.year(); - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - }, - - isDST : function () { - return (this.zone() < moment([this.year()]).zone() || - this.zone() < moment([this.year(), 5]).zone()); - }, - - day : function (input) { - var day = this._d.getDay(); - return (typeof input === 'undefined') ? day : - this.add({ d : input - day }); - }, - - sod: function () { - return this.clone() - .hours(0) - .minutes(0) - .seconds(0) - .milliseconds(0); - }, - - eod: function () { - // end of day = start of day plus 1 day, minus 1 millisecond - return this.sod().add({ - d : 1, - ms : -1 - }); - }, - - zone : function () { - return this._isUTC ? 0 : this._d.getTimezoneOffset(); - }, - - daysInMonth : function () { - return this.clone().month(this.month() + 1).date(0).date(); - } - }; - - // helper for adding shortcuts - function makeShortcut(name, key) { - moment.fn[name] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (typeof input !== 'undefined') { - this._d['set' + utc + key](input); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } - - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < shortcuts.length; i ++) { - makeShortcut(shortcuts[i].toLowerCase(), shortcuts[i]); - } - - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeShortcut('year', 'FullYear'); - - return moment; -})(Date); - //function to reset the date object to 00:00 GMT moment.fn.stripTime = function () { this._d = new Date(Math.floor(this._d.valueOf() / 86400000) * 86400000); return this; -} +}; //function to get the total number of days since the epoch. moment.fn.yearDay = function (input) { var yearday = Math.floor(this._d / 86400000); return (typeof input === 'undefined') ? yearday : this.add({ d : input - yearday }); -} +}; -today = moment().stripTime(); +today = Kalendae.moment().stripTime(); -if (typeof jQuery !== 'undefined') { +if (typeof jQuery !== 'undefined' && (typeof document.addEventListener === 'function' || util.isIE8())) { jQuery.fn.kalendae = function (options) { this.each(function (i, e) { if (e.tagName === 'INPUT') { //if element is an input, bind a popup calendar to the input. $(e).data('kalendae', new Kalendae.Input(e, options)); @@ -1667,10 +1018,10 @@ //otherwise, insert a flat calendar into the element. $(e).data('kalendae', new Kalendae($.extend({}, {attachTo:e}, options))); } }); return this; - } + }; } })();