tsichart-core 2.0.0-beta.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -576,50 +576,89 @@ class Utils {
576
576
  }
577
577
  return hclColor.toString();
578
578
  }
579
+ /**
580
+ * Creates an array of colors for split-by series
581
+ * @param displayState - The current display state
582
+ * @param aggKey - The aggregate key
583
+ * @param ignoreIsOnlyAgg - Whether to ignore the "only aggregate" optimization
584
+ * @returns Array of color strings for each split-by
585
+ */
579
586
  static createSplitByColors(displayState, aggKey, ignoreIsOnlyAgg = false) {
580
- if (Object.keys(displayState[aggKey]["splitBys"]).length == 1)
587
+ const splitBys = displayState[aggKey]?.splitBys;
588
+ if (!splitBys) {
589
+ return [];
590
+ }
591
+ const splitByCount = Object.keys(splitBys).length;
592
+ // Early return for single split-by
593
+ if (splitByCount === 1) {
581
594
  return [displayState[aggKey].color];
582
- var isOnlyAgg = Object.keys(displayState).reduce((accum, currAgg) => {
583
- if (currAgg == aggKey)
584
- return accum;
585
- if (displayState[currAgg]["visible"] == false)
586
- return accum && true;
587
- return false;
588
- }, true);
589
- if (isOnlyAgg && !ignoreIsOnlyAgg) {
590
- return this.generateColors(Object.keys(displayState[aggKey]["splitBys"]).length);
591
595
  }
592
- var aggColor = displayState[aggKey].color;
593
- var interpolateColor = d3__namespace.scaleLinear().domain([0, Object.keys(displayState[aggKey]["splitBys"]).length])
594
- .range([d3__namespace.hcl(aggColor).darker().l, d3__namespace.hcl(aggColor).brighter().l]);
595
- var colors = [];
596
- for (var i = 0; i < Object.keys(displayState[aggKey]["splitBys"]).length; i++) {
597
- const newColor = d3__namespace.hcl(aggColor);
596
+ // Create cache key for memoization
597
+ const cacheKey = `${aggKey}_${splitByCount}_${displayState[aggKey].color}_${ignoreIsOnlyAgg}`;
598
+ if (this.splitByColorCache.has(cacheKey)) {
599
+ return this.splitByColorCache.get(cacheKey);
600
+ }
601
+ const isOnlyVisibleAgg = !ignoreIsOnlyAgg && this.isOnlyVisibleAggregate(displayState, aggKey);
602
+ let colors;
603
+ if (isOnlyVisibleAgg) {
604
+ // Generate distinct colors when this is the only visible aggregate
605
+ colors = this.generateColors(splitByCount);
606
+ }
607
+ else {
608
+ // Generate color variations based on aggregate color
609
+ colors = this.generateSplitByColorVariations(displayState[aggKey].color, splitByCount);
610
+ }
611
+ // Cache the result
612
+ this.splitByColorCache.set(cacheKey, colors);
613
+ // Limit cache size to prevent memory leaks
614
+ if (this.splitByColorCache.size > 100) {
615
+ const firstKey = this.splitByColorCache.keys().next().value;
616
+ this.splitByColorCache.delete(firstKey);
617
+ }
618
+ return colors;
619
+ }
620
+ /**
621
+ * Helper method to check if an aggregate is the only visible one
622
+ */
623
+ static isOnlyVisibleAggregate(displayState, aggKey) {
624
+ for (const currAgg in displayState) {
625
+ if (currAgg !== aggKey && displayState[currAgg]?.visible !== false) {
626
+ return false;
627
+ }
628
+ }
629
+ return true;
630
+ }
631
+ /**
632
+ * Helper method to generate color variations for split-bys
633
+ */
634
+ static generateSplitByColorVariations(baseColor, count) {
635
+ const baseHcl = d3__namespace.hcl(baseColor);
636
+ const interpolateColor = d3__namespace.scaleLinear()
637
+ .domain([0, count])
638
+ .range([baseHcl.darker().l, baseHcl.brighter().l]);
639
+ const colors = new Array(count);
640
+ for (let i = 0; i < count; i++) {
641
+ const newColor = d3__namespace.hcl(baseColor);
598
642
  newColor.l = interpolateColor(i);
599
- colors.push(newColor.formatHex());
643
+ colors[i] = newColor.formatHex();
600
644
  }
601
645
  return colors;
602
646
  }
647
+ /**
648
+ * Clears the split-by color cache (useful when display state changes significantly)
649
+ */
650
+ static clearSplitByColorCache() {
651
+ this.splitByColorCache.clear();
652
+ }
603
653
  static colorSplitBy(displayState, splitByIndex, aggKey, ignoreIsOnlyAgg = false) {
604
- if (Object.keys(displayState[aggKey]["splitBys"]).length == 1)
605
- return displayState[aggKey].color;
606
- var isOnlyAgg = Object.keys(displayState).reduce((accum, currAgg) => {
607
- if (currAgg == aggKey)
608
- return accum;
609
- if (displayState[currAgg]["visible"] == false)
610
- return accum && true;
611
- return false;
612
- }, true);
613
- if (isOnlyAgg && !ignoreIsOnlyAgg) {
614
- var splitByColors = this.generateColors(Object.keys(displayState[aggKey]["splitBys"]).length);
615
- return splitByColors[splitByIndex];
654
+ const colors = this.createSplitByColors(displayState, aggKey, ignoreIsOnlyAgg);
655
+ if (typeof splitByIndex === 'number' &&
656
+ Number.isInteger(splitByIndex) &&
657
+ splitByIndex >= 0 &&
658
+ splitByIndex < colors.length) {
659
+ return colors[splitByIndex];
616
660
  }
617
- var aggColor = displayState[aggKey].color;
618
- var interpolateColor = d3__namespace.scaleLinear().domain([0, Object.keys(displayState[aggKey]["splitBys"]).length])
619
- .range([d3__namespace.hcl(aggColor).darker().l, d3__namespace.hcl(aggColor).brighter().l]);
620
- const newColor = d3__namespace.hcl(aggColor);
621
- newColor.l = interpolateColor(splitByIndex);
622
- return newColor.formatHex();
661
+ return displayState[aggKey]?.color || '#000000';
623
662
  }
624
663
  static getTheme(theme) {
625
664
  return theme ? 'tsi-' + theme : 'tsi-dark';
@@ -1043,6 +1082,7 @@ class Utils {
1043
1082
  }
1044
1083
  }
1045
1084
  Utils.guidForNullTSID = Utils.guid();
1085
+ Utils.splitByColorCache = new Map();
1046
1086
  Utils.equalToEventTarget = (function (current, event) {
1047
1087
  return (current == event.target);
1048
1088
  });
@@ -3461,6 +3501,8 @@ class ContextMenu extends Component {
3461
3501
  this.drawChart = drawChart;
3462
3502
  this.contextMenuElement = d3__namespace.select(renderTarget).insert("div", ":first-child")
3463
3503
  .attr("class", "tsi-contextMenu")
3504
+ .attr("aria-label", "Context Menu")
3505
+ .attr("role", "menu")
3464
3506
  .style("left", "0px")
3465
3507
  .style("top", "0px");
3466
3508
  }
@@ -3549,6 +3591,7 @@ class ContextMenu extends Component {
3549
3591
  var actionElementsEntered = actionElements.enter()
3550
3592
  .append("div")
3551
3593
  .attr("class", `tsi-actionElement`)
3594
+ .attr("role", "menuitem")
3552
3595
  .classed('tsi-hasSubMenu', d => d.isNested)
3553
3596
  .merge(actionElements)
3554
3597
  .text(d => d.name)
@@ -3675,6 +3718,7 @@ class Tooltip extends Component {
3675
3718
  }).data([theme]);
3676
3719
  this.tooltipDiv = tooltip.enter().append('div')
3677
3720
  .attr('class', 'tsi-tooltip')
3721
+ .attr('role', 'tooltip')
3678
3722
  .merge(tooltip)
3679
3723
  .each(function (d) {
3680
3724
  d3__namespace.select(this).selectAll("*").remove();
@@ -6280,6 +6324,8 @@ class LineChart extends TemporalXAxisComponent {
6280
6324
  label.enter()
6281
6325
  .append("text")
6282
6326
  .attr("class", (d) => `tsi-swimLaneLabel-${lane} tsi-swimLaneLabel ${onClickPresentAndValid(d) ? 'tsi-boldOnHover' : ''}`)
6327
+ .attr("role", "heading")
6328
+ .attr("aria-level", "3")
6283
6329
  .merge(label)
6284
6330
  .style("text-anchor", "middle")
6285
6331
  .attr("transform", d => `translate(${(-this.horizontalLabelOffset + swimlaneLabelConstants.labelLeftPadding)},${(d.offset + d.height / 2)}) rotate(-90)`)
@@ -6304,13 +6350,12 @@ class LineChart extends TemporalXAxisComponent {
6304
6350
  });
6305
6351
  }
6306
6352
  render(data, options, aggregateExpressionOptions) {
6307
- console.log('LineChart render called a');
6308
6353
  super.render(data, options, aggregateExpressionOptions);
6309
6354
  this.originalSwimLanes = this.aggregateExpressionOptions.map((aEO) => {
6310
6355
  return aEO.swimLane;
6311
6356
  });
6312
6357
  this.originalSwimLaneOptions = options.swimLaneOptions;
6313
- this.hasBrush = options && (options.brushMoveAction || options.brushMoveEndAction || options.brushContextMenuActions);
6358
+ this.hasBrush = !!(options && (options.brushMoveAction || options.brushMoveEndAction || options.brushContextMenuActions));
6314
6359
  this.chartOptions.setOptions(options);
6315
6360
  this.chartMargins.right = this.chartOptions.labelSeriesWithMarker ? (SERIESLABELWIDTH + 8) : LINECHARTCHARTMARGINS.right;
6316
6361
  this.width = this.getWidth();
@@ -6359,6 +6404,7 @@ class LineChart extends TemporalXAxisComponent {
6359
6404
  .attr("type", "button")
6360
6405
  .on("click", function () {
6361
6406
  self.overwriteSwimLanes();
6407
+ // cast to any to avoid TS incompatibility when spreading chartOptions instance into ILineChartOptions
6362
6408
  self.render(self.data, { ...self.chartOptions, yAxisState: self.nextStackedState() }, self.aggregateExpressionOptions);
6363
6409
  d3__namespace.select(this).attr("aria-label", () => self.getString("set axis state to") + ' ' + self.nextStackedState());
6364
6410
  setTimeout(() => d3__namespace.select(this).node().focus(), 200);
@@ -6385,6 +6431,7 @@ class LineChart extends TemporalXAxisComponent {
6385
6431
  this.svgSelection = this.targetElement.append("svg")
6386
6432
  .attr("class", "tsi-lineChartSVG tsi-chartSVG")
6387
6433
  .attr('title', this.getString('Line chart'))
6434
+ .attr("role", "img")
6388
6435
  .attr("height", this.height);
6389
6436
  var g = this.svgSelection.append("g")
6390
6437
  .classed("svgGroup", true)
@@ -6770,6 +6817,54 @@ class LineChart extends TemporalXAxisComponent {
6770
6817
  }
6771
6818
  }
6772
6819
 
6820
+ class TimezonePicker extends ChartComponent {
6821
+ constructor(renderTarget) {
6822
+ super(renderTarget);
6823
+ this.timeZones = ["Local", "UTC", "Africa/Algiers", "Africa/Cairo", "Africa/Casablanca", "Africa/Harare", "Africa/Johannesburg", "Africa/Lagos", "Africa/Nairobi", "Africa/Windhoek", "America/Anchorage", "America/Bogota", "America/Buenos Aires", "America/Caracas", "America/Chicago", "America/Chihuahua", "America/Denver", "America/Edmonton", "America/Godthab", "America/Guatemala", "America/Halifax", "America/Indiana/Indianapolis", "America/Los Angeles", "America/Manaus", "America/Mexico City", "America/Montevideo", "America/New York", "America/Phoenix", "America/Santiago", "America/Sao Paulo", "America/St Johns", "America/Tijuana", "America/Toronto", "America/Vancouver", "America/Winnipeg", "Asia/Amman", "Asia/Beirut", "Asia/Baghdad", "Asia/Baku", "Asia/Bangkok", "Asia/Calcutta", "Asia/Colombo", "Asia/Dhaka", "Asia/Dubai", "Asia/Ho Chi Minh", "Asia/Hong Kong", "Asia/Irkutsk", "Asia/Istanbul", "Asia/Jakarta", "Asia/Jerusalem", "Asia/Kabul", "Asia/Karachi", "Asia/Kathmandu", "Asia/Krasnoyarsk", "Asia/Kuala Lumpur", "Asia/Kuwait", "Asia/Magadan", "Asia/Muscat", "Asia/Novosibirsk", "Asia/Qatar", "Asia/Rangoon", "Asia/Seoul", "Asia/Shanghai", "Asia/Singapore", "Asia/Taipei", "Asia/Tbilisi", "Asia/Tehran", "Asia/Tokyo", "Asia/Vladivostok", "Asia/Yakutsk", "Asia/Yekaterinburg", "Asia/Yerevan", "Atlantic/Azores", "Atlantic/Cape Verde", "Atlantic/South Georgia", "Australia/Adelaide", "Australia/Brisbane", "Australia/Canberra", "Australia/Darwin", "Australia/Hobart", "Australia/Melbourne", "Australia/Perth", "Australia/Queensland", "Australia/Sydney", "Europe/Amsterdam", "Europe/Andorra", "Europe/Athens", "Europe/Belfast", "Europe/Belgrade", "Europe/Berlin", "Europe/Brussels", "Europe/Budapest", "Europe/Dublin", "Europe/Helsinki", "Europe/Kiev", "Europe/Lisbon", "Europe/London", "Europe/Luxembourg", "Europe/Madrid", "Europe/Minsk", "Europe/Monaco", "Europe/Moscow", "Europe/Oslo", "Europe/Paris", "Europe/Rome", "Europe/Stockholm", "Europe/Vienna", "Europe/Warsaw", "Europe/Zurich", "Pacific/Auckland", "Pacific/Fiji", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Midway", "Pacific/Tongatapu"];
6824
+ }
6825
+ sortTimezones() {
6826
+ let filteredTimezones = this.timeZones.filter((tz) => {
6827
+ return !(tz.toLowerCase() == 'local' || tz == 'UTC');
6828
+ });
6829
+ filteredTimezones.sort((a, b) => {
6830
+ let aOffset = moment.tz(new Date(), a.split(' ').join('_')).utcOffset();
6831
+ let bOffset = moment.tz(new Date(), b.split(' ').join('_')).utcOffset();
6832
+ if (aOffset < bOffset) {
6833
+ return -1;
6834
+ }
6835
+ if (aOffset > bOffset) {
6836
+ return 1;
6837
+ }
6838
+ return 0;
6839
+ });
6840
+ this.timeZones = ['Local', 'UTC'].concat(filteredTimezones);
6841
+ }
6842
+ render(onTimezoneSelect, defaultTimeZone = null) {
6843
+ this.targetElement = d3__namespace.select(this.renderTarget)
6844
+ .classed("tsi-timezonePicker", true);
6845
+ var timezoneSelection = this.targetElement.append("select")
6846
+ .attr("class", "tsi-timezonePicker tsi-select");
6847
+ this.sortTimezones();
6848
+ var options = timezoneSelection.selectAll("option")
6849
+ .data(this.timeZones)
6850
+ .enter()
6851
+ .append("option")
6852
+ .attr('value', d => d)
6853
+ .text((tz) => Utils.convertTimezoneToLabel(tz, this.getString('Local')));
6854
+ timezoneSelection.on("change", function (d) {
6855
+ var timezone = d3__namespace.select(this).node().value.replace(/\s/g, "_");
6856
+ onTimezoneSelect(timezone);
6857
+ });
6858
+ defaultTimeZone = defaultTimeZone.replace(/_/g, " ");
6859
+ if (defaultTimeZone != null) {
6860
+ options.filter((d) => d == defaultTimeZone).attr("selected", true);
6861
+ }
6862
+ return;
6863
+ }
6864
+ }
6865
+
6866
+ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
6867
+
6773
6868
  function getDefaultExportFromCjs (x) {
6774
6869
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
6775
6870
  }
@@ -6789,1231 +6884,1177 @@ function requirePikaday () {
6789
6884
  if (hasRequiredPikaday) return pikaday$1.exports;
6790
6885
  hasRequiredPikaday = 1;
6791
6886
  (function (module, exports) {
6792
- (function (root, factory)
6793
- {
6887
+ (function (root, factory) {
6794
6888
 
6795
6889
  var moment;
6796
6890
  {
6797
6891
  // CommonJS module
6798
6892
  // Load moment.js as an optional dependency
6799
- try { moment = require('moment'); } catch (e) {}
6893
+ try { moment = require('moment'); } catch (e) { moment = (typeof window !== 'undefined' && window.moment) || undefined; }
6800
6894
  module.exports = factory(moment);
6801
6895
  }
6802
- }(pikaday, function (moment)
6803
- {
6896
+ }(typeof self !== 'undefined' ? self :
6897
+ typeof window !== 'undefined' ? window :
6898
+ typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
6899
+ pikaday, function (moment) {
6804
6900
 
6805
- /**
6806
- * feature detection and helper functions
6807
- */
6808
- var hasMoment = typeof moment === 'function',
6901
+ /**
6902
+ * feature detection and helper functions
6903
+ */
6904
+ var hasMoment = typeof moment === 'function' || (moment && typeof moment.version === 'string'),
6809
6905
 
6810
- hasEventListeners = !!window.addEventListener,
6906
+ hasEventListeners = !!window.addEventListener,
6811
6907
 
6812
- document = window.document,
6908
+ document = window.document,
6813
6909
 
6814
- sto = window.setTimeout,
6910
+ sto = window.setTimeout,
6815
6911
 
6816
- addEvent = function(el, e, callback, capture)
6817
- {
6818
- if (hasEventListeners) {
6819
- el.addEventListener(e, callback, !!capture);
6820
- } else {
6821
- el.attachEvent('on' + e, callback);
6822
- }
6823
- },
6824
-
6825
- removeEvent = function(el, e, callback, capture)
6826
- {
6827
- if (hasEventListeners) {
6828
- el.removeEventListener(e, callback, !!capture);
6829
- } else {
6830
- el.detachEvent('on' + e, callback);
6831
- }
6832
- },
6833
-
6834
- trim = function(str)
6835
- {
6836
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
6837
- },
6912
+ addEvent = function (el, e, callback, capture) {
6913
+ if (hasEventListeners) {
6914
+ el.addEventListener(e, callback, !!capture);
6915
+ } else {
6916
+ el.attachEvent('on' + e, callback);
6917
+ }
6918
+ },
6838
6919
 
6839
- hasClass = function(el, cn)
6840
- {
6841
- return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
6842
- },
6920
+ removeEvent = function (el, e, callback, capture) {
6921
+ if (hasEventListeners) {
6922
+ el.removeEventListener(e, callback, !!capture);
6923
+ } else {
6924
+ el.detachEvent('on' + e, callback);
6925
+ }
6926
+ },
6843
6927
 
6844
- addClass = function(el, cn)
6845
- {
6846
- if (!hasClass(el, cn)) {
6847
- el.className = (el.className === '') ? cn : el.className + ' ' + cn;
6848
- }
6849
- },
6928
+ trim = function (str) {
6929
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
6930
+ },
6850
6931
 
6851
- removeClass = function(el, cn)
6852
- {
6853
- el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
6854
- },
6932
+ hasClass = function (el, cn) {
6933
+ return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
6934
+ },
6855
6935
 
6856
- isArray = function(obj)
6857
- {
6858
- return (/Array/).test(Object.prototype.toString.call(obj));
6859
- },
6936
+ addClass = function (el, cn) {
6937
+ if (!hasClass(el, cn)) {
6938
+ el.className = (el.className === '') ? cn : el.className + ' ' + cn;
6939
+ }
6940
+ },
6941
+
6942
+ removeClass = function (el, cn) {
6943
+ el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
6944
+ },
6945
+
6946
+ isArray = function (obj) {
6947
+ return (/Array/).test(Object.prototype.toString.call(obj));
6948
+ },
6949
+
6950
+ isDate = function (obj) {
6951
+ return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
6952
+ },
6953
+
6954
+ isWeekend = function (date) {
6955
+ var day = date.getDay();
6956
+ return day === 0 || day === 6;
6957
+ },
6958
+
6959
+ isLeapYear = function (year) {
6960
+ // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
6961
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
6962
+ },
6963
+
6964
+ getDaysInMonth = function (year, month) {
6965
+ return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
6966
+ },
6967
+
6968
+ setToStartOfDay = function (date) {
6969
+ if (isDate(date)) date.setHours(0, 0, 0, 0);
6970
+ },
6971
+
6972
+ compareDates = function (a, b) {
6973
+ // weak date comparison (use setToStartOfDay(date) to ensure correct result)
6974
+ return a.getTime() === b.getTime();
6975
+ },
6976
+
6977
+ extend = function (to, from, overwrite) {
6978
+ var prop, hasProp;
6979
+ for (prop in from) {
6980
+ hasProp = to[prop] !== undefined;
6981
+ if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) {
6982
+ if (isDate(from[prop])) {
6983
+ if (overwrite) {
6984
+ to[prop] = new Date(from[prop].getTime());
6985
+ }
6986
+ }
6987
+ else if (isArray(from[prop])) {
6988
+ if (overwrite) {
6989
+ to[prop] = from[prop].slice(0);
6990
+ }
6991
+ } else {
6992
+ to[prop] = extend({}, from[prop], overwrite);
6993
+ }
6994
+ } else if (overwrite || !hasProp) {
6995
+ to[prop] = from[prop];
6996
+ }
6997
+ }
6998
+ return to;
6999
+ },
7000
+
7001
+ fireEvent = function (el, eventName, data) {
7002
+ var ev;
7003
+
7004
+ if (document.createEvent) {
7005
+ ev = document.createEvent('HTMLEvents');
7006
+ ev.initEvent(eventName, true, false);
7007
+ ev = extend(ev, data);
7008
+ el.dispatchEvent(ev);
7009
+ } else if (document.createEventObject) {
7010
+ ev = document.createEventObject();
7011
+ ev = extend(ev, data);
7012
+ el.fireEvent('on' + eventName, ev);
7013
+ }
7014
+ },
6860
7015
 
6861
- isDate = function(obj)
6862
- {
6863
- return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
6864
- },
7016
+ adjustCalendar = function (calendar) {
7017
+ if (calendar.month < 0) {
7018
+ calendar.year -= Math.ceil(Math.abs(calendar.month) / 12);
7019
+ calendar.month += 12;
7020
+ }
7021
+ if (calendar.month > 11) {
7022
+ calendar.year += Math.floor(Math.abs(calendar.month) / 12);
7023
+ calendar.month -= 12;
7024
+ }
7025
+ return calendar;
7026
+ },
6865
7027
 
6866
- isWeekend = function(date)
6867
- {
6868
- var day = date.getDay();
6869
- return day === 0 || day === 6;
6870
- },
7028
+ /**
7029
+ * defaults and localisation
7030
+ */
7031
+ defaults = {
6871
7032
 
6872
- isLeapYear = function(year)
6873
- {
6874
- // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
6875
- return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
6876
- },
7033
+ // bind the picker to a form field
7034
+ field: null,
6877
7035
 
6878
- getDaysInMonth = function(year, month)
6879
- {
6880
- return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
6881
- },
7036
+ // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
7037
+ bound: undefined,
6882
7038
 
6883
- setToStartOfDay = function(date)
6884
- {
6885
- if (isDate(date)) date.setHours(0,0,0,0);
6886
- },
7039
+ // position of the datepicker, relative to the field (default to bottom & left)
7040
+ // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
7041
+ position: 'bottom left',
6887
7042
 
6888
- compareDates = function(a,b)
6889
- {
6890
- // weak date comparison (use setToStartOfDay(date) to ensure correct result)
6891
- return a.getTime() === b.getTime();
6892
- },
7043
+ // automatically fit in the viewport even if it means repositioning from the position option
7044
+ reposition: true,
6893
7045
 
6894
- extend = function(to, from, overwrite)
6895
- {
6896
- var prop, hasProp;
6897
- for (prop in from) {
6898
- hasProp = to[prop] !== undefined;
6899
- if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) {
6900
- if (isDate(from[prop])) {
6901
- if (overwrite) {
6902
- to[prop] = new Date(from[prop].getTime());
6903
- }
6904
- }
6905
- else if (isArray(from[prop])) {
6906
- if (overwrite) {
6907
- to[prop] = from[prop].slice(0);
6908
- }
6909
- } else {
6910
- to[prop] = extend({}, from[prop], overwrite);
6911
- }
6912
- } else if (overwrite || !hasProp) {
6913
- to[prop] = from[prop];
6914
- }
6915
- }
6916
- return to;
6917
- },
6918
-
6919
- fireEvent = function(el, eventName, data)
6920
- {
6921
- var ev;
7046
+ // the default output format for `.toString()` and `field` value
7047
+ format: 'YYYY-MM-DD',
6922
7048
 
6923
- if (document.createEvent) {
6924
- ev = document.createEvent('HTMLEvents');
6925
- ev.initEvent(eventName, true, false);
6926
- ev = extend(ev, data);
6927
- el.dispatchEvent(ev);
6928
- } else if (document.createEventObject) {
6929
- ev = document.createEventObject();
6930
- ev = extend(ev, data);
6931
- el.fireEvent('on' + eventName, ev);
6932
- }
6933
- },
7049
+ // the toString function which gets passed a current date object and format
7050
+ // and returns a string
7051
+ toString: null,
6934
7052
 
6935
- adjustCalendar = function(calendar) {
6936
- if (calendar.month < 0) {
6937
- calendar.year -= Math.ceil(Math.abs(calendar.month)/12);
6938
- calendar.month += 12;
6939
- }
6940
- if (calendar.month > 11) {
6941
- calendar.year += Math.floor(Math.abs(calendar.month)/12);
6942
- calendar.month -= 12;
6943
- }
6944
- return calendar;
6945
- },
7053
+ // used to create date object from current input string
7054
+ parse: null,
6946
7055
 
6947
- /**
6948
- * defaults and localisation
6949
- */
6950
- defaults = {
7056
+ // the initial date to view when first opened
7057
+ defaultDate: null,
6951
7058
 
6952
- // bind the picker to a form field
6953
- field: null,
7059
+ // make the `defaultDate` the initial selected value
7060
+ setDefaultDate: false,
6954
7061
 
6955
- // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
6956
- bound: undefined,
7062
+ // first day of week (0: Sunday, 1: Monday etc)
7063
+ firstDay: 0,
6957
7064
 
6958
- // position of the datepicker, relative to the field (default to bottom & left)
6959
- // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
6960
- position: 'bottom left',
7065
+ // the default flag for moment's strict date parsing
7066
+ formatStrict: false,
6961
7067
 
6962
- // automatically fit in the viewport even if it means repositioning from the position option
6963
- reposition: true,
7068
+ // the minimum/earliest date that can be selected
7069
+ minDate: null,
7070
+ // the maximum/latest date that can be selected
7071
+ maxDate: null,
6964
7072
 
6965
- // the default output format for `.toString()` and `field` value
6966
- format: 'YYYY-MM-DD',
7073
+ // number of years either side, or array of upper/lower range
7074
+ yearRange: 10,
6967
7075
 
6968
- // the toString function which gets passed a current date object and format
6969
- // and returns a string
6970
- toString: null,
7076
+ // show week numbers at head of row
7077
+ showWeekNumber: false,
6971
7078
 
6972
- // used to create date object from current input string
6973
- parse: null,
7079
+ // Week picker mode
7080
+ pickWholeWeek: false,
6974
7081
 
6975
- // the initial date to view when first opened
6976
- defaultDate: null,
7082
+ // used internally (don't config outside)
7083
+ minYear: 0,
7084
+ maxYear: 9999,
7085
+ minMonth: undefined,
7086
+ maxMonth: undefined,
6977
7087
 
6978
- // make the `defaultDate` the initial selected value
6979
- setDefaultDate: false,
7088
+ startRange: null,
7089
+ endRange: null,
6980
7090
 
6981
- // first day of week (0: Sunday, 1: Monday etc)
6982
- firstDay: 0,
7091
+ isRTL: false,
6983
7092
 
6984
- // the default flag for moment's strict date parsing
6985
- formatStrict: false,
7093
+ // Additional text to append to the year in the calendar title
7094
+ yearSuffix: '',
6986
7095
 
6987
- // the minimum/earliest date that can be selected
6988
- minDate: null,
6989
- // the maximum/latest date that can be selected
6990
- maxDate: null,
7096
+ // Render the month after year in the calendar title
7097
+ showMonthAfterYear: false,
6991
7098
 
6992
- // number of years either side, or array of upper/lower range
6993
- yearRange: 10,
7099
+ // Render days of the calendar grid that fall in the next or previous month
7100
+ showDaysInNextAndPreviousMonths: false,
6994
7101
 
6995
- // show week numbers at head of row
6996
- showWeekNumber: false,
7102
+ // Allows user to select days that fall in the next or previous month
7103
+ enableSelectionDaysInNextAndPreviousMonths: false,
6997
7104
 
6998
- // Week picker mode
6999
- pickWholeWeek: false,
7105
+ // how many months are visible
7106
+ numberOfMonths: 1,
7000
7107
 
7001
- // used internally (don't config outside)
7002
- minYear: 0,
7003
- maxYear: 9999,
7004
- minMonth: undefined,
7005
- maxMonth: undefined,
7108
+ // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
7109
+ // only used for the first display or when a selected date is not visible
7110
+ mainCalendar: 'left',
7006
7111
 
7007
- startRange: null,
7008
- endRange: null,
7112
+ // Specify a DOM element to render the calendar in
7113
+ container: undefined,
7009
7114
 
7010
- isRTL: false,
7115
+ // Blur field when date is selected
7116
+ blurFieldOnSelect: true,
7011
7117
 
7012
- // Additional text to append to the year in the calendar title
7013
- yearSuffix: '',
7118
+ // internationalization
7119
+ i18n: {
7120
+ previousMonth: 'Previous Month',
7121
+ nextMonth: 'Next Month',
7122
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
7123
+ weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
7124
+ weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
7125
+ },
7014
7126
 
7015
- // Render the month after year in the calendar title
7016
- showMonthAfterYear: false,
7127
+ // Theme Classname
7128
+ theme: null,
7017
7129
 
7018
- // Render days of the calendar grid that fall in the next or previous month
7019
- showDaysInNextAndPreviousMonths: false,
7130
+ // events array
7131
+ events: [],
7020
7132
 
7021
- // Allows user to select days that fall in the next or previous month
7022
- enableSelectionDaysInNextAndPreviousMonths: false,
7023
-
7024
- // how many months are visible
7025
- numberOfMonths: 1,
7133
+ // callback function
7134
+ onSelect: null,
7135
+ onOpen: null,
7136
+ onClose: null,
7137
+ onDraw: null,
7026
7138
 
7027
- // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
7028
- // only used for the first display or when a selected date is not visible
7029
- mainCalendar: 'left',
7139
+ // Enable keyboard input
7140
+ keyboardInput: true
7141
+ },
7030
7142
 
7031
- // Specify a DOM element to render the calendar in
7032
- container: undefined,
7033
7143
 
7034
- // Blur field when date is selected
7035
- blurFieldOnSelect : true,
7144
+ /**
7145
+ * templating functions to abstract HTML rendering
7146
+ */
7147
+ renderDayName = function (opts, day, abbr) {
7148
+ day += opts.firstDay;
7149
+ while (day >= 7) {
7150
+ day -= 7;
7151
+ }
7152
+ return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
7153
+ },
7154
+
7155
+ renderDay = function (opts) {
7156
+ var arr = [];
7157
+ var ariaSelected = 'false';
7158
+ if (opts.isEmpty) {
7159
+ if (opts.showDaysInNextAndPreviousMonths) {
7160
+ arr.push('is-outside-current-month');
7161
+
7162
+ if (!opts.enableSelectionDaysInNextAndPreviousMonths) {
7163
+ arr.push('is-selection-disabled');
7164
+ }
7165
+
7166
+ } else {
7167
+ return '<td class="is-empty"></td>';
7168
+ }
7169
+ }
7170
+ if (opts.isDisabled) {
7171
+ arr.push('is-disabled');
7172
+ }
7173
+ if (opts.isToday) {
7174
+ arr.push('is-today');
7175
+ }
7176
+ if (opts.isSelected) {
7177
+ arr.push('is-selected');
7178
+ ariaSelected = 'true';
7179
+ }
7180
+ if (opts.hasEvent) {
7181
+ arr.push('has-event');
7182
+ }
7183
+ if (opts.isInRange) {
7184
+ arr.push('is-inrange');
7185
+ }
7186
+ if (opts.isStartRange) {
7187
+ arr.push('is-startrange');
7188
+ }
7189
+ if (opts.isEndRange) {
7190
+ arr.push('is-endrange');
7191
+ }
7192
+ return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
7193
+ '<button tabIndex="-1" class="pika-button pika-day" type="button" ' +
7194
+ 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
7195
+ opts.day +
7196
+ '</button>' +
7197
+ '</td>';
7198
+ },
7199
+
7200
+ renderWeek = function (d, m, y) {
7201
+ // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
7202
+ var onejan = new Date(y, 0, 1),
7203
+ weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay() + 1) / 7);
7204
+ return '<td class="pika-week">' + weekNum + '</td>';
7205
+ },
7206
+
7207
+ renderRow = function (days, isRTL, pickWholeWeek, isRowSelected) {
7208
+ return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>';
7209
+ },
7210
+
7211
+ renderBody = function (rows) {
7212
+ return '<tbody>' + rows.join('') + '</tbody>';
7213
+ },
7214
+
7215
+ renderHead = function (opts) {
7216
+ var i, arr = [];
7217
+ if (opts.showWeekNumber) {
7218
+ arr.push('<th></th>');
7219
+ }
7220
+ for (i = 0; i < 7; i++) {
7221
+ arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
7222
+ }
7223
+ return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
7224
+ },
7225
+
7226
+ renderTitle = function (instance, c, year, month, refYear, randId) {
7227
+ var i, j, arr,
7228
+ opts = instance._o,
7229
+ isMinYear = year === opts.minYear,
7230
+ isMaxYear = year === opts.maxYear,
7231
+ html = '<div id="' + randId + '" class="pika-title">',
7232
+ monthHtml,
7233
+ yearHtml,
7234
+ prev = true,
7235
+ next = true;
7236
+
7237
+ for (arr = [], i = 0; i < 12; i++) {
7238
+ arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
7239
+ (i === month ? ' selected="selected"' : '') +
7240
+ ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
7241
+ opts.i18n.months[i] + '</option>');
7242
+ }
7036
7243
 
7037
- // internationalization
7038
- i18n: {
7039
- previousMonth : 'Previous Month',
7040
- nextMonth : 'Next Month',
7041
- months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
7042
- weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
7043
- weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
7044
- },
7244
+ monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select aria-label="select month" class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>';
7045
7245
 
7046
- // Theme Classname
7047
- theme: null,
7246
+ if (isArray(opts.yearRange)) {
7247
+ i = opts.yearRange[0];
7248
+ j = opts.yearRange[1] + 1;
7249
+ } else {
7250
+ i = year - opts.yearRange;
7251
+ j = 1 + year + opts.yearRange;
7252
+ }
7048
7253
 
7049
- // events array
7050
- events: [],
7254
+ for (arr = []; i < j && i <= opts.maxYear; i++) {
7255
+ if (i >= opts.minYear) {
7256
+ arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"' : '') + '>' + (i) + '</option>');
7257
+ }
7258
+ }
7259
+ yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select aria-label="select year" class="pika-select pika-select-year" tabindex="-1">' + arr.join('') + '</select></div>';
7051
7260
 
7052
- // callback function
7053
- onSelect: null,
7054
- onOpen: null,
7055
- onClose: null,
7056
- onDraw: null,
7261
+ if (opts.showMonthAfterYear) {
7262
+ html += yearHtml + monthHtml;
7263
+ } else {
7264
+ html += monthHtml + yearHtml;
7265
+ }
7057
7266
 
7058
- // Enable keyboard input
7059
- keyboardInput: true
7060
- },
7267
+ if (isMinYear && (month === 0 || opts.minMonth >= month)) {
7268
+ prev = false;
7269
+ }
7061
7270
 
7271
+ if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
7272
+ next = false;
7273
+ }
7062
7274
 
7063
- /**
7064
- * templating functions to abstract HTML rendering
7065
- */
7066
- renderDayName = function(opts, day, abbr)
7067
- {
7068
- day += opts.firstDay;
7069
- while (day >= 7) {
7070
- day -= 7;
7071
- }
7072
- return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
7073
- },
7074
-
7075
- renderDay = function(opts)
7076
- {
7077
- var arr = [];
7078
- var ariaSelected = 'false';
7079
- if (opts.isEmpty) {
7080
- if (opts.showDaysInNextAndPreviousMonths) {
7081
- arr.push('is-outside-current-month');
7082
-
7083
- if(!opts.enableSelectionDaysInNextAndPreviousMonths) {
7084
- arr.push('is-selection-disabled');
7085
- }
7086
-
7087
- } else {
7088
- return '<td class="is-empty"></td>';
7089
- }
7090
- }
7091
- if (opts.isDisabled) {
7092
- arr.push('is-disabled');
7093
- }
7094
- if (opts.isToday) {
7095
- arr.push('is-today');
7096
- }
7097
- if (opts.isSelected) {
7098
- arr.push('is-selected');
7099
- ariaSelected = 'true';
7100
- }
7101
- if (opts.hasEvent) {
7102
- arr.push('has-event');
7103
- }
7104
- if (opts.isInRange) {
7105
- arr.push('is-inrange');
7106
- }
7107
- if (opts.isStartRange) {
7108
- arr.push('is-startrange');
7109
- }
7110
- if (opts.isEndRange) {
7111
- arr.push('is-endrange');
7112
- }
7113
- return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
7114
- '<button tabIndex="-1" class="pika-button pika-day" type="button" ' +
7115
- 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
7116
- opts.day +
7117
- '</button>' +
7118
- '</td>';
7119
- },
7120
-
7121
- renderWeek = function (d, m, y) {
7122
- // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
7123
- var onejan = new Date(y, 0, 1),
7124
- weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay()+1)/7);
7125
- return '<td class="pika-week">' + weekNum + '</td>';
7126
- },
7127
-
7128
- renderRow = function(days, isRTL, pickWholeWeek, isRowSelected)
7129
- {
7130
- return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>';
7131
- },
7275
+ if (c === 0) {
7276
+ html += '<button tabIndex="-1" class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
7277
+ }
7278
+ if (c === (instance._o.numberOfMonths - 1)) {
7279
+ html += '<button tabIndex="-1" class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
7280
+ }
7132
7281
 
7133
- renderBody = function(rows)
7134
- {
7135
- return '<tbody>' + rows.join('') + '</tbody>';
7136
- },
7282
+ return html += '</div>';
7283
+ },
7137
7284
 
7138
- renderHead = function(opts)
7139
- {
7140
- var i, arr = [];
7141
- if (opts.showWeekNumber) {
7142
- arr.push('<th></th>');
7143
- }
7144
- for (i = 0; i < 7; i++) {
7145
- arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
7146
- }
7147
- return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
7148
- },
7149
-
7150
- renderTitle = function(instance, c, year, month, refYear, randId)
7151
- {
7152
- var i, j, arr,
7153
- opts = instance._o,
7154
- isMinYear = year === opts.minYear,
7155
- isMaxYear = year === opts.maxYear,
7156
- html = '<div id="' + randId + '" class="pika-title">',
7157
- monthHtml,
7158
- yearHtml,
7159
- prev = true,
7160
- next = true;
7161
-
7162
- for (arr = [], i = 0; i < 12; i++) {
7163
- arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
7164
- (i === month ? ' selected="selected"': '') +
7165
- ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
7166
- opts.i18n.months[i] + '</option>');
7167
- }
7168
-
7169
- monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select aria-label="select month" class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>';
7170
-
7171
- if (isArray(opts.yearRange)) {
7172
- i = opts.yearRange[0];
7173
- j = opts.yearRange[1] + 1;
7174
- } else {
7175
- i = year - opts.yearRange;
7176
- j = 1 + year + opts.yearRange;
7177
- }
7178
-
7179
- for (arr = []; i < j && i <= opts.maxYear; i++) {
7180
- if (i >= opts.minYear) {
7181
- arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"': '') + '>' + (i) + '</option>');
7182
- }
7183
- }
7184
- yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select aria-label="select year" class="pika-select pika-select-year" tabindex="-1">' + arr.join('') + '</select></div>';
7185
-
7186
- if (opts.showMonthAfterYear) {
7187
- html += yearHtml + monthHtml;
7188
- } else {
7189
- html += monthHtml + yearHtml;
7190
- }
7191
-
7192
- if (isMinYear && (month === 0 || opts.minMonth >= month)) {
7193
- prev = false;
7194
- }
7195
-
7196
- if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
7197
- next = false;
7198
- }
7199
-
7200
- if (c === 0) {
7201
- html += '<button tabIndex="-1" class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
7202
- }
7203
- if (c === (instance._o.numberOfMonths - 1) ) {
7204
- html += '<button tabIndex="-1" class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
7205
- }
7206
-
7207
- return html += '</div>';
7208
- },
7209
-
7210
- renderTable = function(opts, data, randId)
7211
- {
7212
- return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
7213
- },
7285
+ renderTable = function (opts, data, randId) {
7286
+ return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
7287
+ },
7214
7288
 
7215
7289
 
7216
- /**
7217
- * Pikaday constructor
7218
- */
7219
- Pikaday = function(options)
7220
- {
7221
- var self = this,
7222
- opts = self.config(options);
7223
-
7224
- self._onMouseDown = function(e)
7225
- {
7226
- if (!self._v) {
7227
- return;
7228
- }
7229
- e = e || window.event;
7230
- var target = e.target || e.srcElement;
7231
- if (!target) {
7232
- return;
7233
- }
7234
-
7235
- if (!hasClass(target, 'is-disabled')) {
7236
- if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
7237
- self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
7238
- if (opts.bound) {
7239
- sto(function() {
7240
- self.hide();
7241
- if (opts.blurFieldOnSelect && opts.field) {
7242
- opts.field.blur();
7290
+ /**
7291
+ * Pikaday constructor
7292
+ */
7293
+ Pikaday = function (options) {
7294
+ var self = this,
7295
+ opts = self.config(options);
7296
+
7297
+ self._onMouseDown = function (e) {
7298
+ if (!self._v) {
7299
+ return;
7243
7300
  }
7244
- }, 100);
7245
- }
7246
- }
7247
- else if (hasClass(target, 'pika-prev')) {
7248
- self.prevMonth();
7249
- }
7250
- else if (hasClass(target, 'pika-next')) {
7251
- self.nextMonth();
7252
- }
7253
- }
7254
- if (!hasClass(target, 'pika-select')) {
7255
- // if this is touch event prevent mouse events emulation
7256
- if (e.preventDefault) {
7257
- e.preventDefault();
7258
- } else {
7259
- e.returnValue = false;
7260
- return false;
7261
- }
7262
- } else {
7263
- self._c = true;
7264
- }
7265
- };
7266
-
7267
- self._onChange = function(e)
7268
- {
7269
- e = e || window.event;
7270
- var target = e.target || e.srcElement;
7271
- if (!target) {
7272
- return;
7273
- }
7274
- if (hasClass(target, 'pika-select-month')) {
7275
- self.gotoMonth(target.value);
7276
- }
7277
- else if (hasClass(target, 'pika-select-year')) {
7278
- self.gotoYear(target.value);
7279
- }
7280
- };
7281
-
7282
- self._onKeyChange = function(e)
7283
- {
7284
- e = e || window.event;
7285
- // ignore if event comes from input box
7286
- if (self.isVisible() && e.target && e.target.type !== 'text') {
7287
-
7288
- switch(e.keyCode){
7289
- case 13:
7290
- case 27:
7301
+ e = e || window.event;
7302
+ var target = e.target || e.srcElement;
7303
+ if (!target) {
7304
+ return;
7305
+ }
7306
+
7307
+ if (!hasClass(target, 'is-disabled')) {
7308
+ if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
7309
+ self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
7310
+ if (opts.bound) {
7311
+ sto(function () {
7312
+ self.hide();
7313
+ if (opts.blurFieldOnSelect && opts.field) {
7314
+ opts.field.blur();
7315
+ }
7316
+ }, 100);
7317
+ }
7318
+ }
7319
+ else if (hasClass(target, 'pika-prev')) {
7320
+ self.prevMonth();
7321
+ }
7322
+ else if (hasClass(target, 'pika-next')) {
7323
+ self.nextMonth();
7324
+ }
7325
+ }
7326
+ if (!hasClass(target, 'pika-select')) {
7327
+ // if this is touch event prevent mouse events emulation
7328
+ if (e.preventDefault) {
7329
+ e.preventDefault();
7330
+ } else {
7331
+ e.returnValue = false;
7332
+ return false;
7333
+ }
7334
+ } else {
7335
+ self._c = true;
7336
+ }
7337
+ };
7338
+
7339
+ self._onChange = function (e) {
7340
+ e = e || window.event;
7341
+ var target = e.target || e.srcElement;
7342
+ if (!target) {
7343
+ return;
7344
+ }
7345
+ if (hasClass(target, 'pika-select-month')) {
7346
+ self.gotoMonth(target.value);
7347
+ }
7348
+ else if (hasClass(target, 'pika-select-year')) {
7349
+ self.gotoYear(target.value);
7350
+ }
7351
+ };
7352
+
7353
+ self._onKeyChange = function (e) {
7354
+ e = e || window.event;
7355
+ // ignore if event comes from input box
7356
+ if (self.isVisible() && e.target && e.target.type !== 'text') {
7357
+
7358
+ switch (e.keyCode) {
7359
+ case 13:
7360
+ case 27:
7361
+ if (opts.field) {
7362
+ opts.field.blur();
7363
+ }
7364
+ break;
7365
+ case 37:
7366
+ e.preventDefault();
7367
+ self.adjustDate('subtract', 1);
7368
+ break;
7369
+ case 38:
7370
+ self.adjustDate('subtract', 7);
7371
+ break;
7372
+ case 39:
7373
+ self.adjustDate('add', 1);
7374
+ break;
7375
+ case 40:
7376
+ self.adjustDate('add', 7);
7377
+ break;
7378
+ }
7379
+ }
7380
+ };
7381
+
7382
+ self._onInputChange = function (e) {
7383
+ var date;
7384
+
7385
+ if (e.firedBy === self) {
7386
+ return;
7387
+ }
7388
+ if (opts.parse) {
7389
+ date = opts.parse(opts.field.value, opts.format);
7390
+ } else if (hasMoment) {
7391
+ date = moment(opts.field.value, opts.format, opts.formatStrict);
7392
+ date = (date && date.isValid()) ? date.toDate() : null;
7393
+ }
7394
+ else {
7395
+ date = new Date(Date.parse(opts.field.value));
7396
+ }
7397
+ // if (isDate(date)) {
7398
+ // self.setDate(date);
7399
+ // }
7400
+ // if (!self._v) {
7401
+ // self.show();
7402
+ // }
7403
+ };
7404
+
7405
+ self._onInputFocus = function () {
7406
+ self.show();
7407
+ };
7408
+
7409
+ self._onInputClick = function () {
7410
+ self.show();
7411
+ };
7412
+
7413
+ self._onInputBlur = function () {
7414
+ // IE allows pika div to gain focus; catch blur the input field
7415
+ var pEl = document.activeElement;
7416
+ do {
7417
+ if (hasClass(pEl, 'pika-single')) {
7418
+ return;
7419
+ }
7420
+ }
7421
+ while ((pEl = pEl.parentNode));
7422
+
7423
+ if (!self._c) {
7424
+ self._b = sto(function () {
7425
+ self.hide();
7426
+ }, 50);
7427
+ }
7428
+ self._c = false;
7429
+ };
7430
+
7431
+ self._onClick = function (e) {
7432
+ e = e || window.event;
7433
+ var target = e.target || e.srcElement,
7434
+ pEl = target;
7435
+ if (!target) {
7436
+ return;
7437
+ }
7438
+ if (!hasEventListeners && hasClass(target, 'pika-select')) {
7439
+ if (!target.onchange) {
7440
+ target.setAttribute('onchange', 'return;');
7441
+ addEvent(target, 'change', self._onChange);
7442
+ }
7443
+ }
7444
+ do {
7445
+ if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) {
7446
+ return;
7447
+ }
7448
+ }
7449
+ while ((pEl = pEl.parentNode));
7450
+ if (self._v && target !== opts.trigger && pEl !== opts.trigger) {
7451
+ self.hide();
7452
+ }
7453
+ };
7454
+
7455
+ self.el = document.createElement('div');
7456
+ self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : '');
7457
+
7458
+ addEvent(self.el, 'mousedown', self._onMouseDown, true);
7459
+ addEvent(self.el, 'touchend', self._onMouseDown, true);
7460
+ addEvent(self.el, 'change', self._onChange);
7461
+
7462
+ if (opts.keyboardInput) {
7463
+ addEvent(document, 'keydown', self._onKeyChange);
7464
+ }
7465
+
7291
7466
  if (opts.field) {
7292
- opts.field.blur();
7467
+ if (opts.container) {
7468
+ opts.container.appendChild(self.el);
7469
+ } else if (opts.bound) {
7470
+ document.body.appendChild(self.el);
7471
+ } else {
7472
+ opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
7473
+ }
7474
+ addEvent(opts.field, 'change', self._onInputChange);
7475
+
7476
+ if (!opts.defaultDate) {
7477
+ if (hasMoment && opts.field.value) {
7478
+ opts.defaultDate = moment(opts.field.value, opts.format).toDate();
7479
+ } else {
7480
+ opts.defaultDate = new Date(Date.parse(opts.field.value));
7481
+ }
7482
+ opts.setDefaultDate = true;
7483
+ }
7484
+ }
7485
+
7486
+ var defDate = opts.defaultDate;
7487
+
7488
+ if (isDate(defDate)) {
7489
+ if (opts.setDefaultDate) {
7490
+ self.setDate(defDate, true);
7491
+ } else {
7492
+ self.gotoDate(defDate);
7493
+ }
7494
+ } else {
7495
+ self.gotoDate(new Date());
7496
+ }
7497
+
7498
+ if (opts.bound) {
7499
+ this.hide();
7500
+ self.el.className += ' is-bound';
7501
+ addEvent(opts.trigger, 'click', self._onInputClick);
7502
+ addEvent(opts.trigger, 'focus', self._onInputFocus);
7503
+ addEvent(opts.trigger, 'blur', self._onInputBlur);
7504
+ } else {
7505
+ this.show();
7293
7506
  }
7294
- break;
7295
- case 37:
7296
- e.preventDefault();
7297
- self.adjustDate('subtract', 1);
7298
- break;
7299
- case 38:
7300
- self.adjustDate('subtract', 7);
7301
- break;
7302
- case 39:
7303
- self.adjustDate('add', 1);
7304
- break;
7305
- case 40:
7306
- self.adjustDate('add', 7);
7307
- break;
7308
- }
7309
- }
7310
- };
7311
-
7312
- self._onInputChange = function(e)
7313
- {
7314
- var date;
7315
-
7316
- if (e.firedBy === self) {
7317
- return;
7318
- }
7319
- if (opts.parse) {
7320
- date = opts.parse(opts.field.value, opts.format);
7321
- } else if (hasMoment) {
7322
- date = moment(opts.field.value, opts.format, opts.formatStrict);
7323
- date = (date && date.isValid()) ? date.toDate() : null;
7324
- }
7325
- else {
7326
- date = new Date(Date.parse(opts.field.value));
7327
- }
7328
- // if (isDate(date)) {
7329
- // self.setDate(date);
7330
- // }
7331
- // if (!self._v) {
7332
- // self.show();
7333
- // }
7334
- };
7335
-
7336
- self._onInputFocus = function()
7337
- {
7338
- self.show();
7339
- };
7340
-
7341
- self._onInputClick = function()
7342
- {
7343
- self.show();
7344
- };
7345
-
7346
- self._onInputBlur = function()
7347
- {
7348
- // IE allows pika div to gain focus; catch blur the input field
7349
- var pEl = document.activeElement;
7350
- do {
7351
- if (hasClass(pEl, 'pika-single')) {
7352
- return;
7353
- }
7354
- }
7355
- while ((pEl = pEl.parentNode));
7356
-
7357
- if (!self._c) {
7358
- self._b = sto(function() {
7359
- self.hide();
7360
- }, 50);
7361
- }
7362
- self._c = false;
7363
- };
7364
-
7365
- self._onClick = function(e)
7366
- {
7367
- e = e || window.event;
7368
- var target = e.target || e.srcElement,
7369
- pEl = target;
7370
- if (!target) {
7371
- return;
7372
- }
7373
- if (!hasEventListeners && hasClass(target, 'pika-select')) {
7374
- if (!target.onchange) {
7375
- target.setAttribute('onchange', 'return;');
7376
- addEvent(target, 'change', self._onChange);
7377
- }
7378
- }
7379
- do {
7380
- if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) {
7381
- return;
7382
- }
7383
- }
7384
- while ((pEl = pEl.parentNode));
7385
- if (self._v && target !== opts.trigger && pEl !== opts.trigger) {
7386
- self.hide();
7387
- }
7388
- };
7389
-
7390
- self.el = document.createElement('div');
7391
- self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : '');
7392
-
7393
- addEvent(self.el, 'mousedown', self._onMouseDown, true);
7394
- addEvent(self.el, 'touchend', self._onMouseDown, true);
7395
- addEvent(self.el, 'change', self._onChange);
7396
-
7397
- if (opts.keyboardInput) {
7398
- addEvent(document, 'keydown', self._onKeyChange);
7399
- }
7400
-
7401
- if (opts.field) {
7402
- if (opts.container) {
7403
- opts.container.appendChild(self.el);
7404
- } else if (opts.bound) {
7405
- document.body.appendChild(self.el);
7406
- } else {
7407
- opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
7408
- }
7409
- addEvent(opts.field, 'change', self._onInputChange);
7410
-
7411
- if (!opts.defaultDate) {
7412
- if (hasMoment && opts.field.value) {
7413
- opts.defaultDate = moment(opts.field.value, opts.format).toDate();
7414
- } else {
7415
- opts.defaultDate = new Date(Date.parse(opts.field.value));
7416
- }
7417
- opts.setDefaultDate = true;
7418
- }
7419
- }
7420
-
7421
- var defDate = opts.defaultDate;
7422
-
7423
- if (isDate(defDate)) {
7424
- if (opts.setDefaultDate) {
7425
- self.setDate(defDate, true);
7426
- } else {
7427
- self.gotoDate(defDate);
7428
- }
7429
- } else {
7430
- self.gotoDate(new Date());
7431
- }
7432
-
7433
- if (opts.bound) {
7434
- this.hide();
7435
- self.el.className += ' is-bound';
7436
- addEvent(opts.trigger, 'click', self._onInputClick);
7437
- addEvent(opts.trigger, 'focus', self._onInputFocus);
7438
- addEvent(opts.trigger, 'blur', self._onInputBlur);
7439
- } else {
7440
- this.show();
7441
- }
7442
- };
7443
-
7444
-
7445
- /**
7446
- * public Pikaday API
7447
- */
7448
- Pikaday.prototype = {
7449
-
7450
-
7451
- /**
7452
- * configure functionality
7453
- */
7454
- config: function(options)
7455
- {
7456
- if (!this._o) {
7457
- this._o = extend({}, defaults, true);
7458
- }
7459
-
7460
- var opts = extend(this._o, options, true);
7461
-
7462
- opts.isRTL = !!opts.isRTL;
7463
-
7464
- opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
7465
-
7466
- opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null;
7467
-
7468
- opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
7469
-
7470
- opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
7471
-
7472
- opts.disableWeekends = !!opts.disableWeekends;
7473
-
7474
- opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null;
7475
-
7476
- var nom = parseInt(opts.numberOfMonths, 10) || 1;
7477
- opts.numberOfMonths = nom > 4 ? 4 : nom;
7478
-
7479
- if (!isDate(opts.minDate)) {
7480
- opts.minDate = false;
7481
- }
7482
- if (!isDate(opts.maxDate)) {
7483
- opts.maxDate = false;
7484
- }
7485
- if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
7486
- opts.maxDate = opts.minDate = false;
7487
- }
7488
- if (opts.minDate) {
7489
- this.setMinDate(opts.minDate);
7490
- }
7491
- if (opts.maxDate) {
7492
- this.setMaxDate(opts.maxDate);
7493
- }
7494
-
7495
- if (isArray(opts.yearRange)) {
7496
- var fallback = new Date().getFullYear() - 10;
7497
- opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
7498
- opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
7499
- } else {
7500
- opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
7501
- if (opts.yearRange > 100) {
7502
- opts.yearRange = 100;
7503
- }
7504
- }
7505
-
7506
- return opts;
7507
- },
7508
-
7509
- /**
7510
- * return a formatted string of the current selection (using Moment.js if available)
7511
- */
7512
- toString: function(format)
7513
- {
7514
- format = format || this._o.format;
7515
- if (!isDate(this._d)) {
7516
- return '';
7517
- }
7518
- if (this._o.toString) {
7519
- return this._o.toString(this._d, format);
7520
- }
7521
- if (hasMoment) {
7522
- return moment(this._d).format(format);
7523
- }
7524
- return this._d.toDateString();
7525
- },
7526
-
7527
- /**
7528
- * return a Moment.js object of the current selection (if available)
7529
- */
7530
- getMoment: function()
7531
- {
7532
- return hasMoment ? moment(this._d) : null;
7533
- },
7534
-
7535
- /**
7536
- * set the current selection from a Moment.js object (if available)
7537
- */
7538
- setMoment: function(date, preventOnSelect)
7539
- {
7540
- if (hasMoment && moment.isMoment(date)) {
7541
- this.setDate(date.toDate(), preventOnSelect);
7542
- }
7543
- },
7544
-
7545
- /**
7546
- * return a Date object of the current selection
7547
- */
7548
- getDate: function()
7549
- {
7550
- return isDate(this._d) ? new Date(this._d.getTime()) : null;
7551
- },
7552
-
7553
- /**
7554
- * set the current selection
7555
- */
7556
- setDate: function(date, preventOnSelect)
7557
- {
7558
- if (!date) {
7559
- this._d = null;
7560
-
7561
- if (this._o.field) {
7562
- this._o.field.value = '';
7563
- fireEvent(this._o.field, 'change', { firedBy: this });
7564
- }
7565
-
7566
- return this.draw();
7567
- }
7568
- if (typeof date === 'string') {
7569
- date = new Date(Date.parse(date));
7570
- }
7571
- if (!isDate(date)) {
7572
- return;
7573
- }
7574
-
7575
- var min = this._o.minDate,
7576
- max = this._o.maxDate;
7577
-
7578
- if (isDate(min) && date < min) {
7579
- date = min;
7580
- } else if (isDate(max) && date > max) {
7581
- date = max;
7582
- }
7583
-
7584
- this._d = new Date(date.getTime());
7585
- setToStartOfDay(this._d);
7586
- this.gotoDate(this._d);
7587
-
7588
- if (this._o.field) {
7589
- this._o.field.value = this.toString();
7590
- fireEvent(this._o.field, 'change', { firedBy: this });
7591
- }
7592
- if (!preventOnSelect && typeof this._o.onSelect === 'function') {
7593
- this._o.onSelect.call(this, this.getDate());
7594
- }
7595
- },
7596
-
7597
- /**
7598
- * change view to a specific date
7599
- */
7600
- gotoDate: function(date)
7601
- {
7602
- var newCalendar = true;
7603
-
7604
- if (!isDate(date)) {
7605
- return;
7606
- }
7607
-
7608
- if (this.calendars) {
7609
- var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
7610
- lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1),
7611
- visibleDate = date.getTime();
7612
- // get the end of the month
7613
- lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1);
7614
- lastVisibleDate.setDate(lastVisibleDate.getDate()-1);
7615
- newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
7616
- }
7617
-
7618
- if (newCalendar) {
7619
- this.calendars = [{
7620
- month: date.getMonth(),
7621
- year: date.getFullYear()
7622
- }];
7623
- if (this._o.mainCalendar === 'right') {
7624
- this.calendars[0].month += 1 - this._o.numberOfMonths;
7625
- }
7626
- }
7627
-
7628
- this.adjustCalendars();
7629
- },
7630
-
7631
- adjustDate: function(sign, days) {
7632
-
7633
- var day = this.getDate() || new Date();
7634
- var difference = parseInt(days)*24*60*60*1000;
7635
-
7636
- var newDay;
7637
-
7638
- if (sign === 'add') {
7639
- newDay = new Date(day.valueOf() + difference);
7640
- } else if (sign === 'subtract') {
7641
- newDay = new Date(day.valueOf() - difference);
7642
- }
7643
-
7644
- this.setDate(newDay);
7645
- },
7646
-
7647
- adjustCalendars: function() {
7648
- this.calendars[0] = adjustCalendar(this.calendars[0]);
7649
- for (var c = 1; c < this._o.numberOfMonths; c++) {
7650
- this.calendars[c] = adjustCalendar({
7651
- month: this.calendars[0].month + c,
7652
- year: this.calendars[0].year
7653
- });
7654
- }
7655
- this.draw();
7656
- },
7657
-
7658
- gotoToday: function()
7659
- {
7660
- this.gotoDate(new Date());
7661
- },
7662
-
7663
- /**
7664
- * change view to a specific month (zero-index, e.g. 0: January)
7665
- */
7666
- gotoMonth: function(month)
7667
- {
7668
- if (!isNaN(month)) {
7669
- this.calendars[0].month = parseInt(month, 10);
7670
- this.adjustCalendars();
7671
- }
7672
- },
7673
-
7674
- nextMonth: function()
7675
- {
7676
- this.calendars[0].month++;
7677
- this.adjustCalendars();
7678
- },
7679
-
7680
- prevMonth: function()
7681
- {
7682
- this.calendars[0].month--;
7683
- this.adjustCalendars();
7684
- },
7685
-
7686
- /**
7687
- * change view to a specific full year (e.g. "2012")
7688
- */
7689
- gotoYear: function(year)
7690
- {
7691
- if (!isNaN(year)) {
7692
- this.calendars[0].year = parseInt(year, 10);
7693
- this.adjustCalendars();
7694
- }
7695
- },
7696
-
7697
- /**
7698
- * change the minDate
7699
- */
7700
- setMinDate: function(value)
7701
- {
7702
- if(value instanceof Date) {
7703
- setToStartOfDay(value);
7704
- this._o.minDate = value;
7705
- this._o.minYear = value.getFullYear();
7706
- this._o.minMonth = value.getMonth();
7707
- } else {
7708
- this._o.minDate = defaults.minDate;
7709
- this._o.minYear = defaults.minYear;
7710
- this._o.minMonth = defaults.minMonth;
7711
- this._o.startRange = defaults.startRange;
7712
- }
7713
-
7714
- this.draw();
7715
- },
7716
-
7717
- /**
7718
- * change the maxDate
7719
- */
7720
- setMaxDate: function(value)
7721
- {
7722
- if(value instanceof Date) {
7723
- setToStartOfDay(value);
7724
- this._o.maxDate = value;
7725
- this._o.maxYear = value.getFullYear();
7726
- this._o.maxMonth = value.getMonth();
7727
- } else {
7728
- this._o.maxDate = defaults.maxDate;
7729
- this._o.maxYear = defaults.maxYear;
7730
- this._o.maxMonth = defaults.maxMonth;
7731
- this._o.endRange = defaults.endRange;
7732
- }
7733
-
7734
- this.draw();
7735
- },
7736
-
7737
- setStartRange: function(value)
7738
- {
7739
- this._o.startRange = value;
7740
- },
7741
-
7742
- setEndRange: function(value)
7743
- {
7744
- this._o.endRange = value;
7745
- },
7746
-
7747
- /**
7748
- * refresh the HTML
7749
- */
7750
- draw: function(force)
7751
- {
7752
- if (!this._v && !force) {
7753
- return;
7754
- }
7755
- var opts = this._o,
7756
- minYear = opts.minYear,
7757
- maxYear = opts.maxYear,
7758
- minMonth = opts.minMonth,
7759
- maxMonth = opts.maxMonth,
7760
- html = '',
7761
- randId;
7762
-
7763
- if (this._y <= minYear) {
7764
- this._y = minYear;
7765
- if (!isNaN(minMonth) && this._m < minMonth) {
7766
- this._m = minMonth;
7767
- }
7768
- }
7769
- if (this._y >= maxYear) {
7770
- this._y = maxYear;
7771
- if (!isNaN(maxMonth) && this._m > maxMonth) {
7772
- this._m = maxMonth;
7773
- }
7774
- }
7775
-
7776
- for (var c = 0; c < opts.numberOfMonths; c++) {
7777
- randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
7778
- html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId) + '</div>';
7779
- }
7780
-
7781
- this.el.innerHTML = html;
7782
-
7783
- if (opts.bound) {
7784
- if(opts.field.type !== 'hidden') {
7785
- sto(function() {
7786
- opts.trigger.focus();
7787
- }, 1);
7788
- }
7789
- }
7790
-
7791
- if (typeof this._o.onDraw === 'function') {
7792
- this._o.onDraw(this);
7793
- }
7794
-
7795
- if (opts.bound) {
7796
- // let the screen reader user know to use arrow keys
7797
- opts.field.setAttribute('aria-label', 'Use the arrow keys to pick a date');
7798
- }
7799
- },
7800
-
7801
- adjustPosition: function()
7802
- {
7803
- var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect;
7804
-
7805
- if (this._o.container) return;
7806
-
7807
- this.el.style.position = 'absolute';
7808
-
7809
- field = this._o.trigger;
7810
- pEl = field;
7811
- width = this.el.offsetWidth;
7812
- height = this.el.offsetHeight;
7813
- viewportWidth = window.innerWidth || document.documentElement.clientWidth;
7814
- viewportHeight = window.innerHeight || document.documentElement.clientHeight;
7815
- scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
7816
-
7817
- if (typeof field.getBoundingClientRect === 'function') {
7818
- clientRect = field.getBoundingClientRect();
7819
- left = clientRect.left + window.pageXOffset;
7820
- top = clientRect.bottom + window.pageYOffset;
7821
- } else {
7822
- left = pEl.offsetLeft;
7823
- top = pEl.offsetTop + pEl.offsetHeight;
7824
- while((pEl = pEl.offsetParent)) {
7825
- left += pEl.offsetLeft;
7826
- top += pEl.offsetTop;
7827
- }
7828
- }
7829
-
7830
- // default position is bottom & left
7831
- if ((this._o.reposition && left + width > viewportWidth) ||
7832
- (
7833
- this._o.position.indexOf('right') > -1 &&
7834
- left - width + field.offsetWidth > 0
7835
- )
7836
- ) {
7837
- left = left - width + field.offsetWidth;
7838
- }
7839
- if ((this._o.reposition && top + height > viewportHeight + scrollTop) ||
7840
- (
7841
- this._o.position.indexOf('top') > -1 &&
7842
- top - height - field.offsetHeight > 0
7843
- )
7844
- ) {
7845
- top = top - height - field.offsetHeight;
7846
- }
7847
-
7848
- this.el.style.left = left + 'px';
7849
- this.el.style.top = top + 'px';
7850
- },
7851
-
7852
- /**
7853
- * render HTML for a particular month
7854
- */
7855
- render: function(year, month, randId)
7856
- {
7857
- var opts = this._o,
7858
- now = new Date(),
7859
- days = getDaysInMonth(year, month),
7860
- before = new Date(year, month, 1).getDay(),
7861
- data = [],
7862
- row = [];
7863
- setToStartOfDay(now);
7864
- if (opts.firstDay > 0) {
7865
- before -= opts.firstDay;
7866
- if (before < 0) {
7867
- before += 7;
7868
- }
7869
- }
7870
- var previousMonth = month === 0 ? 11 : month - 1,
7871
- nextMonth = month === 11 ? 0 : month + 1,
7872
- yearOfPreviousMonth = month === 0 ? year - 1 : year,
7873
- yearOfNextMonth = month === 11 ? year + 1 : year,
7874
- daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth);
7875
- var cells = days + before,
7876
- after = cells;
7877
- while(after > 7) {
7878
- after -= 7;
7879
- }
7880
- cells += 7 - after;
7881
- var isWeekSelected = false;
7882
- for (var i = 0, r = 0; i < cells; i++)
7883
- {
7884
- var day = new Date(year, month, 1 + (i - before)),
7885
- isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
7886
- isToday = compareDates(day, now),
7887
- hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
7888
- isEmpty = i < before || i >= (days + before),
7889
- dayNumber = 1 + (i - before),
7890
- monthNumber = month,
7891
- yearNumber = year,
7892
- isStartRange = opts.startRange && compareDates(opts.startRange, day),
7893
- isEndRange = opts.endRange && compareDates(opts.endRange, day),
7894
- isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
7895
- isDisabled = (opts.minDate && day < opts.minDate) ||
7896
- (opts.maxDate && day > opts.maxDate) ||
7897
- (opts.disableWeekends && isWeekend(day)) ||
7898
- (opts.disableDayFn && opts.disableDayFn(day));
7899
-
7900
- if (isEmpty) {
7901
- if (i < before) {
7902
- dayNumber = daysInPreviousMonth + dayNumber;
7903
- monthNumber = previousMonth;
7904
- yearNumber = yearOfPreviousMonth;
7905
- } else {
7906
- dayNumber = dayNumber - days;
7907
- monthNumber = nextMonth;
7908
- yearNumber = yearOfNextMonth;
7909
- }
7910
- }
7911
-
7912
- var dayConfig = {
7913
- day: dayNumber,
7914
- month: monthNumber,
7915
- year: yearNumber,
7916
- hasEvent: hasEvent,
7917
- isSelected: isSelected,
7918
- isToday: isToday,
7919
- isDisabled: isDisabled,
7920
- isEmpty: isEmpty,
7921
- isStartRange: isStartRange,
7922
- isEndRange: isEndRange,
7923
- isInRange: isInRange,
7924
- showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths,
7925
- enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths
7926
7507
  };
7927
7508
 
7928
- if (opts.pickWholeWeek && isSelected) {
7929
- isWeekSelected = true;
7930
- }
7931
7509
 
7932
- row.push(renderDay(dayConfig));
7510
+ /**
7511
+ * public Pikaday API
7512
+ */
7513
+ Pikaday.prototype = {
7933
7514
 
7934
- if (++r === 7) {
7935
- if (opts.showWeekNumber) {
7936
- row.unshift(renderWeek(i - before, month, year));
7515
+
7516
+ /**
7517
+ * configure functionality
7518
+ */
7519
+ config: function (options) {
7520
+ if (!this._o) {
7521
+ this._o = extend({}, defaults, true);
7522
+ }
7523
+
7524
+ var opts = extend(this._o, options, true);
7525
+
7526
+ opts.isRTL = !!opts.isRTL;
7527
+
7528
+ opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
7529
+
7530
+ opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null;
7531
+
7532
+ opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
7533
+
7534
+ opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
7535
+
7536
+ opts.disableWeekends = !!opts.disableWeekends;
7537
+
7538
+ opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null;
7539
+
7540
+ var nom = parseInt(opts.numberOfMonths, 10) || 1;
7541
+ opts.numberOfMonths = nom > 4 ? 4 : nom;
7542
+
7543
+ if (!isDate(opts.minDate)) {
7544
+ opts.minDate = false;
7545
+ }
7546
+ if (!isDate(opts.maxDate)) {
7547
+ opts.maxDate = false;
7548
+ }
7549
+ if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
7550
+ opts.maxDate = opts.minDate = false;
7551
+ }
7552
+ if (opts.minDate) {
7553
+ this.setMinDate(opts.minDate);
7554
+ }
7555
+ if (opts.maxDate) {
7556
+ this.setMaxDate(opts.maxDate);
7557
+ }
7558
+
7559
+ if (isArray(opts.yearRange)) {
7560
+ var fallback = new Date().getFullYear() - 10;
7561
+ opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
7562
+ opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
7563
+ } else {
7564
+ opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
7565
+ if (opts.yearRange > 100) {
7566
+ opts.yearRange = 100;
7567
+ }
7568
+ }
7569
+
7570
+ return opts;
7571
+ },
7572
+
7573
+ /**
7574
+ * return a formatted string of the current selection (using Moment.js if available)
7575
+ */
7576
+ toString: function (format) {
7577
+ format = format || this._o.format;
7578
+ if (!isDate(this._d)) {
7579
+ return '';
7580
+ }
7581
+ if (this._o.toString) {
7582
+ return this._o.toString(this._d, format);
7583
+ }
7584
+ if (hasMoment) {
7585
+ return moment(this._d).format(format);
7586
+ }
7587
+ return this._d.toDateString();
7588
+ },
7589
+
7590
+ /**
7591
+ * return a Moment.js object of the current selection (if available)
7592
+ */
7593
+ getMoment: function () {
7594
+ return hasMoment ? moment(this._d) : null;
7595
+ },
7596
+
7597
+ /**
7598
+ * set the current selection from a Moment.js object (if available)
7599
+ */
7600
+ setMoment: function (date, preventOnSelect) {
7601
+ if (hasMoment && moment.isMoment(date)) {
7602
+ this.setDate(date.toDate(), preventOnSelect);
7603
+ }
7604
+ },
7605
+
7606
+ /**
7607
+ * return a Date object of the current selection
7608
+ */
7609
+ getDate: function () {
7610
+ return isDate(this._d) ? new Date(this._d.getTime()) : null;
7611
+ },
7612
+
7613
+ /**
7614
+ * set the current selection
7615
+ */
7616
+ setDate: function (date, preventOnSelect) {
7617
+ if (!date) {
7618
+ this._d = null;
7619
+
7620
+ if (this._o.field) {
7621
+ this._o.field.value = '';
7622
+ fireEvent(this._o.field, 'change', { firedBy: this });
7623
+ }
7624
+
7625
+ return this.draw();
7626
+ }
7627
+ if (typeof date === 'string') {
7628
+ date = new Date(Date.parse(date));
7629
+ }
7630
+ if (!isDate(date)) {
7631
+ return;
7632
+ }
7633
+
7634
+ var min = this._o.minDate,
7635
+ max = this._o.maxDate;
7636
+
7637
+ if (isDate(min) && date < min) {
7638
+ date = min;
7639
+ } else if (isDate(max) && date > max) {
7640
+ date = max;
7641
+ }
7642
+
7643
+ this._d = new Date(date.getTime());
7644
+ setToStartOfDay(this._d);
7645
+ this.gotoDate(this._d);
7646
+
7647
+ if (this._o.field) {
7648
+ this._o.field.value = this.toString();
7649
+ fireEvent(this._o.field, 'change', { firedBy: this });
7650
+ }
7651
+ if (!preventOnSelect && typeof this._o.onSelect === 'function') {
7652
+ this._o.onSelect.call(this, this.getDate());
7653
+ }
7654
+ },
7655
+
7656
+ /**
7657
+ * change view to a specific date
7658
+ */
7659
+ gotoDate: function (date) {
7660
+ var newCalendar = true;
7661
+
7662
+ if (!isDate(date)) {
7663
+ return;
7664
+ }
7665
+
7666
+ if (this.calendars) {
7667
+ var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
7668
+ lastVisibleDate = new Date(this.calendars[this.calendars.length - 1].year, this.calendars[this.calendars.length - 1].month, 1),
7669
+ visibleDate = date.getTime();
7670
+ // get the end of the month
7671
+ lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1);
7672
+ lastVisibleDate.setDate(lastVisibleDate.getDate() - 1);
7673
+ newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
7674
+ }
7675
+
7676
+ if (newCalendar) {
7677
+ this.calendars = [{
7678
+ month: date.getMonth(),
7679
+ year: date.getFullYear()
7680
+ }];
7681
+ if (this._o.mainCalendar === 'right') {
7682
+ this.calendars[0].month += 1 - this._o.numberOfMonths;
7683
+ }
7684
+ }
7685
+
7686
+ this.adjustCalendars();
7687
+ },
7688
+
7689
+ adjustDate: function (sign, days) {
7690
+
7691
+ var day = this.getDate() || new Date();
7692
+ var difference = parseInt(days) * 24 * 60 * 60 * 1000;
7693
+
7694
+ var newDay;
7695
+
7696
+ if (sign === 'add') {
7697
+ newDay = new Date(day.valueOf() + difference);
7698
+ } else if (sign === 'subtract') {
7699
+ newDay = new Date(day.valueOf() - difference);
7700
+ }
7701
+
7702
+ this.setDate(newDay);
7703
+ },
7704
+
7705
+ adjustCalendars: function () {
7706
+ this.calendars[0] = adjustCalendar(this.calendars[0]);
7707
+ for (var c = 1; c < this._o.numberOfMonths; c++) {
7708
+ this.calendars[c] = adjustCalendar({
7709
+ month: this.calendars[0].month + c,
7710
+ year: this.calendars[0].year
7711
+ });
7712
+ }
7713
+ this.draw();
7714
+ },
7715
+
7716
+ gotoToday: function () {
7717
+ this.gotoDate(new Date());
7718
+ },
7719
+
7720
+ /**
7721
+ * change view to a specific month (zero-index, e.g. 0: January)
7722
+ */
7723
+ gotoMonth: function (month) {
7724
+ if (!isNaN(month)) {
7725
+ this.calendars[0].month = parseInt(month, 10);
7726
+ this.adjustCalendars();
7727
+ }
7728
+ },
7729
+
7730
+ nextMonth: function () {
7731
+ this.calendars[0].month++;
7732
+ this.adjustCalendars();
7733
+ },
7734
+
7735
+ prevMonth: function () {
7736
+ this.calendars[0].month--;
7737
+ this.adjustCalendars();
7738
+ },
7739
+
7740
+ /**
7741
+ * change view to a specific full year (e.g. "2012")
7742
+ */
7743
+ gotoYear: function (year) {
7744
+ if (!isNaN(year)) {
7745
+ this.calendars[0].year = parseInt(year, 10);
7746
+ this.adjustCalendars();
7747
+ }
7748
+ },
7749
+
7750
+ /**
7751
+ * change the minDate
7752
+ */
7753
+ setMinDate: function (value) {
7754
+ if (value instanceof Date) {
7755
+ setToStartOfDay(value);
7756
+ this._o.minDate = value;
7757
+ this._o.minYear = value.getFullYear();
7758
+ this._o.minMonth = value.getMonth();
7759
+ } else {
7760
+ this._o.minDate = defaults.minDate;
7761
+ this._o.minYear = defaults.minYear;
7762
+ this._o.minMonth = defaults.minMonth;
7763
+ this._o.startRange = defaults.startRange;
7764
+ }
7765
+
7766
+ this.draw();
7767
+ },
7768
+
7769
+ /**
7770
+ * change the maxDate
7771
+ */
7772
+ setMaxDate: function (value) {
7773
+ if (value instanceof Date) {
7774
+ setToStartOfDay(value);
7775
+ this._o.maxDate = value;
7776
+ this._o.maxYear = value.getFullYear();
7777
+ this._o.maxMonth = value.getMonth();
7778
+ } else {
7779
+ this._o.maxDate = defaults.maxDate;
7780
+ this._o.maxYear = defaults.maxYear;
7781
+ this._o.maxMonth = defaults.maxMonth;
7782
+ this._o.endRange = defaults.endRange;
7783
+ }
7784
+
7785
+ this.draw();
7786
+ },
7787
+
7788
+ setStartRange: function (value) {
7789
+ this._o.startRange = value;
7790
+ },
7791
+
7792
+ setEndRange: function (value) {
7793
+ this._o.endRange = value;
7794
+ },
7795
+
7796
+ /**
7797
+ * refresh the HTML
7798
+ */
7799
+ draw: function (force) {
7800
+ if (!this._v && !force) {
7801
+ return;
7802
+ }
7803
+ var opts = this._o,
7804
+ minYear = opts.minYear,
7805
+ maxYear = opts.maxYear,
7806
+ minMonth = opts.minMonth,
7807
+ maxMonth = opts.maxMonth,
7808
+ html = '',
7809
+ randId;
7810
+
7811
+ if (this._y <= minYear) {
7812
+ this._y = minYear;
7813
+ if (!isNaN(minMonth) && this._m < minMonth) {
7814
+ this._m = minMonth;
7815
+ }
7816
+ }
7817
+ if (this._y >= maxYear) {
7818
+ this._y = maxYear;
7819
+ if (!isNaN(maxMonth) && this._m > maxMonth) {
7820
+ this._m = maxMonth;
7821
+ }
7822
+ }
7823
+
7824
+ for (var c = 0; c < opts.numberOfMonths; c++) {
7825
+ randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
7826
+ html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId) + '</div>';
7827
+ }
7828
+
7829
+ this.el.innerHTML = html;
7830
+
7831
+ if (opts.bound) {
7832
+ if (opts.field.type !== 'hidden') {
7833
+ sto(function () {
7834
+ opts.trigger.focus();
7835
+ }, 1);
7836
+ }
7837
+ }
7838
+
7839
+ if (typeof this._o.onDraw === 'function') {
7840
+ this._o.onDraw(this);
7841
+ }
7842
+
7843
+ if (opts.bound) {
7844
+ // let the screen reader user know to use arrow keys
7845
+ opts.field.setAttribute('aria-label', 'Use the arrow keys to pick a date');
7846
+ }
7847
+ },
7848
+
7849
+ adjustPosition: function () {
7850
+ var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect;
7851
+
7852
+ if (this._o.container) return;
7853
+
7854
+ this.el.style.position = 'absolute';
7855
+
7856
+ field = this._o.trigger;
7857
+ pEl = field;
7858
+ width = this.el.offsetWidth;
7859
+ height = this.el.offsetHeight;
7860
+ viewportWidth = window.innerWidth || document.documentElement.clientWidth;
7861
+ viewportHeight = window.innerHeight || document.documentElement.clientHeight;
7862
+ scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
7863
+
7864
+ if (typeof field.getBoundingClientRect === 'function') {
7865
+ clientRect = field.getBoundingClientRect();
7866
+ left = clientRect.left + window.pageXOffset;
7867
+ top = clientRect.bottom + window.pageYOffset;
7868
+ } else {
7869
+ left = pEl.offsetLeft;
7870
+ top = pEl.offsetTop + pEl.offsetHeight;
7871
+ while ((pEl = pEl.offsetParent)) {
7872
+ left += pEl.offsetLeft;
7873
+ top += pEl.offsetTop;
7874
+ }
7875
+ }
7876
+
7877
+ // default position is bottom & left
7878
+ if ((this._o.reposition && left + width > viewportWidth) ||
7879
+ (
7880
+ this._o.position.indexOf('right') > -1 &&
7881
+ left - width + field.offsetWidth > 0
7882
+ )
7883
+ ) {
7884
+ left = left - width + field.offsetWidth;
7885
+ }
7886
+ if ((this._o.reposition && top + height > viewportHeight + scrollTop) ||
7887
+ (
7888
+ this._o.position.indexOf('top') > -1 &&
7889
+ top - height - field.offsetHeight > 0
7890
+ )
7891
+ ) {
7892
+ top = top - height - field.offsetHeight;
7893
+ }
7894
+
7895
+ this.el.style.left = left + 'px';
7896
+ this.el.style.top = top + 'px';
7897
+ },
7898
+
7899
+ /**
7900
+ * render HTML for a particular month
7901
+ */
7902
+ render: function (year, month, randId) {
7903
+ var opts = this._o,
7904
+ now = new Date(),
7905
+ days = getDaysInMonth(year, month),
7906
+ before = new Date(year, month, 1).getDay(),
7907
+ data = [],
7908
+ row = [];
7909
+ setToStartOfDay(now);
7910
+ if (opts.firstDay > 0) {
7911
+ before -= opts.firstDay;
7912
+ if (before < 0) {
7913
+ before += 7;
7914
+ }
7915
+ }
7916
+ var previousMonth = month === 0 ? 11 : month - 1,
7917
+ nextMonth = month === 11 ? 0 : month + 1,
7918
+ yearOfPreviousMonth = month === 0 ? year - 1 : year,
7919
+ yearOfNextMonth = month === 11 ? year + 1 : year,
7920
+ daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth);
7921
+ var cells = days + before,
7922
+ after = cells;
7923
+ while (after > 7) {
7924
+ after -= 7;
7925
+ }
7926
+ cells += 7 - after;
7927
+ var isWeekSelected = false;
7928
+ for (var i = 0, r = 0; i < cells; i++) {
7929
+ var day = new Date(year, month, 1 + (i - before)),
7930
+ isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
7931
+ isToday = compareDates(day, now),
7932
+ hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
7933
+ isEmpty = i < before || i >= (days + before),
7934
+ dayNumber = 1 + (i - before),
7935
+ monthNumber = month,
7936
+ yearNumber = year,
7937
+ isStartRange = opts.startRange && compareDates(opts.startRange, day),
7938
+ isEndRange = opts.endRange && compareDates(opts.endRange, day),
7939
+ isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
7940
+ isDisabled = (opts.minDate && day < opts.minDate) ||
7941
+ (opts.maxDate && day > opts.maxDate) ||
7942
+ (opts.disableWeekends && isWeekend(day)) ||
7943
+ (opts.disableDayFn && opts.disableDayFn(day));
7944
+
7945
+ if (isEmpty) {
7946
+ if (i < before) {
7947
+ dayNumber = daysInPreviousMonth + dayNumber;
7948
+ monthNumber = previousMonth;
7949
+ yearNumber = yearOfPreviousMonth;
7950
+ } else {
7951
+ dayNumber = dayNumber - days;
7952
+ monthNumber = nextMonth;
7953
+ yearNumber = yearOfNextMonth;
7954
+ }
7955
+ }
7956
+
7957
+ var dayConfig = {
7958
+ day: dayNumber,
7959
+ month: monthNumber,
7960
+ year: yearNumber,
7961
+ hasEvent: hasEvent,
7962
+ isSelected: isSelected,
7963
+ isToday: isToday,
7964
+ isDisabled: isDisabled,
7965
+ isEmpty: isEmpty,
7966
+ isStartRange: isStartRange,
7967
+ isEndRange: isEndRange,
7968
+ isInRange: isInRange,
7969
+ showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths,
7970
+ enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths
7971
+ };
7972
+
7973
+ if (opts.pickWholeWeek && isSelected) {
7974
+ isWeekSelected = true;
7975
+ }
7976
+
7977
+ row.push(renderDay(dayConfig));
7978
+
7979
+ if (++r === 7) {
7980
+ if (opts.showWeekNumber) {
7981
+ row.unshift(renderWeek(i - before, month, year));
7982
+ }
7983
+ data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected));
7984
+ row = [];
7985
+ r = 0;
7986
+ isWeekSelected = false;
7987
+ }
7988
+ }
7989
+ return renderTable(opts, data, randId);
7990
+ },
7991
+
7992
+ isVisible: function () {
7993
+ return this._v;
7994
+ },
7995
+
7996
+ show: function () {
7997
+ if (!this.isVisible()) {
7998
+ this._v = true;
7999
+ this.draw();
8000
+ removeClass(this.el, 'is-hidden');
8001
+ if (this._o.bound) {
8002
+ addEvent(document, 'click', this._onClick);
8003
+ this.adjustPosition();
8004
+ }
8005
+ if (typeof this._o.onOpen === 'function') {
8006
+ this._o.onOpen.call(this);
8007
+ }
8008
+ }
8009
+ },
8010
+
8011
+ hide: function () {
8012
+ var v = this._v;
8013
+ if (v !== false) {
8014
+ if (this._o.bound) {
8015
+ removeEvent(document, 'click', this._onClick);
8016
+ }
8017
+ this.el.style.position = 'static'; // reset
8018
+ this.el.style.left = 'auto';
8019
+ this.el.style.top = 'auto';
8020
+ addClass(this.el, 'is-hidden');
8021
+ this._v = false;
8022
+ if (v !== undefined && typeof this._o.onClose === 'function') {
8023
+ this._o.onClose.call(this);
8024
+ }
8025
+ }
8026
+ },
8027
+
8028
+ /**
8029
+ * GAME OVER
8030
+ */
8031
+ destroy: function () {
8032
+ var opts = this._o;
8033
+
8034
+ this.hide();
8035
+ removeEvent(this.el, 'mousedown', this._onMouseDown, true);
8036
+ removeEvent(this.el, 'touchend', this._onMouseDown, true);
8037
+ removeEvent(this.el, 'change', this._onChange);
8038
+ if (opts.keyboardInput) {
8039
+ removeEvent(document, 'keydown', this._onKeyChange);
8040
+ }
8041
+ if (opts.field) {
8042
+ removeEvent(opts.field, 'change', this._onInputChange);
8043
+ if (opts.bound) {
8044
+ removeEvent(opts.trigger, 'click', this._onInputClick);
8045
+ removeEvent(opts.trigger, 'focus', this._onInputFocus);
8046
+ removeEvent(opts.trigger, 'blur', this._onInputBlur);
8047
+ }
8048
+ }
8049
+ if (this.el.parentNode) {
8050
+ this.el.parentNode.removeChild(this.el);
8051
+ }
7937
8052
  }
7938
- data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected));
7939
- row = [];
7940
- r = 0;
7941
- isWeekSelected = false;
7942
- }
7943
- }
7944
- return renderTable(opts, data, randId);
7945
- },
7946
-
7947
- isVisible: function()
7948
- {
7949
- return this._v;
7950
- },
7951
-
7952
- show: function()
7953
- {
7954
- if (!this.isVisible()) {
7955
- this._v = true;
7956
- this.draw();
7957
- removeClass(this.el, 'is-hidden');
7958
- if (this._o.bound) {
7959
- addEvent(document, 'click', this._onClick);
7960
- this.adjustPosition();
7961
- }
7962
- if (typeof this._o.onOpen === 'function') {
7963
- this._o.onOpen.call(this);
7964
- }
7965
- }
7966
- },
7967
-
7968
- hide: function()
7969
- {
7970
- var v = this._v;
7971
- if (v !== false) {
7972
- if (this._o.bound) {
7973
- removeEvent(document, 'click', this._onClick);
7974
- }
7975
- this.el.style.position = 'static'; // reset
7976
- this.el.style.left = 'auto';
7977
- this.el.style.top = 'auto';
7978
- addClass(this.el, 'is-hidden');
7979
- this._v = false;
7980
- if (v !== undefined && typeof this._o.onClose === 'function') {
7981
- this._o.onClose.call(this);
7982
- }
7983
- }
7984
- },
7985
-
7986
- /**
7987
- * GAME OVER
7988
- */
7989
- destroy: function()
7990
- {
7991
- var opts = this._o;
7992
-
7993
- this.hide();
7994
- removeEvent(this.el, 'mousedown', this._onMouseDown, true);
7995
- removeEvent(this.el, 'touchend', this._onMouseDown, true);
7996
- removeEvent(this.el, 'change', this._onChange);
7997
- if (opts.keyboardInput) {
7998
- removeEvent(document, 'keydown', this._onKeyChange);
7999
- }
8000
- if (opts.field) {
8001
- removeEvent(opts.field, 'change', this._onInputChange);
8002
- if (opts.bound) {
8003
- removeEvent(opts.trigger, 'click', this._onInputClick);
8004
- removeEvent(opts.trigger, 'focus', this._onInputFocus);
8005
- removeEvent(opts.trigger, 'blur', this._onInputBlur);
8006
- }
8007
- }
8008
- if (this.el.parentNode) {
8009
- this.el.parentNode.removeChild(this.el);
8010
- }
8011
- }
8012
-
8013
- };
8014
-
8015
- return Pikaday;
8016
- }));
8053
+
8054
+ };
8055
+
8056
+ return Pikaday;
8057
+ }));
8017
8058
  } (pikaday$1));
8018
8059
  return pikaday$1.exports;
8019
8060
  }
@@ -8021,50 +8062,26 @@ function requirePikaday () {
8021
8062
  var pikadayExports = /*@__PURE__*/ requirePikaday();
8022
8063
  var Pikaday = /*@__PURE__*/getDefaultExportFromCjs(pikadayExports);
8023
8064
 
8024
- class TimezonePicker extends ChartComponent {
8025
- constructor(renderTarget) {
8026
- super(renderTarget);
8027
- this.timeZones = ["Local", "UTC", "Africa/Algiers", "Africa/Cairo", "Africa/Casablanca", "Africa/Harare", "Africa/Johannesburg", "Africa/Lagos", "Africa/Nairobi", "Africa/Windhoek", "America/Anchorage", "America/Bogota", "America/Buenos Aires", "America/Caracas", "America/Chicago", "America/Chihuahua", "America/Denver", "America/Edmonton", "America/Godthab", "America/Guatemala", "America/Halifax", "America/Indiana/Indianapolis", "America/Los Angeles", "America/Manaus", "America/Mexico City", "America/Montevideo", "America/New York", "America/Phoenix", "America/Santiago", "America/Sao Paulo", "America/St Johns", "America/Tijuana", "America/Toronto", "America/Vancouver", "America/Winnipeg", "Asia/Amman", "Asia/Beirut", "Asia/Baghdad", "Asia/Baku", "Asia/Bangkok", "Asia/Calcutta", "Asia/Colombo", "Asia/Dhaka", "Asia/Dubai", "Asia/Ho Chi Minh", "Asia/Hong Kong", "Asia/Irkutsk", "Asia/Istanbul", "Asia/Jakarta", "Asia/Jerusalem", "Asia/Kabul", "Asia/Karachi", "Asia/Kathmandu", "Asia/Krasnoyarsk", "Asia/Kuala Lumpur", "Asia/Kuwait", "Asia/Magadan", "Asia/Muscat", "Asia/Novosibirsk", "Asia/Qatar", "Asia/Rangoon", "Asia/Seoul", "Asia/Shanghai", "Asia/Singapore", "Asia/Taipei", "Asia/Tbilisi", "Asia/Tehran", "Asia/Tokyo", "Asia/Vladivostok", "Asia/Yakutsk", "Asia/Yekaterinburg", "Asia/Yerevan", "Atlantic/Azores", "Atlantic/Cape Verde", "Atlantic/South Georgia", "Australia/Adelaide", "Australia/Brisbane", "Australia/Canberra", "Australia/Darwin", "Australia/Hobart", "Australia/Melbourne", "Australia/Perth", "Australia/Queensland", "Australia/Sydney", "Europe/Amsterdam", "Europe/Andorra", "Europe/Athens", "Europe/Belfast", "Europe/Belgrade", "Europe/Berlin", "Europe/Brussels", "Europe/Budapest", "Europe/Dublin", "Europe/Helsinki", "Europe/Kiev", "Europe/Lisbon", "Europe/London", "Europe/Luxembourg", "Europe/Madrid", "Europe/Minsk", "Europe/Monaco", "Europe/Moscow", "Europe/Oslo", "Europe/Paris", "Europe/Rome", "Europe/Stockholm", "Europe/Vienna", "Europe/Warsaw", "Europe/Zurich", "Pacific/Auckland", "Pacific/Fiji", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Midway", "Pacific/Tongatapu"];
8065
+ // Ensure moment is available globally for Pikaday
8066
+ if (typeof window !== 'undefined') {
8067
+ window.moment = moment$1;
8068
+ }
8069
+ // Export a function to safely create Pikaday instances
8070
+ function createPikaday(options) {
8071
+ if (typeof window === 'undefined') {
8072
+ console.warn('Pikaday requires a browser environment');
8073
+ return null;
8028
8074
  }
8029
- sortTimezones() {
8030
- let filteredTimezones = this.timeZones.filter((tz) => {
8031
- return !(tz.toLowerCase() == 'local' || tz == 'UTC');
8032
- });
8033
- filteredTimezones.sort((a, b) => {
8034
- let aOffset = moment.tz(new Date(), a.split(' ').join('_')).utcOffset();
8035
- let bOffset = moment.tz(new Date(), b.split(' ').join('_')).utcOffset();
8036
- if (aOffset < bOffset) {
8037
- return -1;
8038
- }
8039
- if (aOffset > bOffset) {
8040
- return 1;
8041
- }
8042
- return 0;
8043
- });
8044
- this.timeZones = ['Local', 'UTC'].concat(filteredTimezones);
8075
+ const Pikaday = window.Pikaday;
8076
+ if (!Pikaday) {
8077
+ console.error('Pikaday not available. Make sure pikaday.js is loaded.');
8078
+ return null;
8045
8079
  }
8046
- render(onTimezoneSelect, defaultTimeZone = null) {
8047
- this.targetElement = d3__namespace.select(this.renderTarget)
8048
- .classed("tsi-timezonePicker", true);
8049
- var timezoneSelection = this.targetElement.append("select")
8050
- .attr("class", "tsi-timezonePicker tsi-select");
8051
- this.sortTimezones();
8052
- var options = timezoneSelection.selectAll("option")
8053
- .data(this.timeZones)
8054
- .enter()
8055
- .append("option")
8056
- .attr('value', d => d)
8057
- .text((tz) => Utils.convertTimezoneToLabel(tz, this.getString('Local')));
8058
- timezoneSelection.on("change", function (d) {
8059
- var timezone = d3__namespace.select(this).node().value.replace(/\s/g, "_");
8060
- onTimezoneSelect(timezone);
8061
- });
8062
- defaultTimeZone = defaultTimeZone.replace(/_/g, " ");
8063
- if (defaultTimeZone != null) {
8064
- options.filter((d) => d == defaultTimeZone).attr("selected", true);
8065
- }
8066
- return;
8080
+ if (!moment$1 || !window.moment) {
8081
+ console.error('Moment.js not available. Pikaday requires moment.js.');
8082
+ return null;
8067
8083
  }
8084
+ return new Pikaday(options);
8068
8085
  }
8069
8086
 
8070
8087
  class DateTimePicker extends ChartComponent {
@@ -8337,8 +8354,8 @@ class DateTimePicker extends ChartComponent {
8337
8354
  weekdays: moment$1.localeData().weekdays(),
8338
8355
  weekdaysShort: moment$1.localeData().weekdaysMin()
8339
8356
  };
8340
- //@ts-ignore
8341
- this.calendarPicker = new Pikaday({
8357
+ // Use the safe Pikaday wrapper
8358
+ this.calendarPicker = createPikaday({
8342
8359
  bound: false,
8343
8360
  container: this.calendar.node(),
8344
8361
  field: this.calendar.node(),
@@ -8374,6 +8391,11 @@ class DateTimePicker extends ChartComponent {
8374
8391
  maxDate: this.convertToCalendarDate(this.maxMillis),
8375
8392
  defaultDate: Utils.adjustDateFromTimezoneOffset(new Date(this.fromMillis))
8376
8393
  });
8394
+ // Check if Pikaday was created successfully
8395
+ if (!this.calendarPicker) {
8396
+ console.error('Failed to create Pikaday calendar. Check moment.js availability.');
8397
+ return;
8398
+ }
8377
8399
  }
8378
8400
  setSelectedQuickTimes() {
8379
8401
  let isSelected = d => {
@@ -8782,6 +8804,7 @@ class AvailabilityChart extends ChartComponent {
8782
8804
  }
8783
8805
  //transformation of buckets created by the UX client to buckets for the availabilityChart
8784
8806
  createDisplayBuckets(fromMillis, toMillis) {
8807
+ //TODO: "" key is confusing, should be "count" or something similar
8785
8808
  var keysInRange = Object.keys(this.transformedAvailability[0].availabilityCount[""]).reduce((inRangeObj, timestamp, i, timestamps) => {
8786
8809
  var currTSMillis = (new Date(timestamp)).valueOf();
8787
8810
  var nextTSMillis = currTSMillis + this.bucketSize;
@@ -8834,6 +8857,7 @@ class AvailabilityChart extends ChartComponent {
8834
8857
  this.bucketSize = null;
8835
8858
  }
8836
8859
  }
8860
+ //TODO: should have proper types for parameters
8837
8861
  render(transformedAvailability, chartOptions, rawAvailability = {}) {
8838
8862
  this.setChartOptions(chartOptions);
8839
8863
  this.rawAvailability = rawAvailability;
@@ -13997,6 +14021,10 @@ class GeoProcessGraphic extends HistoryPlayback {
13997
14021
  }
13998
14022
  }
13999
14023
 
14024
+ // Ensure moment is available globally for Pikaday and other components
14025
+ if (typeof window !== 'undefined') {
14026
+ window.moment = moment$1;
14027
+ }
14000
14028
  class UXClient {
14001
14029
  constructor() {
14002
14030
  // Public facing components have class constructors exposed as public UXClient members.