123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 |
- /*!
- * Pikaday
- * Copyright © 2012 David Bushell | BSD & MIT license | http://dbushell.com/
- */
- (function (window, document, undefined) {
- 'use strict';
- /**
- * feature detection and helper functions
- */
- var hasMoment = typeof window.moment === 'function',
- hasEventListeners = !!window.addEventListener,
- sto = window.setTimeout,
- addEvent = function (el, e, callback, capture) {
- if (hasEventListeners) {
- el.addEventListener(e, callback, !!capture);
- } else {
- el.attachEvent('on' + e, callback);
- }
- },
- removeEvent = function (el, e, callback, capture) {
- if (hasEventListeners) {
- el.removeEventListener(e, callback, !!capture);
- } else {
- el.detachEvent('on' + e, callback);
- }
- },
- trim = function (str) {
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
- },
- hasClass = function (el, cn) {
- return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
- },
- addClass = function (el, cn) {
- if (!hasClass(el, cn)) {
- el.className = (el.className === '') ? cn : el.className + ' ' + cn;
- }
- },
- removeClass = function (el, cn) {
- el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
- },
- isArray = function (obj) {
- return (/Array/).test(Object.prototype.toString.call(obj));
- },
- isDate = function (obj) {
- return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
- },
- isLeapYear = function (year) {
- // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
- return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
- },
- getDaysInMonth = function (year, month) {
- return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
- },
- compareDates = function (a, b) {
- // weak date comparison (use date.setHours(0,0,0,0) to ensure correct result)
- return a.getTime() === b.getTime();
- },
- extend = function (to, from, overwrite) {
- var prop, hasProp;
- for (prop in from) {
- hasProp = to[prop] !== undefined;
- if (hasProp && typeof from[prop] === 'object' && from[prop].nodeName === undefined) {
- if (isDate(from[prop])) {
- if (overwrite) {
- to[prop] = new Date(from[prop].getTime());
- }
- }
- else if (isArray(from[prop])) {
- if (overwrite) {
- to[prop] = from[prop].slice(0);
- }
- } else {
- to[prop] = extend({}, from[prop], overwrite);
- }
- } else if (overwrite || !hasProp) {
- to[prop] = from[prop];
- }
- }
- return to;
- },
- /**
- * defaults and localisation
- */
- defaults = {
- // bind the picker to a form field
- field: null,
- // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
- bound: undefined,
- // the default output format for `.toString()` and `field` value
- format: 'YYYY-MM-DD',
- // the initial date to view when first opened
- defaultDate: null,
- // make the `defaultDate` the initial selected value
- setDefaultDate: false,
- // first day of week (0: Sunday, 1: Monday etc)
- firstDay: 0,
- // the minimum/earliest date that can be selected
- minDate: null,
- // the maximum/latest date that can be selected
- maxDate: null,
- // number of years either side, or array of upper/lower range
- yearRange: 10,
- // used internally (don't config outside)
- minYear: 1990,
- maxYear: 2099,
- minMonth: undefined,
- maxMonth: undefined,
- isRTL: false,
- // how many months are visible (not implemented yet)
- numberOfMonths: 1,
- // internationalization
- /* i18n: {
- months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
- //monthsShort : ['Jan_Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
- weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
- weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
- }, */
- i18n: {
- months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
- monthsShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
- weekdays: ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
- weekdaysShort: ['日', '一', '二', '三', '四', '五', '六']
- },
- // callback function
- onSelect: null,
- onOpen: null,
- onClose: null
- },
- /**
- * templating functions to abstract HTML rendering
- */
- renderDayName = function (opts, day, abbr) {
- day += opts.firstDay;
- while (day >= 7) {
- day -= 7;
- }
- return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
- },
- renderDay = function (i, isSelected, isToday, isDisabled, isEmpty) {
- if (isEmpty) {
- return '<td class="is-empty"></td>';
- }
- var arr = [];
- if (isDisabled) {
- arr.push('is-disabled');
- }
- if (isToday) {
- arr.push('is-today');
- }
- if (isSelected) {
- arr.push('is-selected');
- }
- return '<td data-day="' + i + '" class="' + arr.join(' ') + '"><a class="pika-button" href="javascript:void(0);">' + i + '</a>' + '</td>';
- },
- renderRow = function (days, isRTL) {
- return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>';
- },
- renderBody = function (rows) {
- return '<tbody>' + rows.join('') + '</tbody>';
- },
- renderHead = function (opts) {
- var i, arr = [];
- for (i = 0; i < 7; i++) {
- arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
- }
- return '<thead>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</thead>';
- },
- renderTitle = function (instance) {
- var i, j, arr,
- opts = instance._o,
- month = instance._m,
- year = instance._y,
- isMinYear = year === opts.minYear,
- isMaxYear = year === opts.maxYear,
- html = '<div class="pika-title">',
- prev = true,
- next = true,
- months = opts.i18n.monthsShort ? opts.i18n.monthsShort : opts.i18n.months;
- if (isMinYear && (month === 0 || opts.minMonth >= month)) {
- prev = false;
- }
- html += '<a class="pika-prev' + (prev ? '' : ' is-disabled') + '" href="javascript:void(0);"><</a>';
- if (isArray(opts.yearRange)) {
- i = opts.yearRange[0];
- j = opts.yearRange[1] + 1;
- } else {
- i = year - opts.yearRange;
- j = 1 + year + opts.yearRange;
- }
- for (arr = []; i < j && i <= opts.maxYear; i++) {
- if (i >= opts.minYear) {
- arr.push('<option value="' + i + '"' + (i === year ? ' selected' : '') + '>' + (i) + '</option>');
- }
- }
- html += '<div class="pika-label pika-label-year">' + year + '年 <select class="pika-select pika-select-year">' + arr.join('') + '</select></div>';
- for (arr = [], i = 0; i < 12; i++) {
- arr.push('<option value="' + i + '"' +
- (i === month ? ' selected' : '') +
- ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled' : '') + '>' +
- months[i] + '</option>');
- }
- html += '<div class="pika-label pika-label-month">' + months[month] + '月<select class="pika-select pika-select-month">' + arr.join('') + '</select></div>';
- if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
- next = false;
- }
- html += '<a class="pika-next' + (next ? '' : ' is-disabled') + '" href="javascript:void(0);">></a>';
- return html += '</div>';
- },
- renderTable = function (opts, data) {
- return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead(opts) + renderBody(data) + '</table>';
- };
- /**
- * Pikaday constructor
- */
- window.Pikaday = function (options) {
- var self = this,
- opts = self.config(options);
- self._hh = 0;
- self._mi = 0;
- self._onMouseDown = function (e) {
- if (!self._v) {
- return;
- }
- e = e || window.event;
- var target = e.target || e.srcElement;
- if (!target) {
- return;
- }
- if (!hasClass(target, 'is-disabled')) {
- if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) {
- self.setDate(new Date(self._y, self._m, parseInt(target.innerHTML, 10)));
- if (opts.bound) {
- sto(function () {
- self.hide();
- }, 100);
- }
- return;
- }
- else if (hasClass(target, 'pika-prev')) {
- self.prevMonth();
- }
- else if (hasClass(target, 'pika-next')) {
- self.nextMonth();
- }
- }
- if (!hasClass(target, 'pika-select')) {
- if (e.preventDefault) {
- e.preventDefault();
- } else {
- return e.returnValue = false;
- }
- } else {
- self._c = true;
- }
- };
- self._onChange = function (e) {
- e = e || window.event;
- var target = e.target || e.srcElement;
- if (!target) {
- return;
- }
- if (hasClass(target, 'pika-select-month')) {
- self.gotoMonth(target.value);
- }
- else if (hasClass(target, 'pika-select-year')) {
- self.gotoYear(target.value);
- }
- };
- self._onInputChange = function (e) {
- if (hasMoment) {
- self.setDate(window.moment(opts.field.value, opts.format).toDate());
- }
- else {
- var date = new Date(Date.parse(opts.field.value));
- self.setDate(isDate(date) ? date : null);
- }
- if (!self._v) {
- self.show();
- }
- };
- self._onInputFocus = function (e) {
- self.show();
- };
- self._onInputClick = function (e) {
- self.show();
- };
- self._onInputBlur = function (e) {
- if (!self._c) {
- self._b = sto(function () {
- self.hide();
- }, 50);
- }
- self._c = false;
- };
- self._onClick = function (e) {
- e = e || window.event;
- var target = e.target || e.srcElement,
- pEl = target;
- if (!target) {
- return;
- }
- if (!hasEventListeners && hasClass(target, 'pika-select')) {
- if (!target.onchange) {
- target.setAttribute('onchange', 'return;');
- addEvent(target, 'change', self._onChange);
- }
- }
- do {
- if (hasClass(pEl, 'pika-single')) {
- return;
- }
- }
- while ((pEl = pEl.parentNode));
- if (self._v && target !== opts.field) {
- self.hide();
- }
- };
-
- self.el = document.createElement('div');
- self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '');
- addEvent(self.el, 'mousedown', self._onMouseDown, true);
- addEvent(self.el, 'change', self._onChange);
- if (opts.field) {
- if (opts.bound) {
- $('body').prepend(self.el);
- //document.body.appendChild(self.el);
- } else {
- opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
- }
- addEvent(opts.field, 'change', self._onInputChange);
- if (!opts.defaultDate) {
- if (hasMoment && opts.field.value) {
- opts.defaultDate = window.moment(opts.field.value, opts.format).toDate();
- } else {
- opts.defaultDate = new Date(Date.parse(opts.field.value));
- }
- opts.setDefaultDate = true;
- }
- }
- var defDate = opts.defaultDate;
- if (isDate(defDate)) {
- if (opts.setDefaultDate) {
- self.setDate(defDate);
- } else {
- self.gotoDate(defDate);
- }
- } else {
- self.gotoDate(new Date());
- }
- if (opts.bound) {
- this.hide();
- self.el.className += ' is-bound';
- addEvent(opts.field, 'click', self._onInputClick);
- addEvent(opts.field, 'focus', self._onInputFocus);
- addEvent(opts.field, 'blur', self._onInputBlur);
- } else {
- this.show();
- }
- };
- /**
- * public Pikaday API
- */
- window.Pikaday.prototype = {
- /**
- * configure functionality
- */
- config: function (options) {
- if (!this._o) {
- this._o = extend({}, defaults, true);
- }
- var opts = extend(this._o, options, true);
- opts.isRTL = !!opts.isRTL;
- opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
- opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
- var nom = parseInt(opts.numberOfMonths, 10) || 1;
- opts.numberOfMonths = nom > 4 ? 4 : nom;
- if (!isDate(opts.minDate)) {
- opts.minDate = false;
- }
- if (!isDate(opts.maxDate)) {
- opts.maxDate = false;
- }
- if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
- opts.maxDate = opts.minDate = false;
- }
- if (opts.minDate) {
- opts.minYear = opts.minDate.getFullYear();
- opts.minMonth = opts.minDate.getMonth();
- }
- if (opts.maxDate) {
- opts.maxYear = opts.maxDate.getFullYear();
- opts.maxMonth = opts.maxDate.getMonth();
- }
- if (isArray(opts.yearRange)) {
- var fallback = new Date().getFullYear() - 10;
- opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
- opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
- } else {
- opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
- if (opts.yearRange > 100) {
- opts.yearRange = 100;
- }
- }
- return opts;
- },
- /**
- * return a formatted string of the current selection (using Moment.js if available)
- */
- toString: function (format) {
- if (!isDate(this._d)) return '';
- var y = this._d.getFullYear();
- var m = this._d.getMonth() + 1;
- var d = this._d.getDate();
- m = m < 10 ? '0' + m : m;
- d = d < 10 ? '0' + d : d;
- return hasMoment ? window.moment(this._d).format(format || this._o.format) : (y + '-' + m + '-' + d);
- },
- /**
- * return a Moment.js object of the current selection (if available)
- */
- getMoment: function () {
- return hasMoment ? window.moment(this._d) : null;
- },
- /**
- * return a Date object of the current selection
- */
- getDate: function () {
- return isDate(this._d) ? new Date(this._d.getTime()) : null;
- },
- /**
- * set the current selection
- */
- setDate: function (date) {
- if (!date) {
- this._d = null;
- return this.draw();
- }
- if (typeof date === 'string') {
- date = new Date(Date.parse(date));
- }
- if (!isDate(date)) {
- return;
- }
- var min = this._o.minDate,
- max = this._o.maxDate;
- if (isDate(min) && date < min) {
- date = min;
- } else if (isDate(max) && date > max) {
- date = max;
- }
- this._d = new Date(date.getTime());
- this._d.setHours(0, 0, 0, 0);
- this.gotoDate(this._d);
- if (this._o.field) {
- this._o.field.value = this.toString();
- }
- if (typeof this._o.onSelect === 'function') {
- this._o.onSelect.call(this, this.getDate());
- }
- },
- /**
- * change view to a specific date
- */
- gotoDate: function (date) {
- if (!isDate(date)) {
- return;
- }
- this._y = date.getFullYear();
- this._m = date.getMonth();
- this.draw();
- },
- gotoToday: function () {
- this.gotoDate(new Date());
- },
- /**
- * change view to a specific month (zero-index, e.g. 0: January)
- */
- gotoMonth: function (month) {
- if (!isNaN((month = parseInt(month, 10)))) {
- this._m = month < 0 ? 0 : month > 11 ? 11 : month;
- this.draw();
- }
- },
- nextMonth: function () {
- if (++this._m > 11) {
- this._m = 0;
- this._y++;
- }
- this.draw();
- },
- prevMonth: function () {
- if (--this._m < 0) {
- this._m = 11;
- this._y--;
- }
- this.draw();
- },
- /**
- * change view to a specific full year (e.g. "2012")
- */
- gotoYear: function (year) {
- if (!isNaN(year)) {
- this._y = parseInt(year, 10);
- this.draw();
- }
- },
- /**
- * refresh the HTML
- */
- draw: function (force) {
- if (!this._v && !force) {
- return;
- }
- var opts = this._o,
- minYear = opts.minYear,
- maxYear = opts.maxYear,
- minMonth = opts.minMonth,
- maxMonth = opts.maxMonth;
- if (this._y <= minYear) {
- this._y = minYear;
- if (!isNaN(minMonth) && this._m < minMonth) {
- this._m = minMonth;
- }
- }
- if (this._y >= maxYear) {
- this._y = maxYear;
- if (!isNaN(maxMonth) && this._m > maxMonth) {
- this._m = maxMonth;
- }
- }
- this.el.innerHTML = renderTitle(this) + this.render(this._y, this._m);
- if (opts.bound) {
- var pEl = opts.field,
- left = pEl.offsetLeft,
- top = pEl.offsetTop + pEl.offsetHeight;
- while ((pEl = pEl.offsetParent)) {
- left += pEl.offsetLeft;
- top += pEl.offsetTop;
- }
- //alert($(this.el).offset().top)
- this.el.style.cssText = 'position:absolute;left:' + (left) + 'px;top:' + top + 'px;';
- //this.el.style.cssText = 'position:absolute;left:' + (left + 1.5) + 'px;top:' + (top + 2) + 'px;';
- sto(function () {
- opts.field.focus();
- }, 1);
- }
- },
- /**
- * render HTML for a particular month
- */
- render: function (year, month) {
- var opts = this._o,
- now = new Date(),
- days = getDaysInMonth(year, month),
- before = new Date(year, month, 1).getDay(),
- data = [],
- row = [];
- now.setHours(0, 0, 0, 0);
- if (opts.firstDay > 0) {
- before -= opts.firstDay;
- if (before < 0) {
- before += 7;
- }
- }
- var cells = days + before,
- after = cells;
- while (after > 7) {
- after -= 7;
- }
- cells += 7 - after;
- for (var i = 0, r = 0; i < cells; i++) {
- var day = new Date(year, month, 1 + (i - before)),
- isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate),
- isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
- isToday = compareDates(day, now),
- isEmpty = i < before || i >= (days + before);
- row.push(renderDay(1 + (i - before), isSelected, isToday, isDisabled, isEmpty));
- if (++r === 7) {
- data.push(renderRow(row, opts.isRTL));
- row = [];
- r = 0;
- }
- }
- return renderTable(opts, data);
- },
- isVisible: function () {
- return this._v;
- },
- show: function () {
- if (!this._v) {
- if (this._o.bound) {
- addEvent(document, 'click', this._onClick);
- }
- removeClass(this.el, 'is-hidden');
- this._v = true;
- this.draw();
- if (typeof this._o.onOpen === 'function') {
- this._o.onOpen.call(this);
- }
- }
- },
- hide: function () {
- var v = this._v;
- if (v !== false) {
- if (this._o.bound) {
- removeEvent(document, 'click', this._onClick);
- }
- this.el.style.cssText = '';
- addClass(this.el, 'is-hidden');
- this._v = false;
- if (v !== undefined && typeof this._o.onClose === 'function') {
- this._o.onClose.call(this);
- }
- }
- },
- /**
- * GAME OVER
- */
- destroy: function () {
- this.hide();
- removeEvent(this.el, 'mousedown', this._onMouseDown, true);
- removeEvent(this.el, 'change', this._onChange);
- if (this._o.field) {
- removeEvent(this._o.field, 'change', this._onInputChange);
- if (this._o.bound) {
- removeEvent(this._o.field, 'click', this._onInputClick);
- removeEvent(this._o.field, 'focus', this._onInputFocus);
- removeEvent(this._o.field, 'blur', this._onInputBlur);
- }
- }
- if (this.el.parentNode) {
- this.el.parentNode.removeChild(this.el);
- }
- }
- };
- })(window, window.document);
|