fullcalendar.io-rails 2.3.2 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e0c3f8226be35a93a659007d0fa20fd66a6ff65
4
- data.tar.gz: ae678572c60154cf91d4519c95315749b13fa9e8
3
+ metadata.gz: 3e95fa760c253b1bcbbdaacc80fd045d1126a39c
4
+ data.tar.gz: 44c65ae292b3c364da1454c5a7838185105f2a69
5
5
  SHA512:
6
- metadata.gz: ac1647ad46ab72f4aedd60e60825dd7cbb1e76a255969f4a0bc2700e04772e0e2d6e213a3e17b121ae62f3712963cc9e036e35cf38e28cb809ef85e093477d4e
7
- data.tar.gz: 1b987ab4011b943ac1fef1f48f7b9111de448f46efbd0abe68cf62fa52bc4fd46072d9aa66a5ebbb56f58849890e81251176338a7ae0128411d164b4c2a28cb8
6
+ metadata.gz: 0aae9e839f7247dac108bb1b750543e22dc486f377ca34b70026670f2b7e103da8e57639158cab448d6ae6ddc9bfceccc469d43e07a6da7ee4b235fa1d2f2299
7
+ data.tar.gz: 28ae98115d58895d0f313f312194b4f9e293ba4e0ce6fab912d6df267ec9b7ab476b8dfffdf71ad44794a87dd9013b7787267dfcd829090812ad3ca07d5e6132
@@ -1,5 +1,5 @@
1
1
  module Fullcalendario
2
2
  module Rails
3
- VERSION = "2.3.2"
3
+ VERSION = "2.4.0"
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * FullCalendar v2.3.2
2
+ * FullCalendar v2.4.0
3
3
  * Docs & License: http://fullcalendar.io/
4
4
  * (c) 2015 Adam Shaw
5
5
  */
@@ -18,7 +18,7 @@
18
18
 
19
19
  ;;
20
20
 
21
- var fc = $.fullCalendar = { version: "2.3.2" };
21
+ var fc = $.fullCalendar = { version: "2.4.0" };
22
22
  var fcViews = fc.views = {};
23
23
 
24
24
 
@@ -419,6 +419,7 @@ function isPrimaryMouseButton(ev) {
419
419
  /* Geometry
420
420
  ----------------------------------------------------------------------------------------------------------------------*/
421
421
 
422
+ fc.intersectRects = intersectRects;
422
423
 
423
424
  // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
424
425
  function intersectRects(rect1, rect2) {
@@ -463,6 +464,90 @@ function diffPoints(point1, point2) {
463
464
  }
464
465
 
465
466
 
467
+ /* Object Ordering by Field
468
+ ----------------------------------------------------------------------------------------------------------------------*/
469
+
470
+ fc.parseFieldSpecs = parseFieldSpecs;
471
+ fc.compareByFieldSpecs = compareByFieldSpecs;
472
+ fc.compareByFieldSpec = compareByFieldSpec;
473
+ fc.flexibleCompare = flexibleCompare;
474
+
475
+
476
+ function parseFieldSpecs(input) {
477
+ var specs = [];
478
+ var tokens = [];
479
+ var i, token;
480
+
481
+ if (typeof input === 'string') {
482
+ tokens = input.split(/\s*,\s*/);
483
+ }
484
+ else if (typeof input === 'function') {
485
+ tokens = [ input ];
486
+ }
487
+ else if ($.isArray(input)) {
488
+ tokens = input;
489
+ }
490
+
491
+ for (i = 0; i < tokens.length; i++) {
492
+ token = tokens[i];
493
+
494
+ if (typeof token === 'string') {
495
+ specs.push(
496
+ token.charAt(0) == '-' ?
497
+ { field: token.substring(1), order: -1 } :
498
+ { field: token, order: 1 }
499
+ );
500
+ }
501
+ else if (typeof token === 'function') {
502
+ specs.push({ func: token });
503
+ }
504
+ }
505
+
506
+ return specs;
507
+ }
508
+
509
+
510
+ function compareByFieldSpecs(obj1, obj2, fieldSpecs) {
511
+ var i;
512
+ var cmp;
513
+
514
+ for (i = 0; i < fieldSpecs.length; i++) {
515
+ cmp = compareByFieldSpec(obj1, obj2, fieldSpecs[i]);
516
+ if (cmp) {
517
+ return cmp;
518
+ }
519
+ }
520
+
521
+ return 0;
522
+ }
523
+
524
+
525
+ function compareByFieldSpec(obj1, obj2, fieldSpec) {
526
+ if (fieldSpec.func) {
527
+ return fieldSpec.func(obj1, obj2);
528
+ }
529
+ return flexibleCompare(obj1[fieldSpec.field], obj2[fieldSpec.field]) *
530
+ (fieldSpec.order || 1);
531
+ }
532
+
533
+
534
+ function flexibleCompare(a, b) {
535
+ if (!a && !b) {
536
+ return 0;
537
+ }
538
+ if (b == null) {
539
+ return -1;
540
+ }
541
+ if (a == null) {
542
+ return 1;
543
+ }
544
+ if ($.type(a) === 'string' || $.type(b) === 'string') {
545
+ return String(a).localeCompare(String(b));
546
+ }
547
+ return a - b;
548
+ }
549
+
550
+
466
551
  /* FullCalendar-specific Misc Utilities
467
552
  ----------------------------------------------------------------------------------------------------------------------*/
468
553
 
@@ -512,6 +597,9 @@ function intersectionToSeg(subjectRange, constraintRange) {
512
597
  ----------------------------------------------------------------------------------------------------------------------*/
513
598
 
514
599
  fc.computeIntervalUnit = computeIntervalUnit;
600
+ fc.divideRangeByDuration = divideRangeByDuration;
601
+ fc.divideDurationByDuration = divideDurationByDuration;
602
+ fc.multiplyDuration = multiplyDuration;
515
603
  fc.durationHasTime = durationHasTime;
516
604
 
517
605
  var dayIDs = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
@@ -583,6 +671,55 @@ function computeRangeAs(unit, start, end) {
583
671
  }
584
672
 
585
673
 
674
+ // Intelligently divides a range (specified by a start/end params) by a duration
675
+ function divideRangeByDuration(start, end, dur) {
676
+ var months;
677
+
678
+ if (durationHasTime(dur)) {
679
+ return (end - start) / dur;
680
+ }
681
+ months = dur.asMonths();
682
+ if (Math.abs(months) >= 1 && isInt(months)) {
683
+ return end.diff(start, 'months', true) / months;
684
+ }
685
+ return end.diff(start, 'days', true) / dur.asDays();
686
+ }
687
+
688
+
689
+ // Intelligently divides one duration by another
690
+ function divideDurationByDuration(dur1, dur2) {
691
+ var months1, months2;
692
+
693
+ if (durationHasTime(dur1) || durationHasTime(dur2)) {
694
+ return dur1 / dur2;
695
+ }
696
+ months1 = dur1.asMonths();
697
+ months2 = dur2.asMonths();
698
+ if (
699
+ Math.abs(months1) >= 1 && isInt(months1) &&
700
+ Math.abs(months2) >= 1 && isInt(months2)
701
+ ) {
702
+ return months1 / months2;
703
+ }
704
+ return dur1.asDays() / dur2.asDays();
705
+ }
706
+
707
+
708
+ // Intelligently multiplies a duration by a number
709
+ function multiplyDuration(dur, n) {
710
+ var months;
711
+
712
+ if (durationHasTime(dur)) {
713
+ return moment.duration(dur * n);
714
+ }
715
+ months = dur.asMonths();
716
+ if (Math.abs(months) >= 1 && isInt(months)) {
717
+ return moment.duration({ months: months * n });
718
+ }
719
+ return moment.duration({ days: dur.asDays() * n });
720
+ }
721
+
722
+
586
723
  // Returns a boolean about whether the given duration has any time parts (hours/minutes/seconds/ms)
587
724
  function durationHasTime(dur) {
588
725
  return Boolean(dur.hours() || dur.minutes() || dur.seconds() || dur.milliseconds());
@@ -600,6 +737,29 @@ function isTimeString(str) {
600
737
  }
601
738
 
602
739
 
740
+ /* Logging and Debug
741
+ ----------------------------------------------------------------------------------------------------------------------*/
742
+
743
+ fc.log = function() {
744
+ var console = window.console;
745
+
746
+ if (console && console.log) {
747
+ return console.log.apply(console, arguments);
748
+ }
749
+ };
750
+
751
+ fc.warn = function() {
752
+ var console = window.console;
753
+
754
+ if (console && console.warn) {
755
+ return console.warn.apply(console, arguments);
756
+ }
757
+ else {
758
+ return fc.log.apply(fc, arguments);
759
+ }
760
+ };
761
+
762
+
603
763
  /* General Utilities
604
764
  ----------------------------------------------------------------------------------------------------------------------*/
605
765
 
@@ -1592,6 +1752,59 @@ Class.mixin = function(members) {
1592
1752
  };
1593
1753
  ;;
1594
1754
 
1755
+ var Emitter = fc.Emitter = Class.extend({
1756
+
1757
+ callbackHash: null,
1758
+
1759
+
1760
+ on: function(name, callback) {
1761
+ this.getCallbacks(name).add(callback);
1762
+ return this; // for chaining
1763
+ },
1764
+
1765
+
1766
+ off: function(name, callback) {
1767
+ this.getCallbacks(name).remove(callback);
1768
+ return this; // for chaining
1769
+ },
1770
+
1771
+
1772
+ trigger: function(name) { // args...
1773
+ var args = Array.prototype.slice.call(arguments, 1);
1774
+
1775
+ this.triggerWith(name, this, args);
1776
+
1777
+ return this; // for chaining
1778
+ },
1779
+
1780
+
1781
+ triggerWith: function(name, context, args) {
1782
+ var callbacks = this.getCallbacks(name);
1783
+
1784
+ callbacks.fireWith(context, args);
1785
+
1786
+ return this; // for chaining
1787
+ },
1788
+
1789
+
1790
+ getCallbacks: function(name) {
1791
+ var callbacks;
1792
+
1793
+ if (!this.callbackHash) {
1794
+ this.callbackHash = {};
1795
+ }
1796
+
1797
+ callbacks = this.callbackHash[name];
1798
+ if (!callbacks) {
1799
+ callbacks = this.callbackHash[name] = $.Callbacks();
1800
+ }
1801
+
1802
+ return callbacks;
1803
+ }
1804
+
1805
+ });
1806
+ ;;
1807
+
1595
1808
  /* A rectangular panel that is absolutely positioned over other content
1596
1809
  ------------------------------------------------------------------------------------------------------------------------
1597
1810
  Options:
@@ -4389,6 +4602,21 @@ Grid.mixin({
4389
4602
  }
4390
4603
 
4391
4604
  return segs;
4605
+ },
4606
+
4607
+
4608
+ sortSegs: function(segs) {
4609
+ segs.sort(proxy(this, 'compareSegs'));
4610
+ },
4611
+
4612
+
4613
+ // A cmp function for determining which segments should take visual priority
4614
+ // DOES NOT WORK ON INVERTED BACKGROUND EVENTS because they have no eventStartMS/eventDurationMS
4615
+ compareSegs: function(seg1, seg2) {
4616
+ return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first
4617
+ seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
4618
+ seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
4619
+ compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
4392
4620
  }
4393
4621
 
4394
4622
  });
@@ -4433,18 +4661,6 @@ function compareNormalRanges(range1, range2) {
4433
4661
  }
4434
4662
 
4435
4663
 
4436
- // A cmp function for determining which segments should take visual priority
4437
- // DOES NOT WORK ON INVERTED BACKGROUND EVENTS because they have no eventStartMS/eventDurationMS
4438
- function compareSegs(seg1, seg2) {
4439
- return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first
4440
- seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
4441
- seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
4442
- (seg1.event.title || '').localeCompare(seg2.event.title); // tie? alphabetically by title
4443
- }
4444
-
4445
- fc.compareSegs = compareSegs; // export
4446
-
4447
-
4448
4664
  /* External-Dragging-Element Data
4449
4665
  ----------------------------------------------------------------------------------------------------------------------*/
4450
4666
 
@@ -5220,7 +5436,7 @@ DayGrid.mixin({
5220
5436
 
5221
5437
  // Give preference to elements with certain criteria, so they have
5222
5438
  // a chance to be closer to the top.
5223
- segs.sort(compareSegs);
5439
+ this.sortSegs(segs);
5224
5440
 
5225
5441
  for (i = 0; i < segs.length; i++) {
5226
5442
  seg = segs[i];
@@ -5621,7 +5837,7 @@ DayGrid.mixin({
5621
5837
  );
5622
5838
 
5623
5839
  // force an order because eventsToSegs doesn't guarantee one
5624
- segs.sort(compareSegs);
5840
+ this.sortSegs(segs);
5625
5841
 
5626
5842
  return segs;
5627
5843
  },
@@ -5673,7 +5889,8 @@ var TimeGrid = Grid.extend({
5673
5889
  minTime: null, // Duration object that denotes the first visible time of any given day
5674
5890
  maxTime: null, // Duration object that denotes the exclusive visible end time of any given day
5675
5891
  colDates: null, // whole-day dates for each column. left to right
5676
- axisFormat: null, // formatting string for times running along vertical axis
5892
+ labelFormat: null, // formatting string for times running along vertical axis
5893
+ labelInterval: null, // duration of how often a label should be displayed for a slot
5677
5894
 
5678
5895
  dayEls: null, // cells elements in the day-row background
5679
5896
  slatEls: null, // elements running horizontally across all columns
@@ -5734,29 +5951,28 @@ var TimeGrid = Grid.extend({
5734
5951
  var view = this.view;
5735
5952
  var isRTL = this.isRTL;
5736
5953
  var html = '';
5737
- var slotNormal = this.slotDuration.asMinutes() % 15 === 0;
5738
5954
  var slotTime = moment.duration(+this.minTime); // wish there was .clone() for durations
5739
5955
  var slotDate; // will be on the view's first day, but we only care about its time
5740
- var minutes;
5956
+ var isLabeled;
5741
5957
  var axisHtml;
5742
5958
 
5743
5959
  // Calculate the time for each slot
5744
5960
  while (slotTime < this.maxTime) {
5745
- slotDate = this.start.clone().time(slotTime); // will be in UTC but that's good. to avoid DST issues
5746
- minutes = slotDate.minutes();
5961
+ slotDate = this.start.clone().time(slotTime); // after .time() will be in UTC. but that's good, avoids DST issues
5962
+ isLabeled = isInt(divideDurationByDuration(slotTime, this.labelInterval));
5747
5963
 
5748
5964
  axisHtml =
5749
5965
  '<td class="fc-axis fc-time ' + view.widgetContentClass + '" ' + view.axisStyleAttr() + '>' +
5750
- ((!slotNormal || !minutes) ? // if irregular slot duration, or on the hour, then display the time
5966
+ (isLabeled ?
5751
5967
  '<span>' + // for matchCellWidths
5752
- htmlEscape(slotDate.format(this.axisFormat)) +
5968
+ htmlEscape(slotDate.format(this.labelFormat)) +
5753
5969
  '</span>' :
5754
5970
  ''
5755
5971
  ) +
5756
5972
  '</td>';
5757
5973
 
5758
5974
  html +=
5759
- '<tr ' + (!minutes ? '' : 'class="fc-minor"') + '>' +
5975
+ '<tr ' + (isLabeled ? '' : 'class="fc-minor"') + '>' +
5760
5976
  (!isRTL ? axisHtml : '') +
5761
5977
  '<td class="' + view.widgetContentClass + '"/>' +
5762
5978
  (isRTL ? axisHtml : '') +
@@ -5778,6 +5994,7 @@ var TimeGrid = Grid.extend({
5778
5994
  var view = this.view;
5779
5995
  var slotDuration = view.opt('slotDuration');
5780
5996
  var snapDuration = view.opt('snapDuration');
5997
+ var input;
5781
5998
 
5782
5999
  slotDuration = moment.duration(slotDuration);
5783
6000
  snapDuration = snapDuration ? moment.duration(snapDuration) : slotDuration;
@@ -5789,7 +6006,41 @@ var TimeGrid = Grid.extend({
5789
6006
  this.minTime = moment.duration(view.opt('minTime'));
5790
6007
  this.maxTime = moment.duration(view.opt('maxTime'));
5791
6008
 
5792
- this.axisFormat = view.opt('axisFormat') || view.opt('smallTimeFormat');
6009
+ // might be an array value (for TimelineView).
6010
+ // if so, getting the most granular entry (the last one probably).
6011
+ input = view.opt('slotLabelFormat');
6012
+ if ($.isArray(input)) {
6013
+ input = input[input.length - 1];
6014
+ }
6015
+
6016
+ this.labelFormat =
6017
+ input ||
6018
+ view.opt('axisFormat') || // deprecated
6019
+ view.opt('smallTimeFormat'); // the computed default
6020
+
6021
+ input = view.opt('slotLabelInterval');
6022
+ this.labelInterval = input ?
6023
+ moment.duration(input) :
6024
+ this.computeLabelInterval(slotDuration);
6025
+ },
6026
+
6027
+
6028
+ // Computes an automatic value for slotLabelInterval
6029
+ computeLabelInterval: function(slotDuration) {
6030
+ var i;
6031
+ var labelInterval;
6032
+ var slotsPerLabel;
6033
+
6034
+ // find the smallest stock label interval that results in more than one slots-per-label
6035
+ for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
6036
+ labelInterval = moment.duration(AGENDA_STOCK_SUB_DURATIONS[i]);
6037
+ slotsPerLabel = divideDurationByDuration(labelInterval, slotDuration);
6038
+ if (isInt(slotsPerLabel) && slotsPerLabel > 1) {
6039
+ return labelInterval;
6040
+ }
6041
+ }
6042
+
6043
+ return moment.duration(slotDuration); // fall back. clone
5793
6044
  },
5794
6045
 
5795
6046
 
@@ -6209,7 +6460,7 @@ TimeGrid.mixin({
6209
6460
 
6210
6461
  for (col = 0; col < segCols.length; col++) { // iterate each column grouping
6211
6462
  colSegs = segCols[col];
6212
- placeSlotSegs(colSegs); // compute horizontal coordinates, z-index's, and reorder the array
6463
+ this.placeSlotSegs(colSegs); // compute horizontal coordinates, z-index's, and reorder the array
6213
6464
 
6214
6465
  containerEl = $('<div class="fc-event-container"/>');
6215
6466
 
@@ -6235,6 +6486,74 @@ TimeGrid.mixin({
6235
6486
  },
6236
6487
 
6237
6488
 
6489
+ // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
6490
+ // NOTE: Also reorders the given array by date!
6491
+ placeSlotSegs: function(segs) {
6492
+ var levels;
6493
+ var level0;
6494
+ var i;
6495
+
6496
+ this.sortSegs(segs); // order by date
6497
+ levels = buildSlotSegLevels(segs);
6498
+ computeForwardSlotSegs(levels);
6499
+
6500
+ if ((level0 = levels[0])) {
6501
+
6502
+ for (i = 0; i < level0.length; i++) {
6503
+ computeSlotSegPressures(level0[i]);
6504
+ }
6505
+
6506
+ for (i = 0; i < level0.length; i++) {
6507
+ this.computeSlotSegCoords(level0[i], 0, 0);
6508
+ }
6509
+ }
6510
+ },
6511
+
6512
+
6513
+ // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
6514
+ // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
6515
+ // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
6516
+ //
6517
+ // The segment might be part of a "series", which means consecutive segments with the same pressure
6518
+ // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
6519
+ // segments behind this one in the current series, and `seriesBackwardCoord` is the starting
6520
+ // coordinate of the first segment in the series.
6521
+ computeSlotSegCoords: function(seg, seriesBackwardPressure, seriesBackwardCoord) {
6522
+ var forwardSegs = seg.forwardSegs;
6523
+ var i;
6524
+
6525
+ if (seg.forwardCoord === undefined) { // not already computed
6526
+
6527
+ if (!forwardSegs.length) {
6528
+
6529
+ // if there are no forward segments, this segment should butt up against the edge
6530
+ seg.forwardCoord = 1;
6531
+ }
6532
+ else {
6533
+
6534
+ // sort highest pressure first
6535
+ this.sortForwardSlotSegs(forwardSegs);
6536
+
6537
+ // this segment's forwardCoord will be calculated from the backwardCoord of the
6538
+ // highest-pressure forward segment.
6539
+ this.computeSlotSegCoords(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);
6540
+ seg.forwardCoord = forwardSegs[0].backwardCoord;
6541
+ }
6542
+
6543
+ // calculate the backwardCoord from the forwardCoord. consider the series
6544
+ seg.backwardCoord = seg.forwardCoord -
6545
+ (seg.forwardCoord - seriesBackwardCoord) / // available width for series
6546
+ (seriesBackwardPressure + 1); // # of segments in the series
6547
+
6548
+ // use this segment's coordinates to computed the coordinates of the less-pressurized
6549
+ // forward segments
6550
+ for (i=0; i<forwardSegs.length; i++) {
6551
+ this.computeSlotSegCoords(forwardSegs[i], 0, seg.forwardCoord);
6552
+ }
6553
+ }
6554
+ },
6555
+
6556
+
6238
6557
  // Refreshes the CSS top/bottom coordinates for each segment element. Probably after a window resize/zoom.
6239
6558
  // Repositions business hours segs too, so not just for events. Maybe shouldn't be here.
6240
6559
  updateSegVerticals: function() {
@@ -6396,33 +6715,25 @@ TimeGrid.mixin({
6396
6715
  }
6397
6716
 
6398
6717
  return segCols;
6399
- }
6400
-
6401
- });
6402
-
6403
-
6404
- // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
6405
- // NOTE: Also reorders the given array by date!
6406
- function placeSlotSegs(segs) {
6407
- var levels;
6408
- var level0;
6409
- var i;
6718
+ },
6410
6719
 
6411
- segs.sort(compareSegs); // order by date
6412
- levels = buildSlotSegLevels(segs);
6413
- computeForwardSlotSegs(levels);
6414
6720
 
6415
- if ((level0 = levels[0])) {
6721
+ sortForwardSlotSegs: function(forwardSegs) {
6722
+ forwardSegs.sort(proxy(this, 'compareForwardSlotSegs'));
6723
+ },
6416
6724
 
6417
- for (i = 0; i < level0.length; i++) {
6418
- computeSlotSegPressures(level0[i]);
6419
- }
6420
6725
 
6421
- for (i = 0; i < level0.length; i++) {
6422
- computeSlotSegCoords(level0[i], 0, 0);
6423
- }
6726
+ // A cmp function for determining which forward segment to rely on more when computing coordinates.
6727
+ compareForwardSlotSegs: function(seg1, seg2) {
6728
+ // put higher-pressure first
6729
+ return seg2.forwardPressure - seg1.forwardPressure ||
6730
+ // put segments that are closer to initial edge first (and favor ones with no coords yet)
6731
+ (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||
6732
+ // do normal sorting...
6733
+ this.compareSegs(seg1, seg2);
6424
6734
  }
6425
- }
6735
+
6736
+ });
6426
6737
 
6427
6738
 
6428
6739
  // Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is
@@ -6501,50 +6812,6 @@ function computeSlotSegPressures(seg) {
6501
6812
  }
6502
6813
 
6503
6814
 
6504
- // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
6505
- // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
6506
- // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
6507
- //
6508
- // The segment might be part of a "series", which means consecutive segments with the same pressure
6509
- // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
6510
- // segments behind this one in the current series, and `seriesBackwardCoord` is the starting
6511
- // coordinate of the first segment in the series.
6512
- function computeSlotSegCoords(seg, seriesBackwardPressure, seriesBackwardCoord) {
6513
- var forwardSegs = seg.forwardSegs;
6514
- var i;
6515
-
6516
- if (seg.forwardCoord === undefined) { // not already computed
6517
-
6518
- if (!forwardSegs.length) {
6519
-
6520
- // if there are no forward segments, this segment should butt up against the edge
6521
- seg.forwardCoord = 1;
6522
- }
6523
- else {
6524
-
6525
- // sort highest pressure first
6526
- forwardSegs.sort(compareForwardSlotSegs);
6527
-
6528
- // this segment's forwardCoord will be calculated from the backwardCoord of the
6529
- // highest-pressure forward segment.
6530
- computeSlotSegCoords(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);
6531
- seg.forwardCoord = forwardSegs[0].backwardCoord;
6532
- }
6533
-
6534
- // calculate the backwardCoord from the forwardCoord. consider the series
6535
- seg.backwardCoord = seg.forwardCoord -
6536
- (seg.forwardCoord - seriesBackwardCoord) / // available width for series
6537
- (seriesBackwardPressure + 1); // # of segments in the series
6538
-
6539
- // use this segment's coordinates to computed the coordinates of the less-pressurized
6540
- // forward segments
6541
- for (i=0; i<forwardSegs.length; i++) {
6542
- computeSlotSegCoords(forwardSegs[i], 0, seg.forwardCoord);
6543
- }
6544
- }
6545
- }
6546
-
6547
-
6548
6815
  // Find all the segments in `otherSegs` that vertically collide with `seg`.
6549
6816
  // Append into an optionally-supplied `results` array and return.
6550
6817
  function computeSlotSegCollisions(seg, otherSegs, results) {
@@ -6565,17 +6832,6 @@ function isSlotSegCollision(seg1, seg2) {
6565
6832
  return seg1.bottom > seg2.top && seg1.top < seg2.bottom;
6566
6833
  }
6567
6834
 
6568
-
6569
- // A cmp function for determining which forward segment to rely on more when computing coordinates.
6570
- function compareForwardSlotSegs(seg1, seg2) {
6571
- // put higher-pressure first
6572
- return seg2.forwardPressure - seg1.forwardPressure ||
6573
- // put segments that are closer to initial edge first (and favor ones with no coords yet)
6574
- (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||
6575
- // do normal sorting...
6576
- compareSegs(seg1, seg2);
6577
- }
6578
-
6579
6835
  ;;
6580
6836
 
6581
6837
  /* An abstract class from which other views inherit from
@@ -6610,6 +6866,8 @@ var View = fc.View = Class.extend({
6610
6866
  isRTL: false,
6611
6867
  isSelected: false, // boolean whether a range of time is user-selected or not
6612
6868
 
6869
+ eventOrderSpecs: null, // criteria for ordering events when they have same date/time
6870
+
6613
6871
  // subclasses can optionally use a scroll container
6614
6872
  scrollerEl: null, // the element that will most likely scroll when content is too tall
6615
6873
  scrollTop: null, // cached vertical scroll value
@@ -6639,6 +6897,8 @@ var View = fc.View = Class.extend({
6639
6897
  this.initHiddenDays();
6640
6898
  this.isRTL = this.opt('isRTL');
6641
6899
 
6900
+ this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'));
6901
+
6642
6902
  this.documentMousedownProxy = proxy(this, 'documentMousedown');
6643
6903
 
6644
6904
  this.initialize();
@@ -7776,6 +8036,9 @@ var Calendar = fc.Calendar = Class.extend({
7776
8036
  });
7777
8037
 
7778
8038
 
8039
+ Calendar.mixin(Emitter);
8040
+
8041
+
7779
8042
  function Calendar_constructor(element, overrides) {
7780
8043
  var t = this;
7781
8044
 
@@ -8409,12 +8672,14 @@ function Calendar_constructor(element, overrides) {
8409
8672
  }
8410
8673
 
8411
8674
 
8412
- function trigger(name, thisObj) {
8675
+ function trigger(name, thisObj) { // overrides the Emitter's trigger method :(
8676
+ var args = Array.prototype.slice.call(arguments, 2);
8677
+
8678
+ thisObj = thisObj || _element;
8679
+ this.triggerWith(name, thisObj, args); // Emitter's method
8680
+
8413
8681
  if (options[name]) {
8414
- return options[name].apply(
8415
- thisObj || _element,
8416
- Array.prototype.slice.call(arguments, 2)
8417
- );
8682
+ return options[name].apply(thisObj, args);
8418
8683
  }
8419
8684
  }
8420
8685
 
@@ -8501,6 +8766,8 @@ Calendar.defaults = {
8501
8766
 
8502
8767
  dropAccept: '*',
8503
8768
 
8769
+ eventOrder: 'title',
8770
+
8504
8771
  eventLimit: false,
8505
8772
  eventLimitText: 'more',
8506
8773
  eventLimitClick: 'popover',
@@ -8796,6 +9063,7 @@ function Header(calendar, options) {
8796
9063
  var groupEl;
8797
9064
 
8798
9065
  $.each(this.split(','), function(j, buttonName) {
9066
+ var customButtonProps;
8799
9067
  var viewSpec;
8800
9068
  var buttonClick;
8801
9069
  var overrideText; // text explicitly set by calendar's constructor options. overcomes icons
@@ -8804,16 +9072,23 @@ function Header(calendar, options) {
8804
9072
  var normalIcon;
8805
9073
  var innerHtml;
8806
9074
  var classes;
8807
- var button;
9075
+ var button; // the element
8808
9076
 
8809
9077
  if (buttonName == 'title') {
8810
9078
  groupChildren = groupChildren.add($('<h2>&nbsp;</h2>')); // we always want it to take up height
8811
9079
  isOnlyButtons = false;
8812
9080
  }
8813
9081
  else {
8814
- viewSpec = calendar.getViewSpec(buttonName);
8815
-
8816
- if (viewSpec) {
9082
+ if ((customButtonProps = (calendar.options.customButtons || {})[buttonName])) {
9083
+ buttonClick = function(ev) {
9084
+ if (customButtonProps.click) {
9085
+ customButtonProps.click.call(button[0], ev);
9086
+ }
9087
+ };
9088
+ overrideText = ''; // icons will override text
9089
+ defaultText = customButtonProps.text;
9090
+ }
9091
+ else if ((viewSpec = calendar.getViewSpec(buttonName))) {
8817
9092
  buttonClick = function() {
8818
9093
  calendar.changeView(buttonName);
8819
9094
  };
@@ -8831,8 +9106,15 @@ function Header(calendar, options) {
8831
9106
 
8832
9107
  if (buttonClick) {
8833
9108
 
8834
- themeIcon = options.themeButtonIcons[buttonName];
8835
- normalIcon = options.buttonIcons[buttonName];
9109
+ themeIcon =
9110
+ customButtonProps ?
9111
+ customButtonProps.themeIcon :
9112
+ options.themeButtonIcons[buttonName];
9113
+
9114
+ normalIcon =
9115
+ customButtonProps ?
9116
+ customButtonProps.icon :
9117
+ options.buttonIcons[buttonName];
8836
9118
 
8837
9119
  if (overrideText) {
8838
9120
  innerHtml = htmlEscape(overrideText);
@@ -8858,11 +9140,11 @@ function Header(calendar, options) {
8858
9140
  innerHtml +
8859
9141
  '</button>'
8860
9142
  )
8861
- .click(function() {
9143
+ .click(function(ev) {
8862
9144
  // don't process clicks for disabled buttons
8863
9145
  if (!button.hasClass(tm + '-state-disabled')) {
8864
9146
 
8865
- buttonClick();
9147
+ buttonClick(ev);
8866
9148
 
8867
9149
  // after the click action, if the button becomes the "active" tab, or disabled,
8868
9150
  // it should never have a hover class, so remove it now.
@@ -10851,6 +11133,16 @@ var AgendaView = View.extend({
10851
11133
 
10852
11134
  var AGENDA_ALL_DAY_EVENT_LIMIT = 5;
10853
11135
 
11136
+ // potential nice values for the slot-duration and interval-duration
11137
+ // from largest to smallest
11138
+ var AGENDA_STOCK_SUB_DURATIONS = [
11139
+ { hours: 1 },
11140
+ { minutes: 30 },
11141
+ { minutes: 15 },
11142
+ { seconds: 30 },
11143
+ { seconds: 15 }
11144
+ ];
11145
+
10854
11146
  fcViews.agenda = {
10855
11147
  'class': AgendaView,
10856
11148
  defaults: {
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * FullCalendar v2.3.2 Google Calendar Plugin
2
+ * FullCalendar v2.4.0 Google Calendar Plugin
3
3
  * Docs & License: http://fullcalendar.io/
4
4
  * (c) 2015 Adam Shaw
5
5
  */
@@ -80,17 +80,13 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
80
80
 
81
81
  function reportError(message, apiErrorObjs) {
82
82
  var errorObjs = apiErrorObjs || [ { message: message } ]; // to be passed into error handlers
83
- var consoleObj = window.console;
84
- var consoleWarnFunc = consoleObj ? (consoleObj.warn || consoleObj.log) : null;
85
83
 
86
84
  // call error handlers
87
85
  (sourceOptions.googleCalendarError || $.noop).apply(calendar, errorObjs);
88
86
  (calendar.options.googleCalendarError || $.noop).apply(calendar, errorObjs);
89
87
 
90
88
  // print error to debug console
91
- if (consoleWarnFunc) {
92
- consoleWarnFunc.apply(consoleObj, [ message ].concat(apiErrorObjs || []));
93
- }
89
+ fc.warn.apply(null, [ message ].concat(apiErrorObjs || []));
94
90
  }
95
91
 
96
92
  if (!apiKey) {
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * FullCalendar v2.3.2 Stylesheet
2
+ * FullCalendar v2.4.0 Stylesheet
3
3
  * Docs & License: http://fullcalendar.io/
4
4
  * (c) 2015 Adam Shaw
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * FullCalendar v2.3.2 Print Stylesheet
2
+ * FullCalendar v2.4.0 Print Stylesheet
3
3
  * Docs & License: http://fullcalendar.io/
4
4
  * (c) 2015 Adam Shaw
5
5
  */
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fullcalendar.io-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.2
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dbackowski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-15 00:00:00.000000000 Z
11
+ date: 2015-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jquery-rails