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.umd.js CHANGED
@@ -21599,6 +21599,8 @@
21599
21599
  return voronoi;
21600
21600
  }
21601
21601
 
21602
+ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
21603
+
21602
21604
  function getDefaultExportFromCjs (x) {
21603
21605
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
21604
21606
  }
@@ -29457,50 +29459,89 @@
29457
29459
  }
29458
29460
  return hclColor.toString();
29459
29461
  }
29462
+ /**
29463
+ * Creates an array of colors for split-by series
29464
+ * @param displayState - The current display state
29465
+ * @param aggKey - The aggregate key
29466
+ * @param ignoreIsOnlyAgg - Whether to ignore the "only aggregate" optimization
29467
+ * @returns Array of color strings for each split-by
29468
+ */
29460
29469
  static createSplitByColors(displayState, aggKey, ignoreIsOnlyAgg = false) {
29461
- if (Object.keys(displayState[aggKey]["splitBys"]).length == 1)
29470
+ const splitBys = displayState[aggKey]?.splitBys;
29471
+ if (!splitBys) {
29472
+ return [];
29473
+ }
29474
+ const splitByCount = Object.keys(splitBys).length;
29475
+ // Early return for single split-by
29476
+ if (splitByCount === 1) {
29462
29477
  return [displayState[aggKey].color];
29463
- var isOnlyAgg = Object.keys(displayState).reduce((accum, currAgg) => {
29464
- if (currAgg == aggKey)
29465
- return accum;
29466
- if (displayState[currAgg]["visible"] == false)
29467
- return accum && true;
29468
- return false;
29469
- }, true);
29470
- if (isOnlyAgg && !ignoreIsOnlyAgg) {
29471
- return this.generateColors(Object.keys(displayState[aggKey]["splitBys"]).length);
29472
29478
  }
29473
- var aggColor = displayState[aggKey].color;
29474
- var interpolateColor = linear().domain([0, Object.keys(displayState[aggKey]["splitBys"]).length])
29475
- .range([hcl$2(aggColor).darker().l, hcl$2(aggColor).brighter().l]);
29476
- var colors = [];
29477
- for (var i = 0; i < Object.keys(displayState[aggKey]["splitBys"]).length; i++) {
29478
- const newColor = hcl$2(aggColor);
29479
+ // Create cache key for memoization
29480
+ const cacheKey = `${aggKey}_${splitByCount}_${displayState[aggKey].color}_${ignoreIsOnlyAgg}`;
29481
+ if (this.splitByColorCache.has(cacheKey)) {
29482
+ return this.splitByColorCache.get(cacheKey);
29483
+ }
29484
+ const isOnlyVisibleAgg = !ignoreIsOnlyAgg && this.isOnlyVisibleAggregate(displayState, aggKey);
29485
+ let colors;
29486
+ if (isOnlyVisibleAgg) {
29487
+ // Generate distinct colors when this is the only visible aggregate
29488
+ colors = this.generateColors(splitByCount);
29489
+ }
29490
+ else {
29491
+ // Generate color variations based on aggregate color
29492
+ colors = this.generateSplitByColorVariations(displayState[aggKey].color, splitByCount);
29493
+ }
29494
+ // Cache the result
29495
+ this.splitByColorCache.set(cacheKey, colors);
29496
+ // Limit cache size to prevent memory leaks
29497
+ if (this.splitByColorCache.size > 100) {
29498
+ const firstKey = this.splitByColorCache.keys().next().value;
29499
+ this.splitByColorCache.delete(firstKey);
29500
+ }
29501
+ return colors;
29502
+ }
29503
+ /**
29504
+ * Helper method to check if an aggregate is the only visible one
29505
+ */
29506
+ static isOnlyVisibleAggregate(displayState, aggKey) {
29507
+ for (const currAgg in displayState) {
29508
+ if (currAgg !== aggKey && displayState[currAgg]?.visible !== false) {
29509
+ return false;
29510
+ }
29511
+ }
29512
+ return true;
29513
+ }
29514
+ /**
29515
+ * Helper method to generate color variations for split-bys
29516
+ */
29517
+ static generateSplitByColorVariations(baseColor, count) {
29518
+ const baseHcl = hcl$2(baseColor);
29519
+ const interpolateColor = linear()
29520
+ .domain([0, count])
29521
+ .range([baseHcl.darker().l, baseHcl.brighter().l]);
29522
+ const colors = new Array(count);
29523
+ for (let i = 0; i < count; i++) {
29524
+ const newColor = hcl$2(baseColor);
29479
29525
  newColor.l = interpolateColor(i);
29480
- colors.push(newColor.formatHex());
29526
+ colors[i] = newColor.formatHex();
29481
29527
  }
29482
29528
  return colors;
29483
29529
  }
29530
+ /**
29531
+ * Clears the split-by color cache (useful when display state changes significantly)
29532
+ */
29533
+ static clearSplitByColorCache() {
29534
+ this.splitByColorCache.clear();
29535
+ }
29484
29536
  static colorSplitBy(displayState, splitByIndex, aggKey, ignoreIsOnlyAgg = false) {
29485
- if (Object.keys(displayState[aggKey]["splitBys"]).length == 1)
29486
- return displayState[aggKey].color;
29487
- var isOnlyAgg = Object.keys(displayState).reduce((accum, currAgg) => {
29488
- if (currAgg == aggKey)
29489
- return accum;
29490
- if (displayState[currAgg]["visible"] == false)
29491
- return accum && true;
29492
- return false;
29493
- }, true);
29494
- if (isOnlyAgg && !ignoreIsOnlyAgg) {
29495
- var splitByColors = this.generateColors(Object.keys(displayState[aggKey]["splitBys"]).length);
29496
- return splitByColors[splitByIndex];
29537
+ const colors = this.createSplitByColors(displayState, aggKey, ignoreIsOnlyAgg);
29538
+ if (typeof splitByIndex === 'number' &&
29539
+ Number.isInteger(splitByIndex) &&
29540
+ splitByIndex >= 0 &&
29541
+ splitByIndex < colors.length) {
29542
+ return colors[splitByIndex];
29497
29543
  }
29498
- var aggColor = displayState[aggKey].color;
29499
- var interpolateColor = linear().domain([0, Object.keys(displayState[aggKey]["splitBys"]).length])
29500
- .range([hcl$2(aggColor).darker().l, hcl$2(aggColor).brighter().l]);
29501
- const newColor = hcl$2(aggColor);
29502
- newColor.l = interpolateColor(splitByIndex);
29503
- return newColor.formatHex();
29544
+ return displayState[aggKey]?.color || '#000000';
29504
29545
  }
29505
29546
  static getTheme(theme) {
29506
29547
  return theme ? 'tsi-' + theme : 'tsi-dark';
@@ -29924,6 +29965,7 @@
29924
29965
  }
29925
29966
  }
29926
29967
  Utils.guidForNullTSID = Utils.guid();
29968
+ Utils.splitByColorCache = new Map();
29927
29969
  Utils.equalToEventTarget = (function (current, event) {
29928
29970
  return (current == event.target);
29929
29971
  });
@@ -31537,9 +31579,9 @@
31537
31579
  // maintainable code, while at the same time manually optimizing for tiny minified file size,
31538
31580
  // browser compatibility without additional requirements
31539
31581
  // and very few assumptions about the user's page layout.
31540
- var global = typeof window !== 'undefined' ? window : null;
31541
- var ssr = global === null;
31542
- var document$1 = !ssr ? global.document : undefined;
31582
+ var global$1 = typeof window !== 'undefined' ? window : null;
31583
+ var ssr = global$1 === null;
31584
+ var document$1 = !ssr ? global$1.document : undefined;
31543
31585
 
31544
31586
  // Save a couple long function names that are used frequently.
31545
31587
  // This optimization saves around 400 bytes.
@@ -32005,11 +32047,11 @@
32005
32047
  self.dragging = false;
32006
32048
 
32007
32049
  // Remove the stored event listeners. This is why we store them.
32008
- global[removeEventListener]('mouseup', self.stop);
32009
- global[removeEventListener]('touchend', self.stop);
32010
- global[removeEventListener]('touchcancel', self.stop);
32011
- global[removeEventListener]('mousemove', self.move);
32012
- global[removeEventListener]('touchmove', self.move);
32050
+ global$1[removeEventListener]('mouseup', self.stop);
32051
+ global$1[removeEventListener]('touchend', self.stop);
32052
+ global$1[removeEventListener]('touchcancel', self.stop);
32053
+ global$1[removeEventListener]('mousemove', self.move);
32054
+ global$1[removeEventListener]('touchmove', self.move);
32013
32055
 
32014
32056
  // Clear bound function references
32015
32057
  self.stop = null;
@@ -32066,11 +32108,11 @@
32066
32108
  self.stop = stopDragging.bind(self);
32067
32109
 
32068
32110
  // All the binding. `window` gets the stop events in case we drag out of the elements.
32069
- global[addEventListener]('mouseup', self.stop);
32070
- global[addEventListener]('touchend', self.stop);
32071
- global[addEventListener]('touchcancel', self.stop);
32072
- global[addEventListener]('mousemove', self.move);
32073
- global[addEventListener]('touchmove', self.move);
32111
+ global$1[addEventListener]('mouseup', self.stop);
32112
+ global$1[addEventListener]('touchend', self.stop);
32113
+ global$1[addEventListener]('touchcancel', self.stop);
32114
+ global$1[addEventListener]('mousemove', self.move);
32115
+ global$1[addEventListener]('touchmove', self.move);
32074
32116
 
32075
32117
  // Disable selection. Disable!
32076
32118
  a[addEventListener]('selectstart', NOOP);
@@ -33114,6 +33156,8 @@
33114
33156
  this.drawChart = drawChart;
33115
33157
  this.contextMenuElement = select(renderTarget).insert("div", ":first-child")
33116
33158
  .attr("class", "tsi-contextMenu")
33159
+ .attr("aria-label", "Context Menu")
33160
+ .attr("role", "menu")
33117
33161
  .style("left", "0px")
33118
33162
  .style("top", "0px");
33119
33163
  }
@@ -33202,6 +33246,7 @@
33202
33246
  var actionElementsEntered = actionElements.enter()
33203
33247
  .append("div")
33204
33248
  .attr("class", `tsi-actionElement`)
33249
+ .attr("role", "menuitem")
33205
33250
  .classed('tsi-hasSubMenu', d => d.isNested)
33206
33251
  .merge(actionElements)
33207
33252
  .text(d => d.name)
@@ -33328,6 +33373,7 @@
33328
33373
  }).data([theme]);
33329
33374
  this.tooltipDiv = tooltip.enter().append('div')
33330
33375
  .attr('class', 'tsi-tooltip')
33376
+ .attr('role', 'tooltip')
33331
33377
  .merge(tooltip)
33332
33378
  .each(function (d) {
33333
33379
  select(this).selectAll("*").remove();
@@ -36702,6 +36748,8 @@
36702
36748
  label.enter()
36703
36749
  .append("text")
36704
36750
  .attr("class", (d) => `tsi-swimLaneLabel-${lane} tsi-swimLaneLabel ${onClickPresentAndValid(d) ? 'tsi-boldOnHover' : ''}`)
36751
+ .attr("role", "heading")
36752
+ .attr("aria-level", "3")
36705
36753
  .merge(label)
36706
36754
  .style("text-anchor", "middle")
36707
36755
  .attr("transform", d => `translate(${(-this.horizontalLabelOffset + swimlaneLabelConstants.labelLeftPadding)},${(d.offset + d.height / 2)}) rotate(-90)`)
@@ -36726,13 +36774,12 @@
36726
36774
  });
36727
36775
  }
36728
36776
  render(data, options, aggregateExpressionOptions) {
36729
- console.log('LineChart render called a');
36730
36777
  super.render(data, options, aggregateExpressionOptions);
36731
36778
  this.originalSwimLanes = this.aggregateExpressionOptions.map((aEO) => {
36732
36779
  return aEO.swimLane;
36733
36780
  });
36734
36781
  this.originalSwimLaneOptions = options.swimLaneOptions;
36735
- this.hasBrush = options && (options.brushMoveAction || options.brushMoveEndAction || options.brushContextMenuActions);
36782
+ this.hasBrush = !!(options && (options.brushMoveAction || options.brushMoveEndAction || options.brushContextMenuActions));
36736
36783
  this.chartOptions.setOptions(options);
36737
36784
  this.chartMargins.right = this.chartOptions.labelSeriesWithMarker ? (SERIESLABELWIDTH + 8) : LINECHARTCHARTMARGINS.right;
36738
36785
  this.width = this.getWidth();
@@ -36781,6 +36828,7 @@
36781
36828
  .attr("type", "button")
36782
36829
  .on("click", function () {
36783
36830
  self.overwriteSwimLanes();
36831
+ // cast to any to avoid TS incompatibility when spreading chartOptions instance into ILineChartOptions
36784
36832
  self.render(self.data, { ...self.chartOptions, yAxisState: self.nextStackedState() }, self.aggregateExpressionOptions);
36785
36833
  select(this).attr("aria-label", () => self.getString("set axis state to") + ' ' + self.nextStackedState());
36786
36834
  setTimeout(() => select(this).node().focus(), 200);
@@ -36807,6 +36855,7 @@
36807
36855
  this.svgSelection = this.targetElement.append("svg")
36808
36856
  .attr("class", "tsi-lineChartSVG tsi-chartSVG")
36809
36857
  .attr('title', this.getString('Line chart'))
36858
+ .attr("role", "img")
36810
36859
  .attr("height", this.height);
36811
36860
  var g = this.svgSelection.append("g")
36812
36861
  .classed("svgGroup", true)
@@ -37192,6 +37241,55 @@
37192
37241
  }
37193
37242
  }
37194
37243
 
37244
+ class TimezonePicker extends ChartComponent {
37245
+ constructor(renderTarget) {
37246
+ super(renderTarget);
37247
+ 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"];
37248
+ }
37249
+ sortTimezones() {
37250
+ let filteredTimezones = this.timeZones.filter((tz) => {
37251
+ return !(tz.toLowerCase() == 'local' || tz == 'UTC');
37252
+ });
37253
+ filteredTimezones.sort((a, b) => {
37254
+ let aOffset = moment$1.tz(new Date(), a.split(' ').join('_')).utcOffset();
37255
+ let bOffset = moment$1.tz(new Date(), b.split(' ').join('_')).utcOffset();
37256
+ if (aOffset < bOffset) {
37257
+ return -1;
37258
+ }
37259
+ if (aOffset > bOffset) {
37260
+ return 1;
37261
+ }
37262
+ return 0;
37263
+ });
37264
+ this.timeZones = ['Local', 'UTC'].concat(filteredTimezones);
37265
+ }
37266
+ render(onTimezoneSelect, defaultTimeZone = null) {
37267
+ this.targetElement = select(this.renderTarget)
37268
+ .classed("tsi-timezonePicker", true);
37269
+ var timezoneSelection = this.targetElement.append("select")
37270
+ .attr("class", "tsi-timezonePicker tsi-select");
37271
+ this.sortTimezones();
37272
+ var options = timezoneSelection.selectAll("option")
37273
+ .data(this.timeZones)
37274
+ .enter()
37275
+ .append("option")
37276
+ .attr('value', d => d)
37277
+ .text((tz) => Utils.convertTimezoneToLabel(tz, this.getString('Local')));
37278
+ timezoneSelection.on("change", function (d) {
37279
+ var timezone = select(this).node().value.replace(/\s/g, "_");
37280
+ onTimezoneSelect(timezone);
37281
+ });
37282
+ defaultTimeZone = defaultTimeZone.replace(/_/g, " ");
37283
+ if (defaultTimeZone != null) {
37284
+ options.filter((d) => d == defaultTimeZone).attr("selected", true);
37285
+ }
37286
+ return;
37287
+ }
37288
+ }
37289
+
37290
+ var momentExports = requireMoment();
37291
+ var moment = /*@__PURE__*/getDefaultExportFromCjs(momentExports);
37292
+
37195
37293
  var pikaday$1 = {exports: {}};
37196
37294
 
37197
37295
  /*!
@@ -37207,1231 +37305,1177 @@
37207
37305
  if (hasRequiredPikaday) return pikaday$1.exports;
37208
37306
  hasRequiredPikaday = 1;
37209
37307
  (function (module, exports) {
37210
- (function (root, factory)
37211
- {
37308
+ (function (root, factory) {
37212
37309
 
37213
37310
  var moment;
37214
37311
  {
37215
37312
  // CommonJS module
37216
37313
  // Load moment.js as an optional dependency
37217
- try { moment = requireMoment(); } catch (e) {}
37314
+ try { moment = requireMoment(); } catch (e) { moment = (typeof window !== 'undefined' && window.moment) || undefined; }
37218
37315
  module.exports = factory(moment);
37219
37316
  }
37220
- }(pikaday, function (moment)
37221
- {
37317
+ }(typeof self !== 'undefined' ? self :
37318
+ typeof window !== 'undefined' ? window :
37319
+ typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
37320
+ pikaday, function (moment) {
37222
37321
 
37223
- /**
37224
- * feature detection and helper functions
37225
- */
37226
- var hasMoment = typeof moment === 'function',
37227
-
37228
- hasEventListeners = !!window.addEventListener,
37229
-
37230
- document = window.document,
37322
+ /**
37323
+ * feature detection and helper functions
37324
+ */
37325
+ var hasMoment = typeof moment === 'function' || (moment && typeof moment.version === 'string'),
37231
37326
 
37232
- sto = window.setTimeout,
37233
-
37234
- addEvent = function(el, e, callback, capture)
37235
- {
37236
- if (hasEventListeners) {
37237
- el.addEventListener(e, callback, !!capture);
37238
- } else {
37239
- el.attachEvent('on' + e, callback);
37240
- }
37241
- },
37327
+ hasEventListeners = !!window.addEventListener,
37242
37328
 
37243
- removeEvent = function(el, e, callback, capture)
37244
- {
37245
- if (hasEventListeners) {
37246
- el.removeEventListener(e, callback, !!capture);
37247
- } else {
37248
- el.detachEvent('on' + e, callback);
37249
- }
37250
- },
37329
+ document = window.document,
37251
37330
 
37252
- trim = function(str)
37253
- {
37254
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
37255
- },
37331
+ sto = window.setTimeout,
37256
37332
 
37257
- hasClass = function(el, cn)
37258
- {
37259
- return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
37260
- },
37333
+ addEvent = function (el, e, callback, capture) {
37334
+ if (hasEventListeners) {
37335
+ el.addEventListener(e, callback, !!capture);
37336
+ } else {
37337
+ el.attachEvent('on' + e, callback);
37338
+ }
37339
+ },
37261
37340
 
37262
- addClass = function(el, cn)
37263
- {
37264
- if (!hasClass(el, cn)) {
37265
- el.className = (el.className === '') ? cn : el.className + ' ' + cn;
37266
- }
37267
- },
37341
+ removeEvent = function (el, e, callback, capture) {
37342
+ if (hasEventListeners) {
37343
+ el.removeEventListener(e, callback, !!capture);
37344
+ } else {
37345
+ el.detachEvent('on' + e, callback);
37346
+ }
37347
+ },
37268
37348
 
37269
- removeClass = function(el, cn)
37270
- {
37271
- el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
37272
- },
37349
+ trim = function (str) {
37350
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
37351
+ },
37273
37352
 
37274
- isArray = function(obj)
37275
- {
37276
- return (/Array/).test(Object.prototype.toString.call(obj));
37277
- },
37353
+ hasClass = function (el, cn) {
37354
+ return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
37355
+ },
37278
37356
 
37279
- isDate = function(obj)
37280
- {
37281
- return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
37282
- },
37357
+ addClass = function (el, cn) {
37358
+ if (!hasClass(el, cn)) {
37359
+ el.className = (el.className === '') ? cn : el.className + ' ' + cn;
37360
+ }
37361
+ },
37362
+
37363
+ removeClass = function (el, cn) {
37364
+ el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
37365
+ },
37366
+
37367
+ isArray = function (obj) {
37368
+ return (/Array/).test(Object.prototype.toString.call(obj));
37369
+ },
37370
+
37371
+ isDate = function (obj) {
37372
+ return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
37373
+ },
37374
+
37375
+ isWeekend = function (date) {
37376
+ var day = date.getDay();
37377
+ return day === 0 || day === 6;
37378
+ },
37379
+
37380
+ isLeapYear = function (year) {
37381
+ // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
37382
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
37383
+ },
37384
+
37385
+ getDaysInMonth = function (year, month) {
37386
+ return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
37387
+ },
37388
+
37389
+ setToStartOfDay = function (date) {
37390
+ if (isDate(date)) date.setHours(0, 0, 0, 0);
37391
+ },
37392
+
37393
+ compareDates = function (a, b) {
37394
+ // weak date comparison (use setToStartOfDay(date) to ensure correct result)
37395
+ return a.getTime() === b.getTime();
37396
+ },
37397
+
37398
+ extend = function (to, from, overwrite) {
37399
+ var prop, hasProp;
37400
+ for (prop in from) {
37401
+ hasProp = to[prop] !== undefined;
37402
+ if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) {
37403
+ if (isDate(from[prop])) {
37404
+ if (overwrite) {
37405
+ to[prop] = new Date(from[prop].getTime());
37406
+ }
37407
+ }
37408
+ else if (isArray(from[prop])) {
37409
+ if (overwrite) {
37410
+ to[prop] = from[prop].slice(0);
37411
+ }
37412
+ } else {
37413
+ to[prop] = extend({}, from[prop], overwrite);
37414
+ }
37415
+ } else if (overwrite || !hasProp) {
37416
+ to[prop] = from[prop];
37417
+ }
37418
+ }
37419
+ return to;
37420
+ },
37421
+
37422
+ fireEvent = function (el, eventName, data) {
37423
+ var ev;
37424
+
37425
+ if (document.createEvent) {
37426
+ ev = document.createEvent('HTMLEvents');
37427
+ ev.initEvent(eventName, true, false);
37428
+ ev = extend(ev, data);
37429
+ el.dispatchEvent(ev);
37430
+ } else if (document.createEventObject) {
37431
+ ev = document.createEventObject();
37432
+ ev = extend(ev, data);
37433
+ el.fireEvent('on' + eventName, ev);
37434
+ }
37435
+ },
37283
37436
 
37284
- isWeekend = function(date)
37285
- {
37286
- var day = date.getDay();
37287
- return day === 0 || day === 6;
37288
- },
37437
+ adjustCalendar = function (calendar) {
37438
+ if (calendar.month < 0) {
37439
+ calendar.year -= Math.ceil(Math.abs(calendar.month) / 12);
37440
+ calendar.month += 12;
37441
+ }
37442
+ if (calendar.month > 11) {
37443
+ calendar.year += Math.floor(Math.abs(calendar.month) / 12);
37444
+ calendar.month -= 12;
37445
+ }
37446
+ return calendar;
37447
+ },
37289
37448
 
37290
- isLeapYear = function(year)
37291
- {
37292
- // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
37293
- return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
37294
- },
37449
+ /**
37450
+ * defaults and localisation
37451
+ */
37452
+ defaults = {
37295
37453
 
37296
- getDaysInMonth = function(year, month)
37297
- {
37298
- return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
37299
- },
37454
+ // bind the picker to a form field
37455
+ field: null,
37300
37456
 
37301
- setToStartOfDay = function(date)
37302
- {
37303
- if (isDate(date)) date.setHours(0,0,0,0);
37304
- },
37457
+ // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
37458
+ bound: undefined,
37305
37459
 
37306
- compareDates = function(a,b)
37307
- {
37308
- // weak date comparison (use setToStartOfDay(date) to ensure correct result)
37309
- return a.getTime() === b.getTime();
37310
- },
37460
+ // position of the datepicker, relative to the field (default to bottom & left)
37461
+ // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
37462
+ position: 'bottom left',
37311
37463
 
37312
- extend = function(to, from, overwrite)
37313
- {
37314
- var prop, hasProp;
37315
- for (prop in from) {
37316
- hasProp = to[prop] !== undefined;
37317
- if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) {
37318
- if (isDate(from[prop])) {
37319
- if (overwrite) {
37320
- to[prop] = new Date(from[prop].getTime());
37321
- }
37322
- }
37323
- else if (isArray(from[prop])) {
37324
- if (overwrite) {
37325
- to[prop] = from[prop].slice(0);
37326
- }
37327
- } else {
37328
- to[prop] = extend({}, from[prop], overwrite);
37329
- }
37330
- } else if (overwrite || !hasProp) {
37331
- to[prop] = from[prop];
37332
- }
37333
- }
37334
- return to;
37335
- },
37464
+ // automatically fit in the viewport even if it means repositioning from the position option
37465
+ reposition: true,
37336
37466
 
37337
- fireEvent = function(el, eventName, data)
37338
- {
37339
- var ev;
37340
-
37341
- if (document.createEvent) {
37342
- ev = document.createEvent('HTMLEvents');
37343
- ev.initEvent(eventName, true, false);
37344
- ev = extend(ev, data);
37345
- el.dispatchEvent(ev);
37346
- } else if (document.createEventObject) {
37347
- ev = document.createEventObject();
37348
- ev = extend(ev, data);
37349
- el.fireEvent('on' + eventName, ev);
37350
- }
37351
- },
37467
+ // the default output format for `.toString()` and `field` value
37468
+ format: 'YYYY-MM-DD',
37352
37469
 
37353
- adjustCalendar = function(calendar) {
37354
- if (calendar.month < 0) {
37355
- calendar.year -= Math.ceil(Math.abs(calendar.month)/12);
37356
- calendar.month += 12;
37357
- }
37358
- if (calendar.month > 11) {
37359
- calendar.year += Math.floor(Math.abs(calendar.month)/12);
37360
- calendar.month -= 12;
37361
- }
37362
- return calendar;
37363
- },
37470
+ // the toString function which gets passed a current date object and format
37471
+ // and returns a string
37472
+ toString: null,
37364
37473
 
37365
- /**
37366
- * defaults and localisation
37367
- */
37368
- defaults = {
37474
+ // used to create date object from current input string
37475
+ parse: null,
37369
37476
 
37370
- // bind the picker to a form field
37371
- field: null,
37477
+ // the initial date to view when first opened
37478
+ defaultDate: null,
37372
37479
 
37373
- // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
37374
- bound: undefined,
37480
+ // make the `defaultDate` the initial selected value
37481
+ setDefaultDate: false,
37375
37482
 
37376
- // position of the datepicker, relative to the field (default to bottom & left)
37377
- // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
37378
- position: 'bottom left',
37483
+ // first day of week (0: Sunday, 1: Monday etc)
37484
+ firstDay: 0,
37379
37485
 
37380
- // automatically fit in the viewport even if it means repositioning from the position option
37381
- reposition: true,
37486
+ // the default flag for moment's strict date parsing
37487
+ formatStrict: false,
37382
37488
 
37383
- // the default output format for `.toString()` and `field` value
37384
- format: 'YYYY-MM-DD',
37489
+ // the minimum/earliest date that can be selected
37490
+ minDate: null,
37491
+ // the maximum/latest date that can be selected
37492
+ maxDate: null,
37385
37493
 
37386
- // the toString function which gets passed a current date object and format
37387
- // and returns a string
37388
- toString: null,
37494
+ // number of years either side, or array of upper/lower range
37495
+ yearRange: 10,
37389
37496
 
37390
- // used to create date object from current input string
37391
- parse: null,
37497
+ // show week numbers at head of row
37498
+ showWeekNumber: false,
37392
37499
 
37393
- // the initial date to view when first opened
37394
- defaultDate: null,
37500
+ // Week picker mode
37501
+ pickWholeWeek: false,
37395
37502
 
37396
- // make the `defaultDate` the initial selected value
37397
- setDefaultDate: false,
37503
+ // used internally (don't config outside)
37504
+ minYear: 0,
37505
+ maxYear: 9999,
37506
+ minMonth: undefined,
37507
+ maxMonth: undefined,
37398
37508
 
37399
- // first day of week (0: Sunday, 1: Monday etc)
37400
- firstDay: 0,
37509
+ startRange: null,
37510
+ endRange: null,
37401
37511
 
37402
- // the default flag for moment's strict date parsing
37403
- formatStrict: false,
37512
+ isRTL: false,
37404
37513
 
37405
- // the minimum/earliest date that can be selected
37406
- minDate: null,
37407
- // the maximum/latest date that can be selected
37408
- maxDate: null,
37514
+ // Additional text to append to the year in the calendar title
37515
+ yearSuffix: '',
37409
37516
 
37410
- // number of years either side, or array of upper/lower range
37411
- yearRange: 10,
37517
+ // Render the month after year in the calendar title
37518
+ showMonthAfterYear: false,
37412
37519
 
37413
- // show week numbers at head of row
37414
- showWeekNumber: false,
37520
+ // Render days of the calendar grid that fall in the next or previous month
37521
+ showDaysInNextAndPreviousMonths: false,
37415
37522
 
37416
- // Week picker mode
37417
- pickWholeWeek: false,
37523
+ // Allows user to select days that fall in the next or previous month
37524
+ enableSelectionDaysInNextAndPreviousMonths: false,
37418
37525
 
37419
- // used internally (don't config outside)
37420
- minYear: 0,
37421
- maxYear: 9999,
37422
- minMonth: undefined,
37423
- maxMonth: undefined,
37526
+ // how many months are visible
37527
+ numberOfMonths: 1,
37424
37528
 
37425
- startRange: null,
37426
- endRange: null,
37529
+ // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
37530
+ // only used for the first display or when a selected date is not visible
37531
+ mainCalendar: 'left',
37427
37532
 
37428
- isRTL: false,
37533
+ // Specify a DOM element to render the calendar in
37534
+ container: undefined,
37429
37535
 
37430
- // Additional text to append to the year in the calendar title
37431
- yearSuffix: '',
37536
+ // Blur field when date is selected
37537
+ blurFieldOnSelect: true,
37432
37538
 
37433
- // Render the month after year in the calendar title
37434
- showMonthAfterYear: false,
37539
+ // internationalization
37540
+ i18n: {
37541
+ previousMonth: 'Previous Month',
37542
+ nextMonth: 'Next Month',
37543
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
37544
+ weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
37545
+ weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
37546
+ },
37435
37547
 
37436
- // Render days of the calendar grid that fall in the next or previous month
37437
- showDaysInNextAndPreviousMonths: false,
37548
+ // Theme Classname
37549
+ theme: null,
37438
37550
 
37439
- // Allows user to select days that fall in the next or previous month
37440
- enableSelectionDaysInNextAndPreviousMonths: false,
37551
+ // events array
37552
+ events: [],
37441
37553
 
37442
- // how many months are visible
37443
- numberOfMonths: 1,
37554
+ // callback function
37555
+ onSelect: null,
37556
+ onOpen: null,
37557
+ onClose: null,
37558
+ onDraw: null,
37444
37559
 
37445
- // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
37446
- // only used for the first display or when a selected date is not visible
37447
- mainCalendar: 'left',
37560
+ // Enable keyboard input
37561
+ keyboardInput: true
37562
+ },
37448
37563
 
37449
- // Specify a DOM element to render the calendar in
37450
- container: undefined,
37451
37564
 
37452
- // Blur field when date is selected
37453
- blurFieldOnSelect : true,
37565
+ /**
37566
+ * templating functions to abstract HTML rendering
37567
+ */
37568
+ renderDayName = function (opts, day, abbr) {
37569
+ day += opts.firstDay;
37570
+ while (day >= 7) {
37571
+ day -= 7;
37572
+ }
37573
+ return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
37574
+ },
37575
+
37576
+ renderDay = function (opts) {
37577
+ var arr = [];
37578
+ var ariaSelected = 'false';
37579
+ if (opts.isEmpty) {
37580
+ if (opts.showDaysInNextAndPreviousMonths) {
37581
+ arr.push('is-outside-current-month');
37582
+
37583
+ if (!opts.enableSelectionDaysInNextAndPreviousMonths) {
37584
+ arr.push('is-selection-disabled');
37585
+ }
37586
+
37587
+ } else {
37588
+ return '<td class="is-empty"></td>';
37589
+ }
37590
+ }
37591
+ if (opts.isDisabled) {
37592
+ arr.push('is-disabled');
37593
+ }
37594
+ if (opts.isToday) {
37595
+ arr.push('is-today');
37596
+ }
37597
+ if (opts.isSelected) {
37598
+ arr.push('is-selected');
37599
+ ariaSelected = 'true';
37600
+ }
37601
+ if (opts.hasEvent) {
37602
+ arr.push('has-event');
37603
+ }
37604
+ if (opts.isInRange) {
37605
+ arr.push('is-inrange');
37606
+ }
37607
+ if (opts.isStartRange) {
37608
+ arr.push('is-startrange');
37609
+ }
37610
+ if (opts.isEndRange) {
37611
+ arr.push('is-endrange');
37612
+ }
37613
+ return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
37614
+ '<button tabIndex="-1" class="pika-button pika-day" type="button" ' +
37615
+ 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
37616
+ opts.day +
37617
+ '</button>' +
37618
+ '</td>';
37619
+ },
37620
+
37621
+ renderWeek = function (d, m, y) {
37622
+ // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
37623
+ var onejan = new Date(y, 0, 1),
37624
+ weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay() + 1) / 7);
37625
+ return '<td class="pika-week">' + weekNum + '</td>';
37626
+ },
37627
+
37628
+ renderRow = function (days, isRTL, pickWholeWeek, isRowSelected) {
37629
+ return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>';
37630
+ },
37631
+
37632
+ renderBody = function (rows) {
37633
+ return '<tbody>' + rows.join('') + '</tbody>';
37634
+ },
37635
+
37636
+ renderHead = function (opts) {
37637
+ var i, arr = [];
37638
+ if (opts.showWeekNumber) {
37639
+ arr.push('<th></th>');
37640
+ }
37641
+ for (i = 0; i < 7; i++) {
37642
+ arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
37643
+ }
37644
+ return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
37645
+ },
37646
+
37647
+ renderTitle = function (instance, c, year, month, refYear, randId) {
37648
+ var i, j, arr,
37649
+ opts = instance._o,
37650
+ isMinYear = year === opts.minYear,
37651
+ isMaxYear = year === opts.maxYear,
37652
+ html = '<div id="' + randId + '" class="pika-title">',
37653
+ monthHtml,
37654
+ yearHtml,
37655
+ prev = true,
37656
+ next = true;
37657
+
37658
+ for (arr = [], i = 0; i < 12; i++) {
37659
+ arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
37660
+ (i === month ? ' selected="selected"' : '') +
37661
+ ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
37662
+ opts.i18n.months[i] + '</option>');
37663
+ }
37454
37664
 
37455
- // internationalization
37456
- i18n: {
37457
- previousMonth : 'Previous Month',
37458
- nextMonth : 'Next Month',
37459
- months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
37460
- weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
37461
- weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
37462
- },
37665
+ 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>';
37463
37666
 
37464
- // Theme Classname
37465
- theme: null,
37667
+ if (isArray(opts.yearRange)) {
37668
+ i = opts.yearRange[0];
37669
+ j = opts.yearRange[1] + 1;
37670
+ } else {
37671
+ i = year - opts.yearRange;
37672
+ j = 1 + year + opts.yearRange;
37673
+ }
37466
37674
 
37467
- // events array
37468
- events: [],
37675
+ for (arr = []; i < j && i <= opts.maxYear; i++) {
37676
+ if (i >= opts.minYear) {
37677
+ arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"' : '') + '>' + (i) + '</option>');
37678
+ }
37679
+ }
37680
+ 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>';
37469
37681
 
37470
- // callback function
37471
- onSelect: null,
37472
- onOpen: null,
37473
- onClose: null,
37474
- onDraw: null,
37682
+ if (opts.showMonthAfterYear) {
37683
+ html += yearHtml + monthHtml;
37684
+ } else {
37685
+ html += monthHtml + yearHtml;
37686
+ }
37475
37687
 
37476
- // Enable keyboard input
37477
- keyboardInput: true
37478
- },
37688
+ if (isMinYear && (month === 0 || opts.minMonth >= month)) {
37689
+ prev = false;
37690
+ }
37479
37691
 
37692
+ if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
37693
+ next = false;
37694
+ }
37480
37695
 
37481
- /**
37482
- * templating functions to abstract HTML rendering
37483
- */
37484
- renderDayName = function(opts, day, abbr)
37485
- {
37486
- day += opts.firstDay;
37487
- while (day >= 7) {
37488
- day -= 7;
37489
- }
37490
- return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
37491
- },
37696
+ if (c === 0) {
37697
+ html += '<button tabIndex="-1" class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
37698
+ }
37699
+ if (c === (instance._o.numberOfMonths - 1)) {
37700
+ html += '<button tabIndex="-1" class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
37701
+ }
37492
37702
 
37493
- renderDay = function(opts)
37494
- {
37495
- var arr = [];
37496
- var ariaSelected = 'false';
37497
- if (opts.isEmpty) {
37498
- if (opts.showDaysInNextAndPreviousMonths) {
37499
- arr.push('is-outside-current-month');
37500
-
37501
- if(!opts.enableSelectionDaysInNextAndPreviousMonths) {
37502
- arr.push('is-selection-disabled');
37503
- }
37703
+ return html += '</div>';
37704
+ },
37504
37705
 
37505
- } else {
37506
- return '<td class="is-empty"></td>';
37507
- }
37508
- }
37509
- if (opts.isDisabled) {
37510
- arr.push('is-disabled');
37511
- }
37512
- if (opts.isToday) {
37513
- arr.push('is-today');
37514
- }
37515
- if (opts.isSelected) {
37516
- arr.push('is-selected');
37517
- ariaSelected = 'true';
37518
- }
37519
- if (opts.hasEvent) {
37520
- arr.push('has-event');
37521
- }
37522
- if (opts.isInRange) {
37523
- arr.push('is-inrange');
37524
- }
37525
- if (opts.isStartRange) {
37526
- arr.push('is-startrange');
37527
- }
37528
- if (opts.isEndRange) {
37529
- arr.push('is-endrange');
37530
- }
37531
- return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
37532
- '<button tabIndex="-1" class="pika-button pika-day" type="button" ' +
37533
- 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
37534
- opts.day +
37535
- '</button>' +
37536
- '</td>';
37537
- },
37538
-
37539
- renderWeek = function (d, m, y) {
37540
- // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
37541
- var onejan = new Date(y, 0, 1),
37542
- weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay()+1)/7);
37543
- return '<td class="pika-week">' + weekNum + '</td>';
37544
- },
37545
-
37546
- renderRow = function(days, isRTL, pickWholeWeek, isRowSelected)
37547
- {
37548
- return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>';
37549
- },
37706
+ renderTable = function (opts, data, randId) {
37707
+ return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
37708
+ },
37550
37709
 
37551
- renderBody = function(rows)
37552
- {
37553
- return '<tbody>' + rows.join('') + '</tbody>';
37554
- },
37555
37710
 
37556
- renderHead = function(opts)
37557
- {
37558
- var i, arr = [];
37559
- if (opts.showWeekNumber) {
37560
- arr.push('<th></th>');
37561
- }
37562
- for (i = 0; i < 7; i++) {
37563
- arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
37564
- }
37565
- return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
37566
- },
37711
+ /**
37712
+ * Pikaday constructor
37713
+ */
37714
+ Pikaday = function (options) {
37715
+ var self = this,
37716
+ opts = self.config(options);
37567
37717
 
37568
- renderTitle = function(instance, c, year, month, refYear, randId)
37569
- {
37570
- var i, j, arr,
37571
- opts = instance._o,
37572
- isMinYear = year === opts.minYear,
37573
- isMaxYear = year === opts.maxYear,
37574
- html = '<div id="' + randId + '" class="pika-title">',
37575
- monthHtml,
37576
- yearHtml,
37577
- prev = true,
37578
- next = true;
37579
-
37580
- for (arr = [], i = 0; i < 12; i++) {
37581
- arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
37582
- (i === month ? ' selected="selected"': '') +
37583
- ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
37584
- opts.i18n.months[i] + '</option>');
37585
- }
37718
+ self._onMouseDown = function (e) {
37719
+ if (!self._v) {
37720
+ return;
37721
+ }
37722
+ e = e || window.event;
37723
+ var target = e.target || e.srcElement;
37724
+ if (!target) {
37725
+ return;
37726
+ }
37586
37727
 
37587
- 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>';
37728
+ if (!hasClass(target, 'is-disabled')) {
37729
+ if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
37730
+ self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
37731
+ if (opts.bound) {
37732
+ sto(function () {
37733
+ self.hide();
37734
+ if (opts.blurFieldOnSelect && opts.field) {
37735
+ opts.field.blur();
37736
+ }
37737
+ }, 100);
37738
+ }
37739
+ }
37740
+ else if (hasClass(target, 'pika-prev')) {
37741
+ self.prevMonth();
37742
+ }
37743
+ else if (hasClass(target, 'pika-next')) {
37744
+ self.nextMonth();
37745
+ }
37746
+ }
37747
+ if (!hasClass(target, 'pika-select')) {
37748
+ // if this is touch event prevent mouse events emulation
37749
+ if (e.preventDefault) {
37750
+ e.preventDefault();
37751
+ } else {
37752
+ e.returnValue = false;
37753
+ return false;
37754
+ }
37755
+ } else {
37756
+ self._c = true;
37757
+ }
37758
+ };
37588
37759
 
37589
- if (isArray(opts.yearRange)) {
37590
- i = opts.yearRange[0];
37591
- j = opts.yearRange[1] + 1;
37592
- } else {
37593
- i = year - opts.yearRange;
37594
- j = 1 + year + opts.yearRange;
37595
- }
37760
+ self._onChange = function (e) {
37761
+ e = e || window.event;
37762
+ var target = e.target || e.srcElement;
37763
+ if (!target) {
37764
+ return;
37765
+ }
37766
+ if (hasClass(target, 'pika-select-month')) {
37767
+ self.gotoMonth(target.value);
37768
+ }
37769
+ else if (hasClass(target, 'pika-select-year')) {
37770
+ self.gotoYear(target.value);
37771
+ }
37772
+ };
37773
+
37774
+ self._onKeyChange = function (e) {
37775
+ e = e || window.event;
37776
+ // ignore if event comes from input box
37777
+ if (self.isVisible() && e.target && e.target.type !== 'text') {
37778
+
37779
+ switch (e.keyCode) {
37780
+ case 13:
37781
+ case 27:
37782
+ if (opts.field) {
37783
+ opts.field.blur();
37784
+ }
37785
+ break;
37786
+ case 37:
37787
+ e.preventDefault();
37788
+ self.adjustDate('subtract', 1);
37789
+ break;
37790
+ case 38:
37791
+ self.adjustDate('subtract', 7);
37792
+ break;
37793
+ case 39:
37794
+ self.adjustDate('add', 1);
37795
+ break;
37796
+ case 40:
37797
+ self.adjustDate('add', 7);
37798
+ break;
37799
+ }
37800
+ }
37801
+ };
37596
37802
 
37597
- for (arr = []; i < j && i <= opts.maxYear; i++) {
37598
- if (i >= opts.minYear) {
37599
- arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"': '') + '>' + (i) + '</option>');
37600
- }
37601
- }
37602
- 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>';
37803
+ self._onInputChange = function (e) {
37804
+ var date;
37603
37805
 
37604
- if (opts.showMonthAfterYear) {
37605
- html += yearHtml + monthHtml;
37606
- } else {
37607
- html += monthHtml + yearHtml;
37608
- }
37806
+ if (e.firedBy === self) {
37807
+ return;
37808
+ }
37809
+ if (opts.parse) {
37810
+ date = opts.parse(opts.field.value, opts.format);
37811
+ } else if (hasMoment) {
37812
+ date = moment(opts.field.value, opts.format, opts.formatStrict);
37813
+ date = (date && date.isValid()) ? date.toDate() : null;
37814
+ }
37815
+ else {
37816
+ date = new Date(Date.parse(opts.field.value));
37817
+ }
37818
+ // if (isDate(date)) {
37819
+ // self.setDate(date);
37820
+ // }
37821
+ // if (!self._v) {
37822
+ // self.show();
37823
+ // }
37824
+ };
37825
+
37826
+ self._onInputFocus = function () {
37827
+ self.show();
37828
+ };
37829
+
37830
+ self._onInputClick = function () {
37831
+ self.show();
37832
+ };
37833
+
37834
+ self._onInputBlur = function () {
37835
+ // IE allows pika div to gain focus; catch blur the input field
37836
+ var pEl = document.activeElement;
37837
+ do {
37838
+ if (hasClass(pEl, 'pika-single')) {
37839
+ return;
37840
+ }
37841
+ }
37842
+ while ((pEl = pEl.parentNode));
37609
37843
 
37610
- if (isMinYear && (month === 0 || opts.minMonth >= month)) {
37611
- prev = false;
37612
- }
37844
+ if (!self._c) {
37845
+ self._b = sto(function () {
37846
+ self.hide();
37847
+ }, 50);
37848
+ }
37849
+ self._c = false;
37850
+ };
37851
+
37852
+ self._onClick = function (e) {
37853
+ e = e || window.event;
37854
+ var target = e.target || e.srcElement,
37855
+ pEl = target;
37856
+ if (!target) {
37857
+ return;
37858
+ }
37859
+ if (!hasEventListeners && hasClass(target, 'pika-select')) {
37860
+ if (!target.onchange) {
37861
+ target.setAttribute('onchange', 'return;');
37862
+ addEvent(target, 'change', self._onChange);
37863
+ }
37864
+ }
37865
+ do {
37866
+ if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) {
37867
+ return;
37868
+ }
37869
+ }
37870
+ while ((pEl = pEl.parentNode));
37871
+ if (self._v && target !== opts.trigger && pEl !== opts.trigger) {
37872
+ self.hide();
37873
+ }
37874
+ };
37613
37875
 
37614
- if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
37615
- next = false;
37616
- }
37876
+ self.el = document.createElement('div');
37877
+ self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : '');
37617
37878
 
37618
- if (c === 0) {
37619
- html += '<button tabIndex="-1" class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
37620
- }
37621
- if (c === (instance._o.numberOfMonths - 1) ) {
37622
- html += '<button tabIndex="-1" class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
37623
- }
37879
+ addEvent(self.el, 'mousedown', self._onMouseDown, true);
37880
+ addEvent(self.el, 'touchend', self._onMouseDown, true);
37881
+ addEvent(self.el, 'change', self._onChange);
37624
37882
 
37625
- return html += '</div>';
37626
- },
37883
+ if (opts.keyboardInput) {
37884
+ addEvent(document, 'keydown', self._onKeyChange);
37885
+ }
37627
37886
 
37628
- renderTable = function(opts, data, randId)
37629
- {
37630
- return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
37631
- },
37887
+ if (opts.field) {
37888
+ if (opts.container) {
37889
+ opts.container.appendChild(self.el);
37890
+ } else if (opts.bound) {
37891
+ document.body.appendChild(self.el);
37892
+ } else {
37893
+ opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
37894
+ }
37895
+ addEvent(opts.field, 'change', self._onInputChange);
37896
+
37897
+ if (!opts.defaultDate) {
37898
+ if (hasMoment && opts.field.value) {
37899
+ opts.defaultDate = moment(opts.field.value, opts.format).toDate();
37900
+ } else {
37901
+ opts.defaultDate = new Date(Date.parse(opts.field.value));
37902
+ }
37903
+ opts.setDefaultDate = true;
37904
+ }
37905
+ }
37632
37906
 
37907
+ var defDate = opts.defaultDate;
37633
37908
 
37634
- /**
37635
- * Pikaday constructor
37636
- */
37637
- Pikaday = function(options)
37638
- {
37639
- var self = this,
37640
- opts = self.config(options);
37909
+ if (isDate(defDate)) {
37910
+ if (opts.setDefaultDate) {
37911
+ self.setDate(defDate, true);
37912
+ } else {
37913
+ self.gotoDate(defDate);
37914
+ }
37915
+ } else {
37916
+ self.gotoDate(new Date());
37917
+ }
37641
37918
 
37642
- self._onMouseDown = function(e)
37643
- {
37644
- if (!self._v) {
37645
- return;
37646
- }
37647
- e = e || window.event;
37648
- var target = e.target || e.srcElement;
37649
- if (!target) {
37650
- return;
37651
- }
37919
+ if (opts.bound) {
37920
+ this.hide();
37921
+ self.el.className += ' is-bound';
37922
+ addEvent(opts.trigger, 'click', self._onInputClick);
37923
+ addEvent(opts.trigger, 'focus', self._onInputFocus);
37924
+ addEvent(opts.trigger, 'blur', self._onInputBlur);
37925
+ } else {
37926
+ this.show();
37927
+ }
37928
+ };
37652
37929
 
37653
- if (!hasClass(target, 'is-disabled')) {
37654
- if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
37655
- self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
37656
- if (opts.bound) {
37657
- sto(function() {
37658
- self.hide();
37659
- if (opts.blurFieldOnSelect && opts.field) {
37660
- opts.field.blur();
37661
- }
37662
- }, 100);
37663
- }
37664
- }
37665
- else if (hasClass(target, 'pika-prev')) {
37666
- self.prevMonth();
37667
- }
37668
- else if (hasClass(target, 'pika-next')) {
37669
- self.nextMonth();
37670
- }
37671
- }
37672
- if (!hasClass(target, 'pika-select')) {
37673
- // if this is touch event prevent mouse events emulation
37674
- if (e.preventDefault) {
37675
- e.preventDefault();
37676
- } else {
37677
- e.returnValue = false;
37678
- return false;
37679
- }
37680
- } else {
37681
- self._c = true;
37682
- }
37683
- };
37684
37930
 
37685
- self._onChange = function(e)
37686
- {
37687
- e = e || window.event;
37688
- var target = e.target || e.srcElement;
37689
- if (!target) {
37690
- return;
37691
- }
37692
- if (hasClass(target, 'pika-select-month')) {
37693
- self.gotoMonth(target.value);
37694
- }
37695
- else if (hasClass(target, 'pika-select-year')) {
37696
- self.gotoYear(target.value);
37697
- }
37698
- };
37931
+ /**
37932
+ * public Pikaday API
37933
+ */
37934
+ Pikaday.prototype = {
37699
37935
 
37700
- self._onKeyChange = function(e)
37701
- {
37702
- e = e || window.event;
37703
- // ignore if event comes from input box
37704
- if (self.isVisible() && e.target && e.target.type !== 'text') {
37705
37936
 
37706
- switch(e.keyCode){
37707
- case 13:
37708
- case 27:
37709
- if (opts.field) {
37710
- opts.field.blur();
37937
+ /**
37938
+ * configure functionality
37939
+ */
37940
+ config: function (options) {
37941
+ if (!this._o) {
37942
+ this._o = extend({}, defaults, true);
37711
37943
  }
37712
- break;
37713
- case 37:
37714
- e.preventDefault();
37715
- self.adjustDate('subtract', 1);
37716
- break;
37717
- case 38:
37718
- self.adjustDate('subtract', 7);
37719
- break;
37720
- case 39:
37721
- self.adjustDate('add', 1);
37722
- break;
37723
- case 40:
37724
- self.adjustDate('add', 7);
37725
- break;
37726
- }
37727
- }
37728
- };
37729
37944
 
37730
- self._onInputChange = function(e)
37731
- {
37732
- var date;
37945
+ var opts = extend(this._o, options, true);
37733
37946
 
37734
- if (e.firedBy === self) {
37735
- return;
37736
- }
37737
- if (opts.parse) {
37738
- date = opts.parse(opts.field.value, opts.format);
37739
- } else if (hasMoment) {
37740
- date = moment(opts.field.value, opts.format, opts.formatStrict);
37741
- date = (date && date.isValid()) ? date.toDate() : null;
37742
- }
37743
- else {
37744
- date = new Date(Date.parse(opts.field.value));
37745
- }
37746
- // if (isDate(date)) {
37747
- // self.setDate(date);
37748
- // }
37749
- // if (!self._v) {
37750
- // self.show();
37751
- // }
37752
- };
37947
+ opts.isRTL = !!opts.isRTL;
37753
37948
 
37754
- self._onInputFocus = function()
37755
- {
37756
- self.show();
37757
- };
37949
+ opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
37758
37950
 
37759
- self._onInputClick = function()
37760
- {
37761
- self.show();
37762
- };
37951
+ opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null;
37763
37952
 
37764
- self._onInputBlur = function()
37765
- {
37766
- // IE allows pika div to gain focus; catch blur the input field
37767
- var pEl = document.activeElement;
37768
- do {
37769
- if (hasClass(pEl, 'pika-single')) {
37770
- return;
37771
- }
37772
- }
37773
- while ((pEl = pEl.parentNode));
37953
+ opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
37774
37954
 
37775
- if (!self._c) {
37776
- self._b = sto(function() {
37777
- self.hide();
37778
- }, 50);
37779
- }
37780
- self._c = false;
37781
- };
37955
+ opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
37782
37956
 
37783
- self._onClick = function(e)
37784
- {
37785
- e = e || window.event;
37786
- var target = e.target || e.srcElement,
37787
- pEl = target;
37788
- if (!target) {
37789
- return;
37790
- }
37791
- if (!hasEventListeners && hasClass(target, 'pika-select')) {
37792
- if (!target.onchange) {
37793
- target.setAttribute('onchange', 'return;');
37794
- addEvent(target, 'change', self._onChange);
37795
- }
37796
- }
37797
- do {
37798
- if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) {
37799
- return;
37800
- }
37801
- }
37802
- while ((pEl = pEl.parentNode));
37803
- if (self._v && target !== opts.trigger && pEl !== opts.trigger) {
37804
- self.hide();
37805
- }
37806
- };
37957
+ opts.disableWeekends = !!opts.disableWeekends;
37807
37958
 
37808
- self.el = document.createElement('div');
37809
- self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : '');
37959
+ opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null;
37810
37960
 
37811
- addEvent(self.el, 'mousedown', self._onMouseDown, true);
37812
- addEvent(self.el, 'touchend', self._onMouseDown, true);
37813
- addEvent(self.el, 'change', self._onChange);
37961
+ var nom = parseInt(opts.numberOfMonths, 10) || 1;
37962
+ opts.numberOfMonths = nom > 4 ? 4 : nom;
37814
37963
 
37815
- if (opts.keyboardInput) {
37816
- addEvent(document, 'keydown', self._onKeyChange);
37817
- }
37818
-
37819
- if (opts.field) {
37820
- if (opts.container) {
37821
- opts.container.appendChild(self.el);
37822
- } else if (opts.bound) {
37823
- document.body.appendChild(self.el);
37824
- } else {
37825
- opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
37826
- }
37827
- addEvent(opts.field, 'change', self._onInputChange);
37828
-
37829
- if (!opts.defaultDate) {
37830
- if (hasMoment && opts.field.value) {
37831
- opts.defaultDate = moment(opts.field.value, opts.format).toDate();
37832
- } else {
37833
- opts.defaultDate = new Date(Date.parse(opts.field.value));
37834
- }
37835
- opts.setDefaultDate = true;
37836
- }
37837
- }
37838
-
37839
- var defDate = opts.defaultDate;
37840
-
37841
- if (isDate(defDate)) {
37842
- if (opts.setDefaultDate) {
37843
- self.setDate(defDate, true);
37844
- } else {
37845
- self.gotoDate(defDate);
37846
- }
37847
- } else {
37848
- self.gotoDate(new Date());
37849
- }
37850
-
37851
- if (opts.bound) {
37852
- this.hide();
37853
- self.el.className += ' is-bound';
37854
- addEvent(opts.trigger, 'click', self._onInputClick);
37855
- addEvent(opts.trigger, 'focus', self._onInputFocus);
37856
- addEvent(opts.trigger, 'blur', self._onInputBlur);
37857
- } else {
37858
- this.show();
37859
- }
37860
- };
37861
-
37862
-
37863
- /**
37864
- * public Pikaday API
37865
- */
37866
- Pikaday.prototype = {
37867
-
37868
-
37869
- /**
37870
- * configure functionality
37871
- */
37872
- config: function(options)
37873
- {
37874
- if (!this._o) {
37875
- this._o = extend({}, defaults, true);
37876
- }
37877
-
37878
- var opts = extend(this._o, options, true);
37879
-
37880
- opts.isRTL = !!opts.isRTL;
37881
-
37882
- opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
37883
-
37884
- opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null;
37885
-
37886
- opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
37887
-
37888
- opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
37889
-
37890
- opts.disableWeekends = !!opts.disableWeekends;
37891
-
37892
- opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null;
37893
-
37894
- var nom = parseInt(opts.numberOfMonths, 10) || 1;
37895
- opts.numberOfMonths = nom > 4 ? 4 : nom;
37896
-
37897
- if (!isDate(opts.minDate)) {
37898
- opts.minDate = false;
37899
- }
37900
- if (!isDate(opts.maxDate)) {
37901
- opts.maxDate = false;
37902
- }
37903
- if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
37904
- opts.maxDate = opts.minDate = false;
37905
- }
37906
- if (opts.minDate) {
37907
- this.setMinDate(opts.minDate);
37908
- }
37909
- if (opts.maxDate) {
37910
- this.setMaxDate(opts.maxDate);
37911
- }
37912
-
37913
- if (isArray(opts.yearRange)) {
37914
- var fallback = new Date().getFullYear() - 10;
37915
- opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
37916
- opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
37917
- } else {
37918
- opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
37919
- if (opts.yearRange > 100) {
37920
- opts.yearRange = 100;
37921
- }
37922
- }
37923
-
37924
- return opts;
37925
- },
37926
-
37927
- /**
37928
- * return a formatted string of the current selection (using Moment.js if available)
37929
- */
37930
- toString: function(format)
37931
- {
37932
- format = format || this._o.format;
37933
- if (!isDate(this._d)) {
37934
- return '';
37935
- }
37936
- if (this._o.toString) {
37937
- return this._o.toString(this._d, format);
37938
- }
37939
- if (hasMoment) {
37940
- return moment(this._d).format(format);
37941
- }
37942
- return this._d.toDateString();
37943
- },
37944
-
37945
- /**
37946
- * return a Moment.js object of the current selection (if available)
37947
- */
37948
- getMoment: function()
37949
- {
37950
- return hasMoment ? moment(this._d) : null;
37951
- },
37952
-
37953
- /**
37954
- * set the current selection from a Moment.js object (if available)
37955
- */
37956
- setMoment: function(date, preventOnSelect)
37957
- {
37958
- if (hasMoment && moment.isMoment(date)) {
37959
- this.setDate(date.toDate(), preventOnSelect);
37960
- }
37961
- },
37962
-
37963
- /**
37964
- * return a Date object of the current selection
37965
- */
37966
- getDate: function()
37967
- {
37968
- return isDate(this._d) ? new Date(this._d.getTime()) : null;
37969
- },
37970
-
37971
- /**
37972
- * set the current selection
37973
- */
37974
- setDate: function(date, preventOnSelect)
37975
- {
37976
- if (!date) {
37977
- this._d = null;
37978
-
37979
- if (this._o.field) {
37980
- this._o.field.value = '';
37981
- fireEvent(this._o.field, 'change', { firedBy: this });
37982
- }
37983
-
37984
- return this.draw();
37985
- }
37986
- if (typeof date === 'string') {
37987
- date = new Date(Date.parse(date));
37988
- }
37989
- if (!isDate(date)) {
37990
- return;
37991
- }
37992
-
37993
- var min = this._o.minDate,
37994
- max = this._o.maxDate;
37995
-
37996
- if (isDate(min) && date < min) {
37997
- date = min;
37998
- } else if (isDate(max) && date > max) {
37999
- date = max;
38000
- }
38001
-
38002
- this._d = new Date(date.getTime());
38003
- setToStartOfDay(this._d);
38004
- this.gotoDate(this._d);
38005
-
38006
- if (this._o.field) {
38007
- this._o.field.value = this.toString();
38008
- fireEvent(this._o.field, 'change', { firedBy: this });
38009
- }
38010
- if (!preventOnSelect && typeof this._o.onSelect === 'function') {
38011
- this._o.onSelect.call(this, this.getDate());
38012
- }
38013
- },
38014
-
38015
- /**
38016
- * change view to a specific date
38017
- */
38018
- gotoDate: function(date)
38019
- {
38020
- var newCalendar = true;
38021
-
38022
- if (!isDate(date)) {
38023
- return;
38024
- }
38025
-
38026
- if (this.calendars) {
38027
- var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
38028
- lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1),
38029
- visibleDate = date.getTime();
38030
- // get the end of the month
38031
- lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1);
38032
- lastVisibleDate.setDate(lastVisibleDate.getDate()-1);
38033
- newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
38034
- }
38035
-
38036
- if (newCalendar) {
38037
- this.calendars = [{
38038
- month: date.getMonth(),
38039
- year: date.getFullYear()
38040
- }];
38041
- if (this._o.mainCalendar === 'right') {
38042
- this.calendars[0].month += 1 - this._o.numberOfMonths;
38043
- }
38044
- }
38045
-
38046
- this.adjustCalendars();
38047
- },
37964
+ if (!isDate(opts.minDate)) {
37965
+ opts.minDate = false;
37966
+ }
37967
+ if (!isDate(opts.maxDate)) {
37968
+ opts.maxDate = false;
37969
+ }
37970
+ if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
37971
+ opts.maxDate = opts.minDate = false;
37972
+ }
37973
+ if (opts.minDate) {
37974
+ this.setMinDate(opts.minDate);
37975
+ }
37976
+ if (opts.maxDate) {
37977
+ this.setMaxDate(opts.maxDate);
37978
+ }
38048
37979
 
38049
- adjustDate: function(sign, days) {
37980
+ if (isArray(opts.yearRange)) {
37981
+ var fallback = new Date().getFullYear() - 10;
37982
+ opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
37983
+ opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
37984
+ } else {
37985
+ opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
37986
+ if (opts.yearRange > 100) {
37987
+ opts.yearRange = 100;
37988
+ }
37989
+ }
38050
37990
 
38051
- var day = this.getDate() || new Date();
38052
- var difference = parseInt(days)*24*60*60*1000;
37991
+ return opts;
37992
+ },
38053
37993
 
38054
- var newDay;
37994
+ /**
37995
+ * return a formatted string of the current selection (using Moment.js if available)
37996
+ */
37997
+ toString: function (format) {
37998
+ format = format || this._o.format;
37999
+ if (!isDate(this._d)) {
38000
+ return '';
38001
+ }
38002
+ if (this._o.toString) {
38003
+ return this._o.toString(this._d, format);
38004
+ }
38005
+ if (hasMoment) {
38006
+ return moment(this._d).format(format);
38007
+ }
38008
+ return this._d.toDateString();
38009
+ },
38010
+
38011
+ /**
38012
+ * return a Moment.js object of the current selection (if available)
38013
+ */
38014
+ getMoment: function () {
38015
+ return hasMoment ? moment(this._d) : null;
38016
+ },
38017
+
38018
+ /**
38019
+ * set the current selection from a Moment.js object (if available)
38020
+ */
38021
+ setMoment: function (date, preventOnSelect) {
38022
+ if (hasMoment && moment.isMoment(date)) {
38023
+ this.setDate(date.toDate(), preventOnSelect);
38024
+ }
38025
+ },
38026
+
38027
+ /**
38028
+ * return a Date object of the current selection
38029
+ */
38030
+ getDate: function () {
38031
+ return isDate(this._d) ? new Date(this._d.getTime()) : null;
38032
+ },
38033
+
38034
+ /**
38035
+ * set the current selection
38036
+ */
38037
+ setDate: function (date, preventOnSelect) {
38038
+ if (!date) {
38039
+ this._d = null;
38040
+
38041
+ if (this._o.field) {
38042
+ this._o.field.value = '';
38043
+ fireEvent(this._o.field, 'change', { firedBy: this });
38044
+ }
38055
38045
 
38056
- if (sign === 'add') {
38057
- newDay = new Date(day.valueOf() + difference);
38058
- } else if (sign === 'subtract') {
38059
- newDay = new Date(day.valueOf() - difference);
38060
- }
38046
+ return this.draw();
38047
+ }
38048
+ if (typeof date === 'string') {
38049
+ date = new Date(Date.parse(date));
38050
+ }
38051
+ if (!isDate(date)) {
38052
+ return;
38053
+ }
38061
38054
 
38062
- this.setDate(newDay);
38063
- },
38055
+ var min = this._o.minDate,
38056
+ max = this._o.maxDate;
38064
38057
 
38065
- adjustCalendars: function() {
38066
- this.calendars[0] = adjustCalendar(this.calendars[0]);
38067
- for (var c = 1; c < this._o.numberOfMonths; c++) {
38068
- this.calendars[c] = adjustCalendar({
38069
- month: this.calendars[0].month + c,
38070
- year: this.calendars[0].year
38071
- });
38072
- }
38073
- this.draw();
38074
- },
38058
+ if (isDate(min) && date < min) {
38059
+ date = min;
38060
+ } else if (isDate(max) && date > max) {
38061
+ date = max;
38062
+ }
38075
38063
 
38076
- gotoToday: function()
38077
- {
38078
- this.gotoDate(new Date());
38079
- },
38064
+ this._d = new Date(date.getTime());
38065
+ setToStartOfDay(this._d);
38066
+ this.gotoDate(this._d);
38080
38067
 
38081
- /**
38082
- * change view to a specific month (zero-index, e.g. 0: January)
38083
- */
38084
- gotoMonth: function(month)
38085
- {
38086
- if (!isNaN(month)) {
38087
- this.calendars[0].month = parseInt(month, 10);
38088
- this.adjustCalendars();
38089
- }
38090
- },
38068
+ if (this._o.field) {
38069
+ this._o.field.value = this.toString();
38070
+ fireEvent(this._o.field, 'change', { firedBy: this });
38071
+ }
38072
+ if (!preventOnSelect && typeof this._o.onSelect === 'function') {
38073
+ this._o.onSelect.call(this, this.getDate());
38074
+ }
38075
+ },
38091
38076
 
38092
- nextMonth: function()
38093
- {
38094
- this.calendars[0].month++;
38095
- this.adjustCalendars();
38096
- },
38077
+ /**
38078
+ * change view to a specific date
38079
+ */
38080
+ gotoDate: function (date) {
38081
+ var newCalendar = true;
38097
38082
 
38098
- prevMonth: function()
38099
- {
38100
- this.calendars[0].month--;
38101
- this.adjustCalendars();
38102
- },
38083
+ if (!isDate(date)) {
38084
+ return;
38085
+ }
38103
38086
 
38104
- /**
38105
- * change view to a specific full year (e.g. "2012")
38106
- */
38107
- gotoYear: function(year)
38108
- {
38109
- if (!isNaN(year)) {
38110
- this.calendars[0].year = parseInt(year, 10);
38111
- this.adjustCalendars();
38112
- }
38113
- },
38087
+ if (this.calendars) {
38088
+ var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
38089
+ lastVisibleDate = new Date(this.calendars[this.calendars.length - 1].year, this.calendars[this.calendars.length - 1].month, 1),
38090
+ visibleDate = date.getTime();
38091
+ // get the end of the month
38092
+ lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1);
38093
+ lastVisibleDate.setDate(lastVisibleDate.getDate() - 1);
38094
+ newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
38095
+ }
38114
38096
 
38115
- /**
38116
- * change the minDate
38117
- */
38118
- setMinDate: function(value)
38119
- {
38120
- if(value instanceof Date) {
38121
- setToStartOfDay(value);
38122
- this._o.minDate = value;
38123
- this._o.minYear = value.getFullYear();
38124
- this._o.minMonth = value.getMonth();
38125
- } else {
38126
- this._o.minDate = defaults.minDate;
38127
- this._o.minYear = defaults.minYear;
38128
- this._o.minMonth = defaults.minMonth;
38129
- this._o.startRange = defaults.startRange;
38130
- }
38097
+ if (newCalendar) {
38098
+ this.calendars = [{
38099
+ month: date.getMonth(),
38100
+ year: date.getFullYear()
38101
+ }];
38102
+ if (this._o.mainCalendar === 'right') {
38103
+ this.calendars[0].month += 1 - this._o.numberOfMonths;
38104
+ }
38105
+ }
38131
38106
 
38132
- this.draw();
38133
- },
38107
+ this.adjustCalendars();
38108
+ },
38134
38109
 
38135
- /**
38136
- * change the maxDate
38137
- */
38138
- setMaxDate: function(value)
38139
- {
38140
- if(value instanceof Date) {
38141
- setToStartOfDay(value);
38142
- this._o.maxDate = value;
38143
- this._o.maxYear = value.getFullYear();
38144
- this._o.maxMonth = value.getMonth();
38145
- } else {
38146
- this._o.maxDate = defaults.maxDate;
38147
- this._o.maxYear = defaults.maxYear;
38148
- this._o.maxMonth = defaults.maxMonth;
38149
- this._o.endRange = defaults.endRange;
38150
- }
38110
+ adjustDate: function (sign, days) {
38151
38111
 
38152
- this.draw();
38153
- },
38112
+ var day = this.getDate() || new Date();
38113
+ var difference = parseInt(days) * 24 * 60 * 60 * 1000;
38154
38114
 
38155
- setStartRange: function(value)
38156
- {
38157
- this._o.startRange = value;
38158
- },
38115
+ var newDay;
38159
38116
 
38160
- setEndRange: function(value)
38161
- {
38162
- this._o.endRange = value;
38163
- },
38117
+ if (sign === 'add') {
38118
+ newDay = new Date(day.valueOf() + difference);
38119
+ } else if (sign === 'subtract') {
38120
+ newDay = new Date(day.valueOf() - difference);
38121
+ }
38164
38122
 
38165
- /**
38166
- * refresh the HTML
38167
- */
38168
- draw: function(force)
38169
- {
38170
- if (!this._v && !force) {
38171
- return;
38172
- }
38173
- var opts = this._o,
38174
- minYear = opts.minYear,
38175
- maxYear = opts.maxYear,
38176
- minMonth = opts.minMonth,
38177
- maxMonth = opts.maxMonth,
38178
- html = '',
38179
- randId;
38180
-
38181
- if (this._y <= minYear) {
38182
- this._y = minYear;
38183
- if (!isNaN(minMonth) && this._m < minMonth) {
38184
- this._m = minMonth;
38185
- }
38186
- }
38187
- if (this._y >= maxYear) {
38188
- this._y = maxYear;
38189
- if (!isNaN(maxMonth) && this._m > maxMonth) {
38190
- this._m = maxMonth;
38191
- }
38192
- }
38123
+ this.setDate(newDay);
38124
+ },
38193
38125
 
38194
- for (var c = 0; c < opts.numberOfMonths; c++) {
38195
- randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
38196
- 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>';
38197
- }
38126
+ adjustCalendars: function () {
38127
+ this.calendars[0] = adjustCalendar(this.calendars[0]);
38128
+ for (var c = 1; c < this._o.numberOfMonths; c++) {
38129
+ this.calendars[c] = adjustCalendar({
38130
+ month: this.calendars[0].month + c,
38131
+ year: this.calendars[0].year
38132
+ });
38133
+ }
38134
+ this.draw();
38135
+ },
38136
+
38137
+ gotoToday: function () {
38138
+ this.gotoDate(new Date());
38139
+ },
38140
+
38141
+ /**
38142
+ * change view to a specific month (zero-index, e.g. 0: January)
38143
+ */
38144
+ gotoMonth: function (month) {
38145
+ if (!isNaN(month)) {
38146
+ this.calendars[0].month = parseInt(month, 10);
38147
+ this.adjustCalendars();
38148
+ }
38149
+ },
38150
+
38151
+ nextMonth: function () {
38152
+ this.calendars[0].month++;
38153
+ this.adjustCalendars();
38154
+ },
38155
+
38156
+ prevMonth: function () {
38157
+ this.calendars[0].month--;
38158
+ this.adjustCalendars();
38159
+ },
38160
+
38161
+ /**
38162
+ * change view to a specific full year (e.g. "2012")
38163
+ */
38164
+ gotoYear: function (year) {
38165
+ if (!isNaN(year)) {
38166
+ this.calendars[0].year = parseInt(year, 10);
38167
+ this.adjustCalendars();
38168
+ }
38169
+ },
38170
+
38171
+ /**
38172
+ * change the minDate
38173
+ */
38174
+ setMinDate: function (value) {
38175
+ if (value instanceof Date) {
38176
+ setToStartOfDay(value);
38177
+ this._o.minDate = value;
38178
+ this._o.minYear = value.getFullYear();
38179
+ this._o.minMonth = value.getMonth();
38180
+ } else {
38181
+ this._o.minDate = defaults.minDate;
38182
+ this._o.minYear = defaults.minYear;
38183
+ this._o.minMonth = defaults.minMonth;
38184
+ this._o.startRange = defaults.startRange;
38185
+ }
38198
38186
 
38199
- this.el.innerHTML = html;
38187
+ this.draw();
38188
+ },
38189
+
38190
+ /**
38191
+ * change the maxDate
38192
+ */
38193
+ setMaxDate: function (value) {
38194
+ if (value instanceof Date) {
38195
+ setToStartOfDay(value);
38196
+ this._o.maxDate = value;
38197
+ this._o.maxYear = value.getFullYear();
38198
+ this._o.maxMonth = value.getMonth();
38199
+ } else {
38200
+ this._o.maxDate = defaults.maxDate;
38201
+ this._o.maxYear = defaults.maxYear;
38202
+ this._o.maxMonth = defaults.maxMonth;
38203
+ this._o.endRange = defaults.endRange;
38204
+ }
38200
38205
 
38201
- if (opts.bound) {
38202
- if(opts.field.type !== 'hidden') {
38203
- sto(function() {
38204
- opts.trigger.focus();
38205
- }, 1);
38206
- }
38207
- }
38206
+ this.draw();
38207
+ },
38208
38208
 
38209
- if (typeof this._o.onDraw === 'function') {
38210
- this._o.onDraw(this);
38211
- }
38209
+ setStartRange: function (value) {
38210
+ this._o.startRange = value;
38211
+ },
38212
38212
 
38213
- if (opts.bound) {
38214
- // let the screen reader user know to use arrow keys
38215
- opts.field.setAttribute('aria-label', 'Use the arrow keys to pick a date');
38216
- }
38217
- },
38213
+ setEndRange: function (value) {
38214
+ this._o.endRange = value;
38215
+ },
38218
38216
 
38219
- adjustPosition: function()
38220
- {
38221
- var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect;
38217
+ /**
38218
+ * refresh the HTML
38219
+ */
38220
+ draw: function (force) {
38221
+ if (!this._v && !force) {
38222
+ return;
38223
+ }
38224
+ var opts = this._o,
38225
+ minYear = opts.minYear,
38226
+ maxYear = opts.maxYear,
38227
+ minMonth = opts.minMonth,
38228
+ maxMonth = opts.maxMonth,
38229
+ html = '',
38230
+ randId;
38231
+
38232
+ if (this._y <= minYear) {
38233
+ this._y = minYear;
38234
+ if (!isNaN(minMonth) && this._m < minMonth) {
38235
+ this._m = minMonth;
38236
+ }
38237
+ }
38238
+ if (this._y >= maxYear) {
38239
+ this._y = maxYear;
38240
+ if (!isNaN(maxMonth) && this._m > maxMonth) {
38241
+ this._m = maxMonth;
38242
+ }
38243
+ }
38222
38244
 
38223
- if (this._o.container) return;
38245
+ for (var c = 0; c < opts.numberOfMonths; c++) {
38246
+ randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
38247
+ 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>';
38248
+ }
38224
38249
 
38225
- this.el.style.position = 'absolute';
38250
+ this.el.innerHTML = html;
38226
38251
 
38227
- field = this._o.trigger;
38228
- pEl = field;
38229
- width = this.el.offsetWidth;
38230
- height = this.el.offsetHeight;
38231
- viewportWidth = window.innerWidth || document.documentElement.clientWidth;
38232
- viewportHeight = window.innerHeight || document.documentElement.clientHeight;
38233
- scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
38252
+ if (opts.bound) {
38253
+ if (opts.field.type !== 'hidden') {
38254
+ sto(function () {
38255
+ opts.trigger.focus();
38256
+ }, 1);
38257
+ }
38258
+ }
38234
38259
 
38235
- if (typeof field.getBoundingClientRect === 'function') {
38236
- clientRect = field.getBoundingClientRect();
38237
- left = clientRect.left + window.pageXOffset;
38238
- top = clientRect.bottom + window.pageYOffset;
38239
- } else {
38240
- left = pEl.offsetLeft;
38241
- top = pEl.offsetTop + pEl.offsetHeight;
38242
- while((pEl = pEl.offsetParent)) {
38243
- left += pEl.offsetLeft;
38244
- top += pEl.offsetTop;
38245
- }
38246
- }
38260
+ if (typeof this._o.onDraw === 'function') {
38261
+ this._o.onDraw(this);
38262
+ }
38247
38263
 
38248
- // default position is bottom & left
38249
- if ((this._o.reposition && left + width > viewportWidth) ||
38250
- (
38251
- this._o.position.indexOf('right') > -1 &&
38252
- left - width + field.offsetWidth > 0
38253
- )
38254
- ) {
38255
- left = left - width + field.offsetWidth;
38256
- }
38257
- if ((this._o.reposition && top + height > viewportHeight + scrollTop) ||
38258
- (
38259
- this._o.position.indexOf('top') > -1 &&
38260
- top - height - field.offsetHeight > 0
38261
- )
38262
- ) {
38263
- top = top - height - field.offsetHeight;
38264
- }
38264
+ if (opts.bound) {
38265
+ // let the screen reader user know to use arrow keys
38266
+ opts.field.setAttribute('aria-label', 'Use the arrow keys to pick a date');
38267
+ }
38268
+ },
38269
+
38270
+ adjustPosition: function () {
38271
+ var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect;
38272
+
38273
+ if (this._o.container) return;
38274
+
38275
+ this.el.style.position = 'absolute';
38276
+
38277
+ field = this._o.trigger;
38278
+ pEl = field;
38279
+ width = this.el.offsetWidth;
38280
+ height = this.el.offsetHeight;
38281
+ viewportWidth = window.innerWidth || document.documentElement.clientWidth;
38282
+ viewportHeight = window.innerHeight || document.documentElement.clientHeight;
38283
+ scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
38284
+
38285
+ if (typeof field.getBoundingClientRect === 'function') {
38286
+ clientRect = field.getBoundingClientRect();
38287
+ left = clientRect.left + window.pageXOffset;
38288
+ top = clientRect.bottom + window.pageYOffset;
38289
+ } else {
38290
+ left = pEl.offsetLeft;
38291
+ top = pEl.offsetTop + pEl.offsetHeight;
38292
+ while ((pEl = pEl.offsetParent)) {
38293
+ left += pEl.offsetLeft;
38294
+ top += pEl.offsetTop;
38295
+ }
38296
+ }
38265
38297
 
38266
- this.el.style.left = left + 'px';
38267
- this.el.style.top = top + 'px';
38268
- },
38298
+ // default position is bottom & left
38299
+ if ((this._o.reposition && left + width > viewportWidth) ||
38300
+ (
38301
+ this._o.position.indexOf('right') > -1 &&
38302
+ left - width + field.offsetWidth > 0
38303
+ )
38304
+ ) {
38305
+ left = left - width + field.offsetWidth;
38306
+ }
38307
+ if ((this._o.reposition && top + height > viewportHeight + scrollTop) ||
38308
+ (
38309
+ this._o.position.indexOf('top') > -1 &&
38310
+ top - height - field.offsetHeight > 0
38311
+ )
38312
+ ) {
38313
+ top = top - height - field.offsetHeight;
38314
+ }
38269
38315
 
38270
- /**
38271
- * render HTML for a particular month
38272
- */
38273
- render: function(year, month, randId)
38274
- {
38275
- var opts = this._o,
38276
- now = new Date(),
38277
- days = getDaysInMonth(year, month),
38278
- before = new Date(year, month, 1).getDay(),
38279
- data = [],
38280
- row = [];
38281
- setToStartOfDay(now);
38282
- if (opts.firstDay > 0) {
38283
- before -= opts.firstDay;
38284
- if (before < 0) {
38285
- before += 7;
38286
- }
38287
- }
38288
- var previousMonth = month === 0 ? 11 : month - 1,
38289
- nextMonth = month === 11 ? 0 : month + 1,
38290
- yearOfPreviousMonth = month === 0 ? year - 1 : year,
38291
- yearOfNextMonth = month === 11 ? year + 1 : year,
38292
- daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth);
38293
- var cells = days + before,
38294
- after = cells;
38295
- while(after > 7) {
38296
- after -= 7;
38297
- }
38298
- cells += 7 - after;
38299
- var isWeekSelected = false;
38300
- for (var i = 0, r = 0; i < cells; i++)
38301
- {
38302
- var day = new Date(year, month, 1 + (i - before)),
38303
- isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
38304
- isToday = compareDates(day, now),
38305
- hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
38306
- isEmpty = i < before || i >= (days + before),
38307
- dayNumber = 1 + (i - before),
38308
- monthNumber = month,
38309
- yearNumber = year,
38310
- isStartRange = opts.startRange && compareDates(opts.startRange, day),
38311
- isEndRange = opts.endRange && compareDates(opts.endRange, day),
38312
- isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
38313
- isDisabled = (opts.minDate && day < opts.minDate) ||
38314
- (opts.maxDate && day > opts.maxDate) ||
38315
- (opts.disableWeekends && isWeekend(day)) ||
38316
- (opts.disableDayFn && opts.disableDayFn(day));
38317
-
38318
- if (isEmpty) {
38319
- if (i < before) {
38320
- dayNumber = daysInPreviousMonth + dayNumber;
38321
- monthNumber = previousMonth;
38322
- yearNumber = yearOfPreviousMonth;
38323
- } else {
38324
- dayNumber = dayNumber - days;
38325
- monthNumber = nextMonth;
38326
- yearNumber = yearOfNextMonth;
38327
- }
38328
- }
38316
+ this.el.style.left = left + 'px';
38317
+ this.el.style.top = top + 'px';
38318
+ },
38319
+
38320
+ /**
38321
+ * render HTML for a particular month
38322
+ */
38323
+ render: function (year, month, randId) {
38324
+ var opts = this._o,
38325
+ now = new Date(),
38326
+ days = getDaysInMonth(year, month),
38327
+ before = new Date(year, month, 1).getDay(),
38328
+ data = [],
38329
+ row = [];
38330
+ setToStartOfDay(now);
38331
+ if (opts.firstDay > 0) {
38332
+ before -= opts.firstDay;
38333
+ if (before < 0) {
38334
+ before += 7;
38335
+ }
38336
+ }
38337
+ var previousMonth = month === 0 ? 11 : month - 1,
38338
+ nextMonth = month === 11 ? 0 : month + 1,
38339
+ yearOfPreviousMonth = month === 0 ? year - 1 : year,
38340
+ yearOfNextMonth = month === 11 ? year + 1 : year,
38341
+ daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth);
38342
+ var cells = days + before,
38343
+ after = cells;
38344
+ while (after > 7) {
38345
+ after -= 7;
38346
+ }
38347
+ cells += 7 - after;
38348
+ var isWeekSelected = false;
38349
+ for (var i = 0, r = 0; i < cells; i++) {
38350
+ var day = new Date(year, month, 1 + (i - before)),
38351
+ isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
38352
+ isToday = compareDates(day, now),
38353
+ hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
38354
+ isEmpty = i < before || i >= (days + before),
38355
+ dayNumber = 1 + (i - before),
38356
+ monthNumber = month,
38357
+ yearNumber = year,
38358
+ isStartRange = opts.startRange && compareDates(opts.startRange, day),
38359
+ isEndRange = opts.endRange && compareDates(opts.endRange, day),
38360
+ isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
38361
+ isDisabled = (opts.minDate && day < opts.minDate) ||
38362
+ (opts.maxDate && day > opts.maxDate) ||
38363
+ (opts.disableWeekends && isWeekend(day)) ||
38364
+ (opts.disableDayFn && opts.disableDayFn(day));
38365
+
38366
+ if (isEmpty) {
38367
+ if (i < before) {
38368
+ dayNumber = daysInPreviousMonth + dayNumber;
38369
+ monthNumber = previousMonth;
38370
+ yearNumber = yearOfPreviousMonth;
38371
+ } else {
38372
+ dayNumber = dayNumber - days;
38373
+ monthNumber = nextMonth;
38374
+ yearNumber = yearOfNextMonth;
38375
+ }
38376
+ }
38329
38377
 
38330
- var dayConfig = {
38331
- day: dayNumber,
38332
- month: monthNumber,
38333
- year: yearNumber,
38334
- hasEvent: hasEvent,
38335
- isSelected: isSelected,
38336
- isToday: isToday,
38337
- isDisabled: isDisabled,
38338
- isEmpty: isEmpty,
38339
- isStartRange: isStartRange,
38340
- isEndRange: isEndRange,
38341
- isInRange: isInRange,
38342
- showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths,
38343
- enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths
38344
- };
38378
+ var dayConfig = {
38379
+ day: dayNumber,
38380
+ month: monthNumber,
38381
+ year: yearNumber,
38382
+ hasEvent: hasEvent,
38383
+ isSelected: isSelected,
38384
+ isToday: isToday,
38385
+ isDisabled: isDisabled,
38386
+ isEmpty: isEmpty,
38387
+ isStartRange: isStartRange,
38388
+ isEndRange: isEndRange,
38389
+ isInRange: isInRange,
38390
+ showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths,
38391
+ enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths
38392
+ };
38393
+
38394
+ if (opts.pickWholeWeek && isSelected) {
38395
+ isWeekSelected = true;
38396
+ }
38345
38397
 
38346
- if (opts.pickWholeWeek && isSelected) {
38347
- isWeekSelected = true;
38348
- }
38398
+ row.push(renderDay(dayConfig));
38349
38399
 
38350
- row.push(renderDay(dayConfig));
38400
+ if (++r === 7) {
38401
+ if (opts.showWeekNumber) {
38402
+ row.unshift(renderWeek(i - before, month, year));
38403
+ }
38404
+ data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected));
38405
+ row = [];
38406
+ r = 0;
38407
+ isWeekSelected = false;
38408
+ }
38409
+ }
38410
+ return renderTable(opts, data, randId);
38411
+ },
38412
+
38413
+ isVisible: function () {
38414
+ return this._v;
38415
+ },
38416
+
38417
+ show: function () {
38418
+ if (!this.isVisible()) {
38419
+ this._v = true;
38420
+ this.draw();
38421
+ removeClass(this.el, 'is-hidden');
38422
+ if (this._o.bound) {
38423
+ addEvent(document, 'click', this._onClick);
38424
+ this.adjustPosition();
38425
+ }
38426
+ if (typeof this._o.onOpen === 'function') {
38427
+ this._o.onOpen.call(this);
38428
+ }
38429
+ }
38430
+ },
38351
38431
 
38352
- if (++r === 7) {
38353
- if (opts.showWeekNumber) {
38354
- row.unshift(renderWeek(i - before, month, year));
38432
+ hide: function () {
38433
+ var v = this._v;
38434
+ if (v !== false) {
38435
+ if (this._o.bound) {
38436
+ removeEvent(document, 'click', this._onClick);
38437
+ }
38438
+ this.el.style.position = 'static'; // reset
38439
+ this.el.style.left = 'auto';
38440
+ this.el.style.top = 'auto';
38441
+ addClass(this.el, 'is-hidden');
38442
+ this._v = false;
38443
+ if (v !== undefined && typeof this._o.onClose === 'function') {
38444
+ this._o.onClose.call(this);
38445
+ }
38446
+ }
38447
+ },
38448
+
38449
+ /**
38450
+ * GAME OVER
38451
+ */
38452
+ destroy: function () {
38453
+ var opts = this._o;
38454
+
38455
+ this.hide();
38456
+ removeEvent(this.el, 'mousedown', this._onMouseDown, true);
38457
+ removeEvent(this.el, 'touchend', this._onMouseDown, true);
38458
+ removeEvent(this.el, 'change', this._onChange);
38459
+ if (opts.keyboardInput) {
38460
+ removeEvent(document, 'keydown', this._onKeyChange);
38461
+ }
38462
+ if (opts.field) {
38463
+ removeEvent(opts.field, 'change', this._onInputChange);
38464
+ if (opts.bound) {
38465
+ removeEvent(opts.trigger, 'click', this._onInputClick);
38466
+ removeEvent(opts.trigger, 'focus', this._onInputFocus);
38467
+ removeEvent(opts.trigger, 'blur', this._onInputBlur);
38468
+ }
38469
+ }
38470
+ if (this.el.parentNode) {
38471
+ this.el.parentNode.removeChild(this.el);
38472
+ }
38355
38473
  }
38356
- data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected));
38357
- row = [];
38358
- r = 0;
38359
- isWeekSelected = false;
38360
- }
38361
- }
38362
- return renderTable(opts, data, randId);
38363
- },
38364
-
38365
- isVisible: function()
38366
- {
38367
- return this._v;
38368
- },
38369
38474
 
38370
- show: function()
38371
- {
38372
- if (!this.isVisible()) {
38373
- this._v = true;
38374
- this.draw();
38375
- removeClass(this.el, 'is-hidden');
38376
- if (this._o.bound) {
38377
- addEvent(document, 'click', this._onClick);
38378
- this.adjustPosition();
38379
- }
38380
- if (typeof this._o.onOpen === 'function') {
38381
- this._o.onOpen.call(this);
38382
- }
38383
- }
38384
- },
38475
+ };
38385
38476
 
38386
- hide: function()
38387
- {
38388
- var v = this._v;
38389
- if (v !== false) {
38390
- if (this._o.bound) {
38391
- removeEvent(document, 'click', this._onClick);
38392
- }
38393
- this.el.style.position = 'static'; // reset
38394
- this.el.style.left = 'auto';
38395
- this.el.style.top = 'auto';
38396
- addClass(this.el, 'is-hidden');
38397
- this._v = false;
38398
- if (v !== undefined && typeof this._o.onClose === 'function') {
38399
- this._o.onClose.call(this);
38400
- }
38401
- }
38402
- },
38403
-
38404
- /**
38405
- * GAME OVER
38406
- */
38407
- destroy: function()
38408
- {
38409
- var opts = this._o;
38410
-
38411
- this.hide();
38412
- removeEvent(this.el, 'mousedown', this._onMouseDown, true);
38413
- removeEvent(this.el, 'touchend', this._onMouseDown, true);
38414
- removeEvent(this.el, 'change', this._onChange);
38415
- if (opts.keyboardInput) {
38416
- removeEvent(document, 'keydown', this._onKeyChange);
38417
- }
38418
- if (opts.field) {
38419
- removeEvent(opts.field, 'change', this._onInputChange);
38420
- if (opts.bound) {
38421
- removeEvent(opts.trigger, 'click', this._onInputClick);
38422
- removeEvent(opts.trigger, 'focus', this._onInputFocus);
38423
- removeEvent(opts.trigger, 'blur', this._onInputBlur);
38424
- }
38425
- }
38426
- if (this.el.parentNode) {
38427
- this.el.parentNode.removeChild(this.el);
38428
- }
38429
- }
38430
-
38431
- };
38432
-
38433
- return Pikaday;
38434
- }));
38477
+ return Pikaday;
38478
+ }));
38435
38479
  } (pikaday$1));
38436
38480
  return pikaday$1.exports;
38437
38481
  }
@@ -38439,53 +38483,26 @@
38439
38483
  var pikadayExports = /*@__PURE__*/ requirePikaday();
38440
38484
  var Pikaday = /*@__PURE__*/getDefaultExportFromCjs(pikadayExports);
38441
38485
 
38442
- var momentExports = requireMoment();
38443
- var moment = /*@__PURE__*/getDefaultExportFromCjs(momentExports);
38444
-
38445
- class TimezonePicker extends ChartComponent {
38446
- constructor(renderTarget) {
38447
- super(renderTarget);
38448
- 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"];
38486
+ // Ensure moment is available globally for Pikaday
38487
+ if (typeof window !== 'undefined') {
38488
+ window.moment = moment;
38489
+ }
38490
+ // Export a function to safely create Pikaday instances
38491
+ function createPikaday(options) {
38492
+ if (typeof window === 'undefined') {
38493
+ console.warn('Pikaday requires a browser environment');
38494
+ return null;
38449
38495
  }
38450
- sortTimezones() {
38451
- let filteredTimezones = this.timeZones.filter((tz) => {
38452
- return !(tz.toLowerCase() == 'local' || tz == 'UTC');
38453
- });
38454
- filteredTimezones.sort((a, b) => {
38455
- let aOffset = moment$1.tz(new Date(), a.split(' ').join('_')).utcOffset();
38456
- let bOffset = moment$1.tz(new Date(), b.split(' ').join('_')).utcOffset();
38457
- if (aOffset < bOffset) {
38458
- return -1;
38459
- }
38460
- if (aOffset > bOffset) {
38461
- return 1;
38462
- }
38463
- return 0;
38464
- });
38465
- this.timeZones = ['Local', 'UTC'].concat(filteredTimezones);
38496
+ const Pikaday = window.Pikaday;
38497
+ if (!Pikaday) {
38498
+ console.error('Pikaday not available. Make sure pikaday.js is loaded.');
38499
+ return null;
38466
38500
  }
38467
- render(onTimezoneSelect, defaultTimeZone = null) {
38468
- this.targetElement = select(this.renderTarget)
38469
- .classed("tsi-timezonePicker", true);
38470
- var timezoneSelection = this.targetElement.append("select")
38471
- .attr("class", "tsi-timezonePicker tsi-select");
38472
- this.sortTimezones();
38473
- var options = timezoneSelection.selectAll("option")
38474
- .data(this.timeZones)
38475
- .enter()
38476
- .append("option")
38477
- .attr('value', d => d)
38478
- .text((tz) => Utils.convertTimezoneToLabel(tz, this.getString('Local')));
38479
- timezoneSelection.on("change", function (d) {
38480
- var timezone = select(this).node().value.replace(/\s/g, "_");
38481
- onTimezoneSelect(timezone);
38482
- });
38483
- defaultTimeZone = defaultTimeZone.replace(/_/g, " ");
38484
- if (defaultTimeZone != null) {
38485
- options.filter((d) => d == defaultTimeZone).attr("selected", true);
38486
- }
38487
- return;
38501
+ if (!moment || !window.moment) {
38502
+ console.error('Moment.js not available. Pikaday requires moment.js.');
38503
+ return null;
38488
38504
  }
38505
+ return new Pikaday(options);
38489
38506
  }
38490
38507
 
38491
38508
  class DateTimePicker extends ChartComponent {
@@ -38758,8 +38775,8 @@
38758
38775
  weekdays: moment.localeData().weekdays(),
38759
38776
  weekdaysShort: moment.localeData().weekdaysMin()
38760
38777
  };
38761
- //@ts-ignore
38762
- this.calendarPicker = new Pikaday({
38778
+ // Use the safe Pikaday wrapper
38779
+ this.calendarPicker = createPikaday({
38763
38780
  bound: false,
38764
38781
  container: this.calendar.node(),
38765
38782
  field: this.calendar.node(),
@@ -38795,6 +38812,11 @@
38795
38812
  maxDate: this.convertToCalendarDate(this.maxMillis),
38796
38813
  defaultDate: Utils.adjustDateFromTimezoneOffset(new Date(this.fromMillis))
38797
38814
  });
38815
+ // Check if Pikaday was created successfully
38816
+ if (!this.calendarPicker) {
38817
+ console.error('Failed to create Pikaday calendar. Check moment.js availability.');
38818
+ return;
38819
+ }
38798
38820
  }
38799
38821
  setSelectedQuickTimes() {
38800
38822
  let isSelected = d => {
@@ -39203,6 +39225,7 @@
39203
39225
  }
39204
39226
  //transformation of buckets created by the UX client to buckets for the availabilityChart
39205
39227
  createDisplayBuckets(fromMillis, toMillis) {
39228
+ //TODO: "" key is confusing, should be "count" or something similar
39206
39229
  var keysInRange = Object.keys(this.transformedAvailability[0].availabilityCount[""]).reduce((inRangeObj, timestamp, i, timestamps) => {
39207
39230
  var currTSMillis = (new Date(timestamp)).valueOf();
39208
39231
  var nextTSMillis = currTSMillis + this.bucketSize;
@@ -39255,6 +39278,7 @@
39255
39278
  this.bucketSize = null;
39256
39279
  }
39257
39280
  }
39281
+ //TODO: should have proper types for parameters
39258
39282
  render(transformedAvailability, chartOptions, rawAvailability = {}) {
39259
39283
  this.setChartOptions(chartOptions);
39260
39284
  this.rawAvailability = rawAvailability;
@@ -45009,6 +45033,10 @@
45009
45033
  }
45010
45034
  }
45011
45035
 
45036
+ // Ensure moment is available globally for Pikaday and other components
45037
+ if (typeof window !== 'undefined') {
45038
+ window.moment = moment;
45039
+ }
45012
45040
  class UXClient {
45013
45041
  constructor() {
45014
45042
  // Public facing components have class constructors exposed as public UXClient members.