You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6381 lines
241 KiB

2 years ago
  1. /*!
  2. FullCalendar Scheduler v1.5.0
  3. Docs & License: http://fullcalendar.io/scheduler/
  4. (c) 2016 Adam Shaw
  5. */
  6. (function (factory) {
  7. if (typeof define === 'function' && define.amd) {
  8. define(['jquery', 'moment', 'fullcalendar'], factory);
  9. }
  10. else if (typeof exports === 'object') { // Node/CommonJS
  11. module.exports = factory(
  12. require('jquery'),
  13. require('moment'),
  14. require('fullcalendar')
  15. );
  16. }
  17. else {
  18. factory(jQuery, moment);
  19. }
  20. })(function ($, moment) {
  21. ;
  22. var COL_MIN_WIDTH, Calendar, CalendarExtension, Class, ClippedScroller, CoordCache, DEFAULT_GRID_DURATION, DragListener, EmitterMixin, EnhancedScroller, EventRow, FC, Grid, HRowGroup, LICENSE_INFO_URL, ListenerMixin, MAX_AUTO_CELLS, MAX_AUTO_SLOTS_PER_LABEL, MAX_CELLS, MIN_AUTO_LABELS, PRESET_LICENSE_KEYS, Promise, RELEASE_DATE, ResourceAgendaView, ResourceBasicView, ResourceDayGrid, ResourceDayTableMixin, ResourceGridMixin, ResourceManager, ResourceMonthView, ResourceRow, ResourceTimeGrid, ResourceTimelineGrid, ResourceTimelineView, ResourceViewMixin, RowGroup, RowParent, STOCK_SUB_DURATIONS, ScrollFollower, ScrollFollowerSprite, ScrollJoiner, ScrollerCanvas, Spreadsheet, TaskQueue, TimelineGrid, TimelineView, UPGRADE_WINDOW, VRowGroup, VertResourceViewMixin, View, _filterResourcesWithEvents, applyAll, capitaliseFirstLetter, compareByFieldSpecs, computeIntervalUnit, computeOffsetForSeg, computeOffsetForSegs, copyRect, createObject, cssToStr, debounce, detectWarningInContainer, divideDurationByDuration, divideRangeByDuration, durationHasTime, flexibleCompare, getContentRect, getOuterRect, getOwnCells, getRectHeight, getRectWidth, getScrollbarWidths, hContainRect, htmlEscape, intersectRanges, intersectRects, isImmuneUrl, isInt, isValidKey, joinRects, multiplyDuration, origExecuteEventsRender, origGetSegCustomClasses, origGetSegDefaultBackgroundColor, origGetSegDefaultBorderColor, origGetSegDefaultTextColor, origHandleDate, origOnDateRender, origRemoveElement, origSetElement, parseFieldSpecs, processLicenseKey, proxy, renderingWarningInContainer, testRectContains, testRectHContains, testRectVContains, timeRowSegsCollide, vContainRect,
  23. extend = function (child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  24. hasProp = {}.hasOwnProperty,
  25. indexOf = [].indexOf || function (item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
  26. slice = [].slice;
  27. FC = $.fullCalendar;
  28. FC.schedulerVersion = "1.5.0";
  29. if (FC.internalApiVersion !== 7) {
  30. FC.warn('v' + FC.schedulerVersion + ' of FullCalendar Scheduler ' + 'is incompatible with v' + FC.version + ' of the core.\n' + 'Please see http://fullcalendar.io/support/ for more information.');
  31. return;
  32. }
  33. Calendar = FC.Calendar;
  34. Class = FC.Class;
  35. View = FC.View;
  36. Grid = FC.Grid;
  37. intersectRanges = FC.intersectRanges;
  38. debounce = FC.debounce;
  39. isInt = FC.isInt;
  40. getScrollbarWidths = FC.getScrollbarWidths;
  41. DragListener = FC.DragListener;
  42. htmlEscape = FC.htmlEscape;
  43. computeIntervalUnit = FC.computeIntervalUnit;
  44. proxy = FC.proxy;
  45. capitaliseFirstLetter = FC.capitaliseFirstLetter;
  46. applyAll = FC.applyAll;
  47. EmitterMixin = FC.EmitterMixin;
  48. ListenerMixin = FC.ListenerMixin;
  49. durationHasTime = FC.durationHasTime;
  50. divideRangeByDuration = FC.divideRangeByDuration;
  51. divideDurationByDuration = FC.divideDurationByDuration;
  52. multiplyDuration = FC.multiplyDuration;
  53. parseFieldSpecs = FC.parseFieldSpecs;
  54. compareByFieldSpecs = FC.compareByFieldSpecs;
  55. flexibleCompare = FC.flexibleCompare;
  56. intersectRects = FC.intersectRects;
  57. CoordCache = FC.CoordCache;
  58. getContentRect = FC.getContentRect;
  59. getOuterRect = FC.getOuterRect;
  60. createObject = FC.createObject;
  61. Promise = FC.Promise;
  62. TaskQueue = FC.TaskQueue;
  63. /*
  64. Given a jQuery <tr> set, returns the <td>'s that do not have multi-line rowspans.
  65. Would use the [rowspan] selector, but never not defined in IE8.
  66. */
  67. getOwnCells = function (trs) {
  68. return trs.find('> td').filter(function (i, tdNode) {
  69. return tdNode.rowSpan <= 1;
  70. });
  71. };
  72. /*
  73. A Scroller with additional functionality:
  74. - optional ScrollerCanvas for content
  75. - fired events for scroll start/end
  76. - cross-browser normalization of horizontal scroll for RTL
  77. */
  78. EnhancedScroller = (function (superClass) {
  79. var detectRtlScrollSystem, rtlScrollSystem;
  80. extend(EnhancedScroller, superClass);
  81. EnhancedScroller.mixin(EmitterMixin);
  82. EnhancedScroller.mixin(ListenerMixin);
  83. EnhancedScroller.prototype.canvas = null;
  84. EnhancedScroller.prototype.isScrolling = false;
  85. EnhancedScroller.prototype.isTouching = false;
  86. EnhancedScroller.prototype.isMoving = false;
  87. EnhancedScroller.prototype.isTouchScrollEnabled = true;
  88. EnhancedScroller.prototype.preventTouchScrollHandler = null;
  89. function EnhancedScroller() {
  90. EnhancedScroller.__super__.constructor.apply(this, arguments);
  91. this.requestMovingEnd = debounce(this.reportMovingEnd, 500);
  92. }
  93. EnhancedScroller.prototype.render = function () {
  94. EnhancedScroller.__super__.render.apply(this, arguments);
  95. if (this.canvas) {
  96. this.canvas.render();
  97. this.canvas.el.appendTo(this.scrollEl);
  98. }
  99. return this.bindHandlers();
  100. };
  101. EnhancedScroller.prototype.destroy = function () {
  102. EnhancedScroller.__super__.destroy.apply(this, arguments);
  103. return this.unbindHandlers();
  104. };
  105. EnhancedScroller.prototype.disableTouchScroll = function () {
  106. this.isTouchScrollEnabled = false;
  107. return this.bindPreventTouchScroll();
  108. };
  109. EnhancedScroller.prototype.enableTouchScroll = function () {
  110. this.isTouchScrollEnabled = true;
  111. if (!this.isTouching) {
  112. return this.unbindPreventTouchScroll();
  113. }
  114. };
  115. EnhancedScroller.prototype.bindPreventTouchScroll = function () {
  116. if (!this.preventTouchScrollHandler) {
  117. return this.scrollEl.on('touchmove', this.preventTouchScrollHandler = FC.preventDefault);
  118. }
  119. };
  120. EnhancedScroller.prototype.unbindPreventTouchScroll = function () {
  121. if (this.preventTouchScrollHandler) {
  122. this.scrollEl.off('touchmove', this.preventTouchScrollHandler);
  123. return this.preventTouchScrollHandler = null;
  124. }
  125. };
  126. EnhancedScroller.prototype.bindHandlers = function () {
  127. return this.listenTo(this.scrollEl, {
  128. scroll: this.reportScroll,
  129. touchstart: this.reportTouchStart,
  130. touchend: this.reportTouchEnd
  131. });
  132. };
  133. EnhancedScroller.prototype.unbindHandlers = function () {
  134. return this.stopListeningTo(this.scrollEl);
  135. };
  136. EnhancedScroller.prototype.reportScroll = function () {
  137. if (!this.isScrolling) {
  138. this.reportScrollStart();
  139. }
  140. this.trigger('scroll');
  141. this.isMoving = true;
  142. return this.requestMovingEnd();
  143. };
  144. EnhancedScroller.prototype.reportScrollStart = function () {
  145. if (!this.isScrolling) {
  146. this.isScrolling = true;
  147. return this.trigger('scrollStart', this.isTouching);
  148. }
  149. };
  150. EnhancedScroller.prototype.requestMovingEnd = null;
  151. EnhancedScroller.prototype.reportMovingEnd = function () {
  152. this.isMoving = false;
  153. if (!this.isTouching) {
  154. return this.reportScrollEnd();
  155. }
  156. };
  157. EnhancedScroller.prototype.reportScrollEnd = function () {
  158. if (this.isScrolling) {
  159. this.trigger('scrollEnd');
  160. return this.isScrolling = false;
  161. }
  162. };
  163. EnhancedScroller.prototype.reportTouchStart = function () {
  164. return this.isTouching = true;
  165. };
  166. EnhancedScroller.prototype.reportTouchEnd = function () {
  167. if (this.isTouching) {
  168. this.isTouching = false;
  169. if (this.isTouchScrollEnabled) {
  170. this.unbindPreventTouchScroll();
  171. }
  172. if (!this.isMoving) {
  173. return this.reportScrollEnd();
  174. }
  175. }
  176. };
  177. /*
  178. If RTL, and scrolled to the left, returns NEGATIVE value (like Firefox)
  179. */
  180. EnhancedScroller.prototype.getScrollLeft = function () {
  181. var direction, node, val;
  182. direction = this.scrollEl.css('direction');
  183. node = this.scrollEl[0];
  184. val = node.scrollLeft;
  185. if (direction === 'rtl') {
  186. switch (rtlScrollSystem) {
  187. case 'positive':
  188. val = val + node.clientWidth - node.scrollWidth;
  189. break;
  190. case 'reverse':
  191. val = -val;
  192. }
  193. }
  194. return val;
  195. };
  196. /*
  197. Accepts a NEGATIVE value for when scrolled in RTL
  198. */
  199. EnhancedScroller.prototype.setScrollLeft = function (val) {
  200. var direction, node;
  201. direction = this.scrollEl.css('direction');
  202. node = this.scrollEl[0];
  203. if (direction === 'rtl') {
  204. switch (rtlScrollSystem) {
  205. case 'positive':
  206. val = val - node.clientWidth + node.scrollWidth;
  207. break;
  208. case 'reverse':
  209. val = -val;
  210. }
  211. }
  212. return node.scrollLeft = val;
  213. };
  214. /*
  215. Always returns the number of pixels scrolled from the leftmost position (even if RTL).
  216. Always positive.
  217. */
  218. EnhancedScroller.prototype.getScrollFromLeft = function () {
  219. var direction, node, val;
  220. direction = this.scrollEl.css('direction');
  221. node = this.scrollEl[0];
  222. val = node.scrollLeft;
  223. if (direction === 'rtl') {
  224. switch (rtlScrollSystem) {
  225. case 'negative':
  226. val = val - node.clientWidth + node.scrollWidth;
  227. break;
  228. case 'reverse':
  229. val = -val - node.clientWidth + node.scrollWidth;
  230. }
  231. }
  232. return val;
  233. };
  234. EnhancedScroller.prototype.getNativeScrollLeft = function () {
  235. return this.scrollEl[0].scrollLeft;
  236. };
  237. EnhancedScroller.prototype.setNativeScrollLeft = function (val) {
  238. return this.scrollEl[0].scrollLeft = val;
  239. };
  240. rtlScrollSystem = null;
  241. detectRtlScrollSystem = function () {
  242. var el, node, system;
  243. el = $('<div style=" position: absolute top: -1000px; width: 1px; height: 1px; overflow: scroll; direction: rtl; font-size: 14px; ">A</div>').appendTo('body');
  244. node = el[0];
  245. system = node.scrollLeft > 0 ? 'positive' : (node.scrollLeft = 1, el.scrollLeft > 0 ? 'reverse' : 'negative');
  246. el.remove();
  247. return system;
  248. };
  249. $(function () {
  250. return rtlScrollSystem = detectRtlScrollSystem();
  251. });
  252. return EnhancedScroller;
  253. })(FC.Scroller);
  254. /*
  255. A Scroller, but with a wrapping div that allows "clipping" away of native scrollbars,
  256. giving the appearance that there are no scrollbars.
  257. */
  258. ClippedScroller = (function (superClass) {
  259. extend(ClippedScroller, superClass);
  260. ClippedScroller.prototype.isHScrollbarsClipped = false;
  261. ClippedScroller.prototype.isVScrollbarsClipped = false;
  262. /*
  263. Received overflows can be set to 'clipped', meaning scrollbars shouldn't be visible
  264. to the user, but the area should still scroll.
  265. */
  266. function ClippedScroller() {
  267. ClippedScroller.__super__.constructor.apply(this, arguments);
  268. if (this.overflowX === 'clipped-scroll') {
  269. this.overflowX = 'scroll';
  270. this.isHScrollbarsClipped = true;
  271. }
  272. if (this.overflowY === 'clipped-scroll') {
  273. this.overflowY = 'scroll';
  274. this.isVScrollbarsClipped = true;
  275. }
  276. }
  277. ClippedScroller.prototype.renderEl = function () {
  278. var scrollEl;
  279. scrollEl = ClippedScroller.__super__.renderEl.apply(this, arguments);
  280. return $('<div class="fc-scroller-clip" />').append(scrollEl);
  281. };
  282. ClippedScroller.prototype.updateSize = function () {
  283. var cssProps, scrollEl, scrollbarWidths;
  284. scrollEl = this.scrollEl;
  285. scrollbarWidths = getScrollbarWidths(scrollEl);
  286. cssProps = {
  287. marginLeft: 0,
  288. marginRight: 0,
  289. marginTop: 0,
  290. marginBottom: 0
  291. };
  292. if (this.isHScrollbarsClipped) {
  293. cssProps.marginTop = -scrollbarWidths.top;
  294. cssProps.marginBottom = -scrollbarWidths.bottom;
  295. }
  296. if (this.isVScrollbarsClipped) {
  297. cssProps.marginLeft = -scrollbarWidths.left;
  298. cssProps.marginRight = -scrollbarWidths.right;
  299. }
  300. scrollEl.css(cssProps);
  301. return scrollEl.toggleClass('fc-no-scrollbars', (this.isHScrollbarsClipped || this.overflowX === 'hidden') && (this.isVScrollbarsClipped || this.overflowY === 'hidden') && !(scrollbarWidths.top || scrollbarWidths.bottom || scrollbarWidths.left || scrollbarWidths.right));
  302. };
  303. /*
  304. Accounts for 'clipped' scrollbars
  305. */
  306. ClippedScroller.prototype.getScrollbarWidths = function () {
  307. var widths;
  308. widths = getScrollbarWidths(this.scrollEl);
  309. if (this.isHScrollbarsClipped) {
  310. widths.top = 0;
  311. widths.bottom = 0;
  312. }
  313. if (this.isVScrollbarsClipped) {
  314. widths.left = 0;
  315. widths.right = 0;
  316. }
  317. return widths;
  318. };
  319. return ClippedScroller;
  320. })(EnhancedScroller);
  321. /*
  322. A rectangular area of content that lives within a Scroller.
  323. Can have "gutters", areas of dead spacing around the perimeter.
  324. Also very useful for forcing a width, which a Scroller cannot do alone.
  325. Has a content area that lives above a background area.
  326. */
  327. ScrollerCanvas = (function () {
  328. ScrollerCanvas.prototype.el = null;
  329. ScrollerCanvas.prototype.contentEl = null;
  330. ScrollerCanvas.prototype.bgEl = null;
  331. ScrollerCanvas.prototype.gutters = null;
  332. ScrollerCanvas.prototype.width = null;
  333. ScrollerCanvas.prototype.minWidth = null;
  334. function ScrollerCanvas() {
  335. this.gutters = {};
  336. }
  337. ScrollerCanvas.prototype.render = function () {
  338. this.el = $('<div class="fc-scroller-canvas"> <div class="fc-content"></div> <div class="fc-bg"></div> </div>');
  339. this.contentEl = this.el.find('.fc-content');
  340. return this.bgEl = this.el.find('.fc-bg');
  341. };
  342. /*
  343. If falsy, resets all the gutters to 0
  344. */
  345. ScrollerCanvas.prototype.setGutters = function (gutters) {
  346. if (!gutters) {
  347. this.gutters = {};
  348. } else {
  349. $.extend(this.gutters, gutters);
  350. }
  351. return this.updateSize();
  352. };
  353. ScrollerCanvas.prototype.setWidth = function (width1) {
  354. this.width = width1;
  355. return this.updateSize();
  356. };
  357. ScrollerCanvas.prototype.setMinWidth = function (minWidth1) {
  358. this.minWidth = minWidth1;
  359. return this.updateSize();
  360. };
  361. ScrollerCanvas.prototype.clearWidth = function () {
  362. this.width = null;
  363. this.minWidth = null;
  364. return this.updateSize();
  365. };
  366. ScrollerCanvas.prototype.updateSize = function () {
  367. var gutters;
  368. gutters = this.gutters;
  369. this.el.toggleClass('fc-gutter-left', Boolean(gutters.left)).toggleClass('fc-gutter-right', Boolean(gutters.right)).toggleClass('fc-gutter-top', Boolean(gutters.top)).toggleClass('fc-gutter-bottom', Boolean(gutters.bottom)).css({
  370. paddingLeft: gutters.left || '',
  371. paddingRight: gutters.right || '',
  372. paddingTop: gutters.top || '',
  373. paddingBottom: gutters.bottom || '',
  374. width: this.width != null ? this.width + (gutters.left || 0) + (gutters.right || 0) : '',
  375. minWidth: this.minWidth != null ? this.minWidth + (gutters.left || 0) + (gutters.right || 0) : ''
  376. });
  377. return this.bgEl.css({
  378. left: gutters.left || '',
  379. right: gutters.right || '',
  380. top: gutters.top || '',
  381. bottom: gutters.bottom || ''
  382. });
  383. };
  384. return ScrollerCanvas;
  385. })();
  386. ScrollJoiner = (function () {
  387. ScrollJoiner.prototype.axis = null;
  388. ScrollJoiner.prototype.scrollers = null;
  389. ScrollJoiner.prototype.masterScroller = null;
  390. function ScrollJoiner(axis, scrollers) {
  391. var j, len, ref, scroller;
  392. this.axis = axis;
  393. this.scrollers = scrollers;
  394. ref = this.scrollers;
  395. for (j = 0, len = ref.length; j < len; j++) {
  396. scroller = ref[j];
  397. this.initScroller(scroller);
  398. }
  399. return;
  400. }
  401. ScrollJoiner.prototype.initScroller = function (scroller) {
  402. scroller.scrollEl.on('wheel mousewheel DomMouseScroll MozMousePixelScroll', (function (_this) {
  403. return function () {
  404. _this.assignMasterScroller(scroller);
  405. };
  406. })(this));
  407. return scroller.on('scrollStart', (function (_this) {
  408. return function () {
  409. if (!_this.masterScroller) {
  410. return _this.assignMasterScroller(scroller);
  411. }
  412. };
  413. })(this)).on('scroll', (function (_this) {
  414. return function () {
  415. var j, len, otherScroller, ref, results;
  416. if (scroller === _this.masterScroller) {
  417. ref = _this.scrollers;
  418. results = [];
  419. for (j = 0, len = ref.length; j < len; j++) {
  420. otherScroller = ref[j];
  421. if (otherScroller !== scroller) {
  422. switch (_this.axis) {
  423. case 'horizontal':
  424. results.push(otherScroller.setNativeScrollLeft(scroller.getNativeScrollLeft()));
  425. break;
  426. case 'vertical':
  427. results.push(otherScroller.setScrollTop(scroller.getScrollTop()));
  428. break;
  429. default:
  430. results.push(void 0);
  431. }
  432. } else {
  433. results.push(void 0);
  434. }
  435. }
  436. return results;
  437. }
  438. };
  439. })(this)).on('scrollEnd', (function (_this) {
  440. return function () {
  441. if (scroller === _this.masterScroller) {
  442. return _this.unassignMasterScroller();
  443. }
  444. };
  445. })(this));
  446. };
  447. ScrollJoiner.prototype.assignMasterScroller = function (scroller) {
  448. var j, len, otherScroller, ref;
  449. this.unassignMasterScroller();
  450. this.masterScroller = scroller;
  451. ref = this.scrollers;
  452. for (j = 0, len = ref.length; j < len; j++) {
  453. otherScroller = ref[j];
  454. if (otherScroller !== scroller) {
  455. otherScroller.disableTouchScroll();
  456. }
  457. }
  458. };
  459. ScrollJoiner.prototype.unassignMasterScroller = function () {
  460. var j, len, otherScroller, ref;
  461. if (this.masterScroller) {
  462. ref = this.scrollers;
  463. for (j = 0, len = ref.length; j < len; j++) {
  464. otherScroller = ref[j];
  465. otherScroller.enableTouchScroll();
  466. }
  467. this.masterScroller = null;
  468. }
  469. };
  470. ScrollJoiner.prototype.update = function () {
  471. var allWidths, i, j, k, len, len1, maxBottom, maxLeft, maxRight, maxTop, ref, scroller, widths;
  472. allWidths = (function () {
  473. var j, len, ref, results;
  474. ref = this.scrollers;
  475. results = [];
  476. for (j = 0, len = ref.length; j < len; j++) {
  477. scroller = ref[j];
  478. results.push(scroller.getScrollbarWidths());
  479. }
  480. return results;
  481. }).call(this);
  482. maxLeft = maxRight = maxTop = maxBottom = 0;
  483. for (j = 0, len = allWidths.length; j < len; j++) {
  484. widths = allWidths[j];
  485. maxLeft = Math.max(maxLeft, widths.left);
  486. maxRight = Math.max(maxRight, widths.right);
  487. maxTop = Math.max(maxTop, widths.top);
  488. maxBottom = Math.max(maxBottom, widths.bottom);
  489. }
  490. ref = this.scrollers;
  491. for (i = k = 0, len1 = ref.length; k < len1; i = ++k) {
  492. scroller = ref[i];
  493. widths = allWidths[i];
  494. scroller.canvas.setGutters(this.axis === 'horizontal' ? {
  495. left: maxLeft - widths.left,
  496. right: maxRight - widths.right
  497. } : {
  498. top: maxTop - widths.top,
  499. bottom: maxBottom - widths.bottom
  500. });
  501. }
  502. };
  503. return ScrollJoiner;
  504. })();
  505. ScrollFollower = (function () {
  506. ScrollFollower.prototype.scroller = null;
  507. ScrollFollower.prototype.scrollbarWidths = null;
  508. ScrollFollower.prototype.sprites = null;
  509. ScrollFollower.prototype.viewportRect = null;
  510. ScrollFollower.prototype.contentOffset = null;
  511. ScrollFollower.prototype.isHFollowing = true;
  512. ScrollFollower.prototype.isVFollowing = false;
  513. ScrollFollower.prototype.allowPointerEvents = false;
  514. ScrollFollower.prototype.containOnNaturalLeft = false;
  515. ScrollFollower.prototype.containOnNaturalRight = false;
  516. ScrollFollower.prototype.minTravel = 0;
  517. ScrollFollower.prototype.isTouch = false;
  518. ScrollFollower.prototype.isForcedRelative = false;
  519. function ScrollFollower(scroller, allowPointerEvents) {
  520. this.allowPointerEvents = allowPointerEvents != null ? allowPointerEvents : false;
  521. this.scroller = scroller;
  522. this.sprites = [];
  523. scroller.on('scroll', (function (_this) {
  524. return function () {
  525. if (scroller.isTouching) {
  526. _this.isTouch = true;
  527. return _this.isForcedRelative = true;
  528. } else {
  529. _this.isTouch = false;
  530. _this.isForcedRelative = false;
  531. return _this.handleScroll();
  532. }
  533. };
  534. })(this));
  535. scroller.on('scrollEnd', (function (_this) {
  536. return function () {
  537. return _this.handleScroll();
  538. };
  539. })(this));
  540. }
  541. ScrollFollower.prototype.setSprites = function (sprites) {
  542. var j, len, sprite;
  543. this.clearSprites();
  544. if (sprites instanceof $) {
  545. return this.sprites = (function () {
  546. var j, len, results;
  547. results = [];
  548. for (j = 0, len = sprites.length; j < len; j++) {
  549. sprite = sprites[j];
  550. results.push(new ScrollFollowerSprite($(sprite), this));
  551. }
  552. return results;
  553. }).call(this);
  554. } else {
  555. for (j = 0, len = sprites.length; j < len; j++) {
  556. sprite = sprites[j];
  557. sprite.follower = this;
  558. }
  559. return this.sprites = sprites;
  560. }
  561. };
  562. ScrollFollower.prototype.clearSprites = function () {
  563. var j, len, ref, sprite;
  564. ref = this.sprites;
  565. for (j = 0, len = ref.length; j < len; j++) {
  566. sprite = ref[j];
  567. sprite.clear();
  568. }
  569. return this.sprites = [];
  570. };
  571. ScrollFollower.prototype.handleScroll = function () {
  572. this.updateViewport();
  573. return this.updatePositions();
  574. };
  575. ScrollFollower.prototype.cacheDimensions = function () {
  576. var j, len, ref, sprite;
  577. this.updateViewport();
  578. this.scrollbarWidths = this.scroller.getScrollbarWidths();
  579. this.contentOffset = this.scroller.canvas.el.offset();
  580. ref = this.sprites;
  581. for (j = 0, len = ref.length; j < len; j++) {
  582. sprite = ref[j];
  583. sprite.cacheDimensions();
  584. }
  585. };
  586. ScrollFollower.prototype.updateViewport = function () {
  587. var left, scroller, top;
  588. scroller = this.scroller;
  589. left = scroller.getScrollFromLeft();
  590. top = scroller.getScrollTop();
  591. return this.viewportRect = {
  592. left: left,
  593. right: left + scroller.getClientWidth(),
  594. top: top,
  595. bottom: top + scroller.getClientHeight()
  596. };
  597. };
  598. ScrollFollower.prototype.forceRelative = function () {
  599. var j, len, ref, results, sprite;
  600. if (!this.isForcedRelative) {
  601. this.isForcedRelative = true;
  602. ref = this.sprites;
  603. results = [];
  604. for (j = 0, len = ref.length; j < len; j++) {
  605. sprite = ref[j];
  606. if (sprite.doAbsolute) {
  607. results.push(sprite.assignPosition());
  608. } else {
  609. results.push(void 0);
  610. }
  611. }
  612. return results;
  613. }
  614. };
  615. ScrollFollower.prototype.clearForce = function () {
  616. var j, len, ref, results, sprite;
  617. if (this.isForcedRelative && !this.isTouch) {
  618. this.isForcedRelative = false;
  619. ref = this.sprites;
  620. results = [];
  621. for (j = 0, len = ref.length; j < len; j++) {
  622. sprite = ref[j];
  623. results.push(sprite.assignPosition());
  624. }
  625. return results;
  626. }
  627. };
  628. ScrollFollower.prototype.update = function () {
  629. this.cacheDimensions();
  630. return this.updatePositions();
  631. };
  632. ScrollFollower.prototype.updatePositions = function () {
  633. var j, len, ref, sprite;
  634. ref = this.sprites;
  635. for (j = 0, len = ref.length; j < len; j++) {
  636. sprite = ref[j];
  637. sprite.updatePosition();
  638. }
  639. };
  640. ScrollFollower.prototype.getContentRect = function (el) {
  641. return getContentRect(el, this.contentOffset);
  642. };
  643. ScrollFollower.prototype.getBoundingRect = function (el) {
  644. return getOuterRect(el, this.contentOffset);
  645. };
  646. return ScrollFollower;
  647. })();
  648. ScrollFollowerSprite = (function () {
  649. ScrollFollowerSprite.prototype.follower = null;
  650. ScrollFollowerSprite.prototype.el = null;
  651. ScrollFollowerSprite.prototype.absoluteEl = null;
  652. ScrollFollowerSprite.prototype.naturalRect = null;
  653. ScrollFollowerSprite.prototype.parentRect = null;
  654. ScrollFollowerSprite.prototype.containerRect = null;
  655. ScrollFollowerSprite.prototype.isEnabled = true;
  656. ScrollFollowerSprite.prototype.isHFollowing = false;
  657. ScrollFollowerSprite.prototype.isVFollowing = false;
  658. ScrollFollowerSprite.prototype.doAbsolute = false;
  659. ScrollFollowerSprite.prototype.isAbsolute = false;
  660. ScrollFollowerSprite.prototype.isCentered = false;
  661. ScrollFollowerSprite.prototype.rect = null;
  662. ScrollFollowerSprite.prototype.isBlock = false;
  663. ScrollFollowerSprite.prototype.naturalWidth = null;
  664. function ScrollFollowerSprite(el1, follower1) {
  665. this.el = el1;
  666. this.follower = follower1 != null ? follower1 : null;
  667. this.isBlock = this.el.css('display') === 'block';
  668. this.el.css('position', 'relative');
  669. }
  670. ScrollFollowerSprite.prototype.disable = function () {
  671. if (this.isEnabled) {
  672. this.isEnabled = false;
  673. this.resetPosition();
  674. return this.unabsolutize();
  675. }
  676. };
  677. ScrollFollowerSprite.prototype.enable = function () {
  678. if (!this.isEnabled) {
  679. this.isEnabled = true;
  680. return this.assignPosition();
  681. }
  682. };
  683. ScrollFollowerSprite.prototype.clear = function () {
  684. this.disable();
  685. this.follower = null;
  686. return this.absoluteEl = null;
  687. };
  688. ScrollFollowerSprite.prototype.cacheDimensions = function () {
  689. var containerRect, follower, isCentered, isHFollowing, isVFollowing, minTravel, naturalRect, parentEl;
  690. isHFollowing = false;
  691. isVFollowing = false;
  692. isCentered = false;
  693. this.naturalWidth = this.el.width();
  694. this.resetPosition();
  695. follower = this.follower;
  696. naturalRect = this.naturalRect = follower.getBoundingRect(this.el);
  697. parentEl = this.el.parent();
  698. this.parentRect = follower.getBoundingRect(parentEl);
  699. containerRect = this.containerRect = joinRects(follower.getContentRect(parentEl), naturalRect);
  700. minTravel = follower.minTravel;
  701. if (follower.containOnNaturalLeft) {
  702. containerRect.left = naturalRect.left;
  703. }
  704. if (follower.containOnNaturalRight) {
  705. containerRect.right = naturalRect.right;
  706. }
  707. if (follower.isHFollowing) {
  708. if (getRectWidth(containerRect) - getRectWidth(naturalRect) >= minTravel) {
  709. isCentered = this.el.css('text-align') === 'center';
  710. isHFollowing = true;
  711. }
  712. }
  713. if (follower.isVFollowing) {
  714. if (getRectHeight(containerRect) - getRectHeight(naturalRect) >= minTravel) {
  715. isVFollowing = true;
  716. }
  717. }
  718. this.isHFollowing = isHFollowing;
  719. this.isVFollowing = isVFollowing;
  720. return this.isCentered = isCentered;
  721. };
  722. ScrollFollowerSprite.prototype.updatePosition = function () {
  723. this.computePosition();
  724. return this.assignPosition();
  725. };
  726. ScrollFollowerSprite.prototype.resetPosition = function () {
  727. return this.el.css({
  728. top: '',
  729. left: ''
  730. });
  731. };
  732. ScrollFollowerSprite.prototype.computePosition = function () {
  733. var containerRect, doAbsolute, parentRect, rect, rectWidth, subjectRect, viewportRect, visibleParentRect;
  734. viewportRect = this.follower.viewportRect;
  735. parentRect = this.parentRect;
  736. containerRect = this.containerRect;
  737. visibleParentRect = intersectRects(viewportRect, parentRect);
  738. rect = null;
  739. doAbsolute = false;
  740. if (visibleParentRect) {
  741. rect = copyRect(this.naturalRect);
  742. subjectRect = intersectRects(rect, parentRect);
  743. if ((this.isCentered && !testRectContains(viewportRect, parentRect)) || (subjectRect && !testRectContains(viewportRect, subjectRect))) {
  744. doAbsolute = true;
  745. if (this.isHFollowing) {
  746. if (this.isCentered) {
  747. rectWidth = getRectWidth(rect);
  748. rect.left = (visibleParentRect.left + visibleParentRect.right) / 2 - rectWidth / 2;
  749. rect.right = rect.left + rectWidth;
  750. } else {
  751. if (!hContainRect(rect, viewportRect)) {
  752. doAbsolute = false;
  753. }
  754. }
  755. if (hContainRect(rect, containerRect)) {
  756. doAbsolute = false;
  757. }
  758. }
  759. if (this.isVFollowing) {
  760. if (!vContainRect(rect, viewportRect)) {
  761. doAbsolute = false;
  762. }
  763. if (vContainRect(rect, containerRect)) {
  764. doAbsolute = false;
  765. }
  766. }
  767. if (!testRectContains(viewportRect, rect)) {
  768. doAbsolute = false;
  769. }
  770. }
  771. }
  772. this.rect = rect;
  773. return this.doAbsolute = doAbsolute;
  774. };
  775. ScrollFollowerSprite.prototype.assignPosition = function () {
  776. var left, top;
  777. if (this.isEnabled) {
  778. if (!this.rect) {
  779. return this.unabsolutize();
  780. } else if (this.doAbsolute && !this.follower.isForcedRelative) {
  781. this.absolutize();
  782. return this.absoluteEl.css({
  783. top: this.rect.top - this.follower.viewportRect.top + this.follower.scrollbarWidths.top,
  784. left: this.rect.left - this.follower.viewportRect.left + this.follower.scrollbarWidths.left,
  785. width: this.isBlock ? this.naturalWidth : ''
  786. });
  787. } else {
  788. top = this.rect.top - this.naturalRect.top;
  789. left = this.rect.left - this.naturalRect.left;
  790. this.unabsolutize();
  791. return this.el.toggleClass('fc-following', Boolean(top || left)).css({
  792. top: top,
  793. left: left
  794. });
  795. }
  796. }
  797. };
  798. ScrollFollowerSprite.prototype.absolutize = function () {
  799. if (!this.isAbsolute) {
  800. if (!this.absoluteEl) {
  801. this.absoluteEl = this.buildAbsoluteEl();
  802. }
  803. this.absoluteEl.appendTo(this.follower.scroller.el);
  804. this.el.css('visibility', 'hidden');
  805. return this.isAbsolute = true;
  806. }
  807. };
  808. ScrollFollowerSprite.prototype.unabsolutize = function () {
  809. if (this.isAbsolute) {
  810. this.absoluteEl.detach();
  811. this.el.css('visibility', '');
  812. return this.isAbsolute = false;
  813. }
  814. };
  815. ScrollFollowerSprite.prototype.buildAbsoluteEl = function () {
  816. var el;
  817. el = this.el.clone().addClass('fc-following');
  818. el.css({
  819. 'position': 'absolute',
  820. 'z-index': 1000,
  821. 'font-weight': this.el.css('font-weight'),
  822. 'font-size': this.el.css('font-size'),
  823. 'font-family': this.el.css('font-family'),
  824. 'text-decoration': this.el.css('text-decoration'),
  825. 'color': this.el.css('color'),
  826. 'padding-top': this.el.css('padding-top'),
  827. 'padding-bottom': this.el.css('padding-bottom'),
  828. 'padding-left': this.el.css('padding-left'),
  829. 'padding-right': this.el.css('padding-right')
  830. });
  831. if (!this.follower.allowPointerEvents) {
  832. el.css('pointer-events', 'none');
  833. }
  834. return el;
  835. };
  836. return ScrollFollowerSprite;
  837. })();
  838. copyRect = function (rect) {
  839. return {
  840. left: rect.left,
  841. right: rect.right,
  842. top: rect.top,
  843. bottom: rect.bottom
  844. };
  845. };
  846. getRectWidth = function (rect) {
  847. return rect.right - rect.left;
  848. };
  849. getRectHeight = function (rect) {
  850. return rect.bottom - rect.top;
  851. };
  852. testRectContains = function (rect, innerRect) {
  853. return testRectHContains(rect, innerRect) && testRectVContains(rect, innerRect);
  854. };
  855. testRectHContains = function (rect, innerRect) {
  856. return innerRect.left >= rect.left && innerRect.right <= rect.right;
  857. };
  858. testRectVContains = function (rect, innerRect) {
  859. return innerRect.top >= rect.top && innerRect.bottom <= rect.bottom;
  860. };
  861. hContainRect = function (rect, outerRect) {
  862. if (rect.left < outerRect.left) {
  863. rect.right = outerRect.left + getRectWidth(rect);
  864. rect.left = outerRect.left;
  865. return true;
  866. } else if (rect.right > outerRect.right) {
  867. rect.left = outerRect.right - getRectWidth(rect);
  868. rect.right = outerRect.right;
  869. return true;
  870. } else {
  871. return false;
  872. }
  873. };
  874. vContainRect = function (rect, outerRect) {
  875. if (rect.top < outerRect.top) {
  876. rect.bottom = outerRect.top + getRectHeight(rect);
  877. rect.top = outerRect.top;
  878. return true;
  879. } else if (rect.bottom > outerRect.bottom) {
  880. rect.top = outerRect.bottom - getRectHeight(rect);
  881. rect.bottom = outerRect.bottom;
  882. return true;
  883. } else {
  884. return false;
  885. }
  886. };
  887. joinRects = function (rect1, rect2) {
  888. return {
  889. left: Math.min(rect1.left, rect2.left),
  890. right: Math.max(rect1.right, rect2.right),
  891. top: Math.min(rect1.top, rect2.top),
  892. bottom: Math.max(rect1.bottom, rect2.bottom)
  893. };
  894. };
  895. CalendarExtension = (function (superClass) {
  896. extend(CalendarExtension, superClass);
  897. function CalendarExtension() {
  898. return CalendarExtension.__super__.constructor.apply(this, arguments);
  899. }
  900. CalendarExtension.prototype.resourceManager = null;
  901. CalendarExtension.prototype.initialize = function () {
  902. return this.resourceManager = new ResourceManager(this);
  903. };
  904. CalendarExtension.prototype.instantiateView = function (viewType) {
  905. var spec, viewClass;
  906. spec = this.getViewSpec(viewType);
  907. viewClass = spec['class'];
  908. if (this.options.resources && spec.options.resources !== false) {
  909. if (spec.queryResourceClass) {
  910. viewClass = spec.queryResourceClass(spec) || viewClass;
  911. } else if (spec.resourceClass) {
  912. viewClass = spec.resourceClass;
  913. }
  914. }
  915. return new viewClass(this, viewType, spec.options, spec.duration);
  916. };
  917. CalendarExtension.prototype.getResources = function () {
  918. return Array.prototype.slice.call(this.resourceManager.topLevelResources);
  919. };
  920. CalendarExtension.prototype.addResource = function (resourceInput, scroll) {
  921. var promise;
  922. if (scroll == null) {
  923. scroll = false;
  924. }
  925. promise = this.resourceManager.addResource(resourceInput);
  926. if (scroll && this.view.scrollToResource) {
  927. promise.then((function (_this) {
  928. return function (resource) {
  929. return _this.view.scrollToResource(resource);
  930. };
  931. })(this));
  932. }
  933. };
  934. CalendarExtension.prototype.removeResource = function (idOrResource) {
  935. return this.resourceManager.removeResource(idOrResource);
  936. };
  937. CalendarExtension.prototype.refetchResources = function () {
  938. this.resourceManager.fetchResources();
  939. };
  940. CalendarExtension.prototype.rerenderResources = function () {
  941. this.resourceManager.resetCurrentResources();
  942. };
  943. CalendarExtension.prototype.isSpanAllowed = function (span, constraint) {
  944. var constrainToResourceIds, ref;
  945. if (typeof constraint === 'object') {
  946. constrainToResourceIds = this.getEventResourceIds(constraint);
  947. if (constrainToResourceIds.length && (!span.resourceId || !(ref = span.resourceId, indexOf.call(constrainToResourceIds, ref) >= 0))) {
  948. return false;
  949. }
  950. }
  951. return CalendarExtension.__super__.isSpanAllowed.apply(this, arguments);
  952. };
  953. CalendarExtension.prototype.getPeerEvents = function (span, event) {
  954. var filteredPeerEvents, isPeer, j, k, l, len, len1, len2, newResourceId, newResourceIds, peerEvent, peerEvents, peerResourceId, peerResourceIds;
  955. peerEvents = CalendarExtension.__super__.getPeerEvents.apply(this, arguments);
  956. newResourceIds = span.resourceId ? [span.resourceId] : event ? this.getEventResourceIds(event) : [];
  957. filteredPeerEvents = [];
  958. for (j = 0, len = peerEvents.length; j < len; j++) {
  959. peerEvent = peerEvents[j];
  960. isPeer = false;
  961. peerResourceIds = this.getEventResourceIds(peerEvent);
  962. if (!peerResourceIds.length || !newResourceIds.length) {
  963. isPeer = true;
  964. } else {
  965. for (k = 0, len1 = peerResourceIds.length; k < len1; k++) {
  966. peerResourceId = peerResourceIds[k];
  967. for (l = 0, len2 = newResourceIds.length; l < len2; l++) {
  968. newResourceId = newResourceIds[l];
  969. if (newResourceId === peerResourceId) {
  970. isPeer = true;
  971. break;
  972. }
  973. }
  974. }
  975. }
  976. if (isPeer) {
  977. filteredPeerEvents.push(peerEvent);
  978. }
  979. }
  980. return filteredPeerEvents;
  981. };
  982. CalendarExtension.prototype.spanContainsSpan = function (outerSpan, innerSpan) {
  983. if (outerSpan.resourceId && outerSpan.resourceId !== innerSpan.resourceId) {
  984. return false;
  985. } else {
  986. return CalendarExtension.__super__.spanContainsSpan.apply(this, arguments);
  987. }
  988. };
  989. CalendarExtension.prototype.getCurrentBusinessHourEvents = function (wholeDay) {
  990. var allEvents, anyCustomBusinessHours, event, events, flatResources, j, k, l, len, len1, len2, resource;
  991. flatResources = this.resourceManager.getFlatResources();
  992. anyCustomBusinessHours = false;
  993. for (j = 0, len = flatResources.length; j < len; j++) {
  994. resource = flatResources[j];
  995. if (resource.businessHours) {
  996. anyCustomBusinessHours = true;
  997. }
  998. }
  999. if (anyCustomBusinessHours) {
  1000. allEvents = [];
  1001. for (k = 0, len1 = flatResources.length; k < len1; k++) {
  1002. resource = flatResources[k];
  1003. events = this.computeBusinessHourEvents(wholeDay, resource.businessHours || this.options.businessHours);
  1004. for (l = 0, len2 = events.length; l < len2; l++) {
  1005. event = events[l];
  1006. event.resourceId = resource.id;
  1007. allEvents.push(event);
  1008. }
  1009. }
  1010. return allEvents;
  1011. } else {
  1012. return CalendarExtension.__super__.getCurrentBusinessHourEvents.apply(this, arguments);
  1013. }
  1014. };
  1015. CalendarExtension.prototype.buildSelectSpan = function (startInput, endInput, resourceId) {
  1016. var span;
  1017. span = CalendarExtension.__super__.buildSelectSpan.apply(this, arguments);
  1018. if (resourceId) {
  1019. span.resourceId = resourceId;
  1020. }
  1021. return span;
  1022. };
  1023. CalendarExtension.prototype.getResourceById = function (id) {
  1024. return this.resourceManager.getResourceById(id);
  1025. };
  1026. CalendarExtension.prototype.normalizeEvent = function (event) {
  1027. CalendarExtension.__super__.normalizeEvent.apply(this, arguments);
  1028. if (event.resourceId == null) {
  1029. event.resourceId = null;
  1030. }
  1031. return event.resourceIds != null ? event.resourceIds : event.resourceIds = null;
  1032. };
  1033. CalendarExtension.prototype.getEventResourceId = function (event) {
  1034. return this.getEventResourceIds(event)[0];
  1035. };
  1036. CalendarExtension.prototype.getEventResourceIds = function (event) {
  1037. var j, len, normalResourceId, normalResourceIds, ref, ref1, ref2, resourceId;
  1038. resourceId = String((ref = (ref1 = event[this.getEventResourceField()]) != null ? ref1 : event.resourceId) != null ? ref : '');
  1039. if (resourceId) {
  1040. return [resourceId];
  1041. } else if (event.resourceIds) {
  1042. normalResourceIds = [];
  1043. ref2 = event.resourceIds;
  1044. for (j = 0, len = ref2.length; j < len; j++) {
  1045. resourceId = ref2[j];
  1046. normalResourceId = String(resourceId != null ? resourceId : '');
  1047. if (normalResourceId) {
  1048. normalResourceIds.push(normalResourceId);
  1049. }
  1050. }
  1051. return normalResourceIds;
  1052. } else {
  1053. return [];
  1054. }
  1055. };
  1056. CalendarExtension.prototype.setEventResourceId = function (event, resourceId) {
  1057. return event[this.getEventResourceField()] = String(resourceId != null ? resourceId : '');
  1058. };
  1059. CalendarExtension.prototype.getEventResourceField = function () {
  1060. return this.options['eventResourceField'] || 'resourceId';
  1061. };
  1062. CalendarExtension.prototype.getResourceEvents = function (idOrResource) {
  1063. var resource;
  1064. resource = typeof idOrResource === 'object' ? idOrResource : this.getResourceById(idOrResource);
  1065. if (resource) {
  1066. return this.clientEvents((function (_this) {
  1067. return function (event) {
  1068. return $.inArray(resource.id, _this.getEventResourceIds(event)) !== -1;
  1069. };
  1070. })(this));
  1071. } else {
  1072. return [];
  1073. }
  1074. };
  1075. CalendarExtension.prototype.getEventResource = function (idOrEvent) {
  1076. return this.getEventResources(idOrEvent)[0];
  1077. };
  1078. CalendarExtension.prototype.getEventResources = function (idOrEvent) {
  1079. var event, j, len, ref, resource, resourceId, resources;
  1080. event = typeof idOrEvent === 'object' ? idOrEvent : this.clientEvents(idOrEvent)[0];
  1081. resources = [];
  1082. if (event) {
  1083. ref = this.getEventResourceIds(event);
  1084. for (j = 0, len = ref.length; j < len; j++) {
  1085. resourceId = ref[j];
  1086. resource = this.getResourceById(resourceId);
  1087. if (resource) {
  1088. resources.push(resource);
  1089. }
  1090. }
  1091. }
  1092. return resources;
  1093. };
  1094. return CalendarExtension;
  1095. })(Calendar);
  1096. Calendar.prototype = CalendarExtension.prototype;
  1097. origSetElement = View.prototype.setElement;
  1098. origRemoveElement = View.prototype.removeElement;
  1099. origHandleDate = View.prototype.handleDate;
  1100. origOnDateRender = View.prototype.onDateRender;
  1101. origExecuteEventsRender = View.prototype.executeEventsRender;
  1102. View.prototype.isResourcesBound = false;
  1103. View.prototype.isResourcesSet = false;
  1104. Calendar.defaults.refetchResourcesOnNavigate = false;
  1105. View.prototype.setElement = function () {
  1106. var promise;
  1107. promise = origSetElement.apply(this, arguments);
  1108. this.bindResources();
  1109. return promise;
  1110. };
  1111. View.prototype.removeElement = function () {
  1112. this.unbindResources({
  1113. skipRerender: true
  1114. });
  1115. return origRemoveElement.apply(this, arguments);
  1116. };
  1117. View.prototype.handleDate = function (date, isReset) {
  1118. if (isReset && this.opt('refetchResourcesOnNavigate')) {
  1119. this.unsetResources({
  1120. skipUnrender: true
  1121. });
  1122. this.fetchResources();
  1123. }
  1124. return origHandleDate.apply(this, arguments);
  1125. };
  1126. View.prototype.onDateRender = function () {
  1127. processLicenseKey(this.calendar.options.schedulerLicenseKey, this.el);
  1128. return origOnDateRender.apply(this, arguments);
  1129. };
  1130. View.prototype.executeEventsRender = function (events) {
  1131. return this.whenResourcesSet().then((function (_this) {
  1132. return function () {
  1133. return origExecuteEventsRender.call(_this, events);
  1134. };
  1135. })(this));
  1136. };
  1137. View.prototype.bindResources = function () {
  1138. var promise;
  1139. if (!this.isResourcesBound) {
  1140. this.isResourcesBound = true;
  1141. this.trigger('resourcesBind');
  1142. promise = this.opt('refetchResourcesOnNavigate') ? this.fetchResources() : this.requestResources();
  1143. return this.rejectOn('resourcesUnbind', promise).then((function (_this) {
  1144. return function (resources) {
  1145. _this.listenTo(_this.calendar.resourceManager, {
  1146. set: _this.setResources,
  1147. reset: _this.setResources,
  1148. unset: _this.unsetResources,
  1149. add: _this.addResource,
  1150. remove: _this.removeResource
  1151. });
  1152. return _this.setResources(resources);
  1153. };
  1154. })(this));
  1155. }
  1156. };
  1157. View.prototype.unbindResources = function (teardownOptions) {
  1158. if (this.isResourcesBound) {
  1159. this.isResourcesBound = false;
  1160. this.stopListeningTo(this.calendar.resourceManager);
  1161. this.unsetResources(teardownOptions);
  1162. return this.trigger('resourcesUnbind');
  1163. }
  1164. };
  1165. View.prototype.setResources = function (resources) {
  1166. var isReset;
  1167. isReset = this.isResourcesSet;
  1168. this.isResourcesSet = true;
  1169. this.handleResources(resources, isReset);
  1170. return this.trigger(isReset ? 'resourcesReset' : 'resourcesSet', resources);
  1171. };
  1172. View.prototype.unsetResources = function (teardownOptions) {
  1173. if (this.isResourcesSet) {
  1174. this.isResourcesSet = false;
  1175. this.handleResourcesUnset(teardownOptions);
  1176. return this.trigger('resourcesUnset');
  1177. }
  1178. };
  1179. View.prototype.whenResourcesSet = function () {
  1180. if (this.isResourcesSet) {
  1181. return Promise.resolve();
  1182. } else {
  1183. return new Promise((function (_this) {
  1184. return function (resolve) {
  1185. return _this.one('resourcesSet', resolve);
  1186. };
  1187. })(this));
  1188. }
  1189. };
  1190. View.prototype.addResource = function (resource) {
  1191. if (this.isResourcesSet) {
  1192. this.handleResourceAdd(resource);
  1193. return this.trigger('resourceAdd', resource);
  1194. }
  1195. };
  1196. View.prototype.removeResource = function (resource) {
  1197. if (this.isResourcesSet) {
  1198. this.handleResourceRemove(resource);
  1199. return this.trigger('resourceRemove', resource);
  1200. }
  1201. };
  1202. View.prototype.handleResources = function (resources) {
  1203. if (this.isEventsRendered) {
  1204. return this.requestCurrentEventsRender();
  1205. }
  1206. };
  1207. View.prototype.handleResourcesUnset = function (teardownOptions) {
  1208. if (teardownOptions == null) {
  1209. teardownOptions = {};
  1210. }
  1211. return this.requestEventsUnrender();
  1212. };
  1213. View.prototype.handleResourceAdd = function (resource) {
  1214. if (this.isEventsRendered) {
  1215. return this.requestCurrentEventsRender();
  1216. }
  1217. };
  1218. View.prototype.handleResourceRemove = function (resource) {
  1219. if (this.isEventsRendered) {
  1220. return this.requestCurrentEventsRender();
  1221. }
  1222. };
  1223. View.prototype.requestResources = function () {
  1224. return this.calendar.resourceManager.getResources();
  1225. };
  1226. View.prototype.fetchResources = function () {
  1227. return this.calendar.resourceManager.fetchResources();
  1228. };
  1229. View.prototype.getCurrentResources = function () {
  1230. return this.calendar.resourceManager.topLevelResources;
  1231. };
  1232. origGetSegCustomClasses = Grid.prototype.getSegCustomClasses;
  1233. origGetSegDefaultBackgroundColor = Grid.prototype.getSegDefaultBackgroundColor;
  1234. origGetSegDefaultBorderColor = Grid.prototype.getSegDefaultBorderColor;
  1235. origGetSegDefaultTextColor = Grid.prototype.getSegDefaultTextColor;
  1236. Grid.prototype.getSegCustomClasses = function (seg) {
  1237. var classes, j, len, ref, resource;
  1238. classes = origGetSegCustomClasses.apply(this, arguments);
  1239. ref = this.getSegResources(seg);
  1240. for (j = 0, len = ref.length; j < len; j++) {
  1241. resource = ref[j];
  1242. classes = classes.concat(resource.eventClassName || []);
  1243. }
  1244. return classes;
  1245. };
  1246. Grid.prototype.getSegDefaultBackgroundColor = function (seg) {
  1247. var currentResource, j, len, resources, val;
  1248. resources = this.getSegResources(seg);
  1249. for (j = 0, len = resources.length; j < len; j++) {
  1250. currentResource = resources[j];
  1251. while (currentResource) {
  1252. val = currentResource.eventBackgroundColor || currentResource.eventColor;
  1253. if (val) {
  1254. return val;
  1255. }
  1256. currentResource = currentResource._parent;
  1257. }
  1258. }
  1259. return origGetSegDefaultBackgroundColor.apply(this, arguments);
  1260. };
  1261. Grid.prototype.getSegDefaultBorderColor = function (seg) {
  1262. var currentResource, j, len, resources, val;
  1263. resources = this.getSegResources(seg);
  1264. for (j = 0, len = resources.length; j < len; j++) {
  1265. currentResource = resources[j];
  1266. while (currentResource) {
  1267. val = currentResource.eventBorderColor || currentResource.eventColor;
  1268. if (val) {
  1269. return val;
  1270. }
  1271. currentResource = currentResource._parent;
  1272. }
  1273. }
  1274. return origGetSegDefaultBorderColor.apply(this, arguments);
  1275. };
  1276. Grid.prototype.getSegDefaultTextColor = function (seg) {
  1277. var currentResource, j, len, resources, val;
  1278. resources = this.getSegResources(seg);
  1279. for (j = 0, len = resources.length; j < len; j++) {
  1280. currentResource = resources[j];
  1281. while (currentResource) {
  1282. val = currentResource.eventTextColor;
  1283. if (val) {
  1284. return val;
  1285. }
  1286. currentResource = currentResource._parent;
  1287. }
  1288. }
  1289. return origGetSegDefaultTextColor.apply(this, arguments);
  1290. };
  1291. Grid.prototype.getSegResources = function (seg) {
  1292. if (seg.resource) {
  1293. return [seg.resource];
  1294. } else {
  1295. return this.view.calendar.getEventResources(seg.event);
  1296. }
  1297. };
  1298. ResourceManager = (function (superClass) {
  1299. extend(ResourceManager, superClass);
  1300. ResourceManager.mixin(EmitterMixin);
  1301. ResourceManager.resourceGuid = 1;
  1302. ResourceManager.ajaxDefaults = {
  1303. dataType: 'json',
  1304. cache: false
  1305. };
  1306. ResourceManager.prototype.calendar = null;
  1307. ResourceManager.prototype.fetchId = 0;
  1308. ResourceManager.prototype.topLevelResources = null;
  1309. ResourceManager.prototype.resourcesById = null;
  1310. ResourceManager.prototype.fetching = null;
  1311. function ResourceManager(calendar1) {
  1312. this.calendar = calendar1;
  1313. this.initializeCache();
  1314. }
  1315. ResourceManager.prototype.getResources = function () {
  1316. return this.fetching || this.fetchResources();
  1317. };
  1318. ResourceManager.prototype.fetchResources = function () {
  1319. var currentFetchId;
  1320. currentFetchId = (this.fetchId += 1);
  1321. return this.fetching = new Promise((function (_this) {
  1322. return function (resolve, reject) {
  1323. return _this.fetchResourceInputs(function (resourceInputs) {
  1324. if (currentFetchId === _this.fetchId) {
  1325. _this.setResources(resourceInputs);
  1326. return resolve(_this.topLevelResources);
  1327. } else {
  1328. return reject();
  1329. }
  1330. });
  1331. };
  1332. })(this));
  1333. };
  1334. ResourceManager.prototype.fetchResourceInputs = function (callback) {
  1335. var source;
  1336. source = this.calendar.options['resources'];
  1337. if ($.type(source) === 'string') {
  1338. source = {
  1339. url: source
  1340. };
  1341. }
  1342. switch ($.type(source)) {
  1343. case 'function':
  1344. this.calendar.pushLoading();
  1345. return source((function (_this) {
  1346. return function (resourceInputs) {
  1347. _this.calendar.popLoading();
  1348. return callback(resourceInputs);
  1349. };
  1350. })(this));
  1351. case 'object':
  1352. this.calendar.pushLoading();
  1353. return $.ajax($.extend({}, ResourceManager.ajaxDefaults, source)).then((function (_this) {
  1354. return function (resourceInputs) {
  1355. _this.calendar.popLoading();
  1356. return callback(resourceInputs);
  1357. };
  1358. })(this));
  1359. case 'array':
  1360. return callback(source);
  1361. default:
  1362. return callback([]);
  1363. }
  1364. };
  1365. ResourceManager.prototype.getResourceById = function (id) {
  1366. return this.resourcesById[id];
  1367. };
  1368. ResourceManager.prototype.getFlatResources = function () {
  1369. var id, results;
  1370. results = [];
  1371. for (id in this.resourcesById) {
  1372. results.push(this.resourcesById[id]);
  1373. }
  1374. return results;
  1375. };
  1376. ResourceManager.prototype.initializeCache = function () {
  1377. this.topLevelResources = [];
  1378. return this.resourcesById = {};
  1379. };
  1380. ResourceManager.prototype.setResources = function (resourceInputs) {
  1381. var j, len, resource, resourceInput, resources, validResources, wasSet;
  1382. wasSet = Boolean(this.topLevelResources);
  1383. this.initializeCache();
  1384. resources = (function () {
  1385. var j, len, results;
  1386. results = [];
  1387. for (j = 0, len = resourceInputs.length; j < len; j++) {
  1388. resourceInput = resourceInputs[j];
  1389. results.push(this.buildResource(resourceInput));
  1390. }
  1391. return results;
  1392. }).call(this);
  1393. validResources = (function () {
  1394. var j, len, results;
  1395. results = [];
  1396. for (j = 0, len = resources.length; j < len; j++) {
  1397. resource = resources[j];
  1398. if (this.addResourceToIndex(resource)) {
  1399. results.push(resource);
  1400. }
  1401. }
  1402. return results;
  1403. }).call(this);
  1404. for (j = 0, len = validResources.length; j < len; j++) {
  1405. resource = validResources[j];
  1406. this.addResourceToTree(resource);
  1407. }
  1408. if (wasSet) {
  1409. this.trigger('reset', this.topLevelResources);
  1410. } else {
  1411. this.trigger('set', this.topLevelResources);
  1412. }
  1413. return this.calendar.publiclyTrigger('resourcesSet', null, this.topLevelResources);
  1414. };
  1415. ResourceManager.prototype.resetCurrentResources = function () {
  1416. if (this.topLevelResources) {
  1417. return this.trigger('reset', this.topLevelResources);
  1418. }
  1419. };
  1420. ResourceManager.prototype.addResource = function (resourceInput) {
  1421. return this.getResources().then((function (_this) {
  1422. return function () {
  1423. var resource;
  1424. resource = _this.buildResource(resourceInput);
  1425. if (_this.addResourceToIndex(resource)) {
  1426. _this.addResourceToTree(resource);
  1427. _this.trigger('add', resource);
  1428. return resource;
  1429. } else {
  1430. return false;
  1431. }
  1432. };
  1433. })(this));
  1434. };
  1435. ResourceManager.prototype.addResourceToIndex = function (resource) {
  1436. var child, j, len, ref;
  1437. if (this.resourcesById[resource.id]) {
  1438. return false;
  1439. } else {
  1440. this.resourcesById[resource.id] = resource;
  1441. ref = resource.children;
  1442. for (j = 0, len = ref.length; j < len; j++) {
  1443. child = ref[j];
  1444. this.addResourceToIndex(child);
  1445. }
  1446. return true;
  1447. }
  1448. };
  1449. ResourceManager.prototype.addResourceToTree = function (resource) {
  1450. var parent, parentId, ref, siblings;
  1451. if (!resource.parent) {
  1452. parentId = String((ref = resource['parentId']) != null ? ref : '');
  1453. if (parentId) {
  1454. parent = this.resourcesById[parentId];
  1455. if (parent) {
  1456. resource.parent = parent;
  1457. siblings = parent.children;
  1458. } else {
  1459. return false;
  1460. }
  1461. } else {
  1462. siblings = this.topLevelResources;
  1463. }
  1464. siblings.push(resource);
  1465. }
  1466. return true;
  1467. };
  1468. ResourceManager.prototype.removeResource = function (idOrResource) {
  1469. var id;
  1470. id = typeof idOrResource === 'object' ? idOrResource.id : idOrResource;
  1471. return this.getResources().then((function (_this) {
  1472. return function () {
  1473. var resource;
  1474. resource = _this.removeResourceFromIndex(id);
  1475. if (resource) {
  1476. _this.removeResourceFromTree(resource);
  1477. _this.trigger('remove', resource);
  1478. }
  1479. return resource;
  1480. };
  1481. })(this));
  1482. };
  1483. ResourceManager.prototype.removeResourceFromIndex = function (resourceId) {
  1484. var child, j, len, ref, resource;
  1485. resource = this.resourcesById[resourceId];
  1486. if (resource) {
  1487. delete this.resourcesById[resourceId];
  1488. ref = resource.children;
  1489. for (j = 0, len = ref.length; j < len; j++) {
  1490. child = ref[j];
  1491. this.removeResourceFromIndex(child.id);
  1492. }
  1493. return resource;
  1494. } else {
  1495. return false;
  1496. }
  1497. };
  1498. ResourceManager.prototype.removeResourceFromTree = function (resource, siblings) {
  1499. var i, j, len, sibling;
  1500. if (siblings == null) {
  1501. siblings = this.topLevelResources;
  1502. }
  1503. for (i = j = 0, len = siblings.length; j < len; i = ++j) {
  1504. sibling = siblings[i];
  1505. if (sibling === resource) {
  1506. resource.parent = null;
  1507. siblings.splice(i, 1);
  1508. return true;
  1509. }
  1510. if (this.removeResourceFromTree(resource, sibling.children)) {
  1511. return true;
  1512. }
  1513. }
  1514. return false;
  1515. };
  1516. ResourceManager.prototype.buildResource = function (resourceInput) {
  1517. var child, childInput, rawClassName, ref, resource;
  1518. resource = $.extend({}, resourceInput);
  1519. resource.id = String((ref = resourceInput.id) != null ? ref : '_fc' + ResourceManager.resourceGuid++);
  1520. rawClassName = resourceInput.eventClassName;
  1521. resource.eventClassName = (function () {
  1522. switch ($.type(rawClassName)) {
  1523. case 'string':
  1524. return rawClassName.split(/\s+/);
  1525. case 'array':
  1526. return rawClassName;
  1527. default:
  1528. return [];
  1529. }
  1530. })();
  1531. resource.children = (function () {
  1532. var j, len, ref1, ref2, results;
  1533. ref2 = (ref1 = resourceInput.children) != null ? ref1 : [];
  1534. results = [];
  1535. for (j = 0, len = ref2.length; j < len; j++) {
  1536. childInput = ref2[j];
  1537. child = this.buildResource(childInput);
  1538. child.parent = resource;
  1539. results.push(child);
  1540. }
  1541. return results;
  1542. }).call(this);
  1543. return resource;
  1544. };
  1545. return ResourceManager;
  1546. })(Class);
  1547. Calendar.defaults.filterResourcesWithEvents = false;
  1548. /*
  1549. A view that structurally distinguishes events by resource
  1550. */
  1551. ResourceViewMixin = {
  1552. isResourcesRendered: false,
  1553. isResourcesDirty: false,
  1554. resourceRenderQueue: null,
  1555. resourceTextFunc: null,
  1556. canRenderSpecificResources: false,
  1557. setElement: function () {
  1558. this.resourceRenderQueue = new TaskQueue();
  1559. return View.prototype.setElement.apply(this, arguments);
  1560. },
  1561. onDateRender: function () {
  1562. return this.rejectOn('dateUnrender', this.whenResourcesRendered()).then((function (_this) {
  1563. return function () {
  1564. return View.prototype.onDateRender.apply(_this, arguments);
  1565. };
  1566. })(this));
  1567. },
  1568. handleEvents: function (events) {
  1569. var filteredResources, resources;
  1570. if (this.opt('filterResourcesWithEvents')) {
  1571. if (this.isResourcesSet) {
  1572. resources = this.getCurrentResources();
  1573. filteredResources = this.filterResourcesWithEvents(resources, events);
  1574. return this.requestResourcesRender(filteredResources);
  1575. }
  1576. } else {
  1577. if (this.isResourcesRendered && !this.isResourcesDirty) {
  1578. return this.requestEventsRender(events);
  1579. }
  1580. }
  1581. },
  1582. handleResources: function (resources) {
  1583. var events, filteredResources;
  1584. if (this.opt('filterResourcesWithEvents')) {
  1585. if (this.isEventsSet) {
  1586. events = this.getCurrentEvents();
  1587. filteredResources = this.filterResourcesWithEvents(resources, events);
  1588. return this.requestResourcesRender(filteredResources);
  1589. }
  1590. } else {
  1591. return this.requestResourcesRender(resources);
  1592. }
  1593. },
  1594. handleResourcesUnset: function (teardownOptions) {
  1595. if (teardownOptions == null) {
  1596. teardownOptions = {};
  1597. }
  1598. if (teardownOptions.skipUnrender) {
  1599. return this.isResourcesDirty = this.isResourcesRendered;
  1600. } else {
  1601. return this.requestResourcesUnrender(teardownOptions);
  1602. }
  1603. },
  1604. handleResourceAdd: function (resource) {
  1605. var a, events;
  1606. if (this.canRenderSpecificResources) {
  1607. if (this.opt('filterResourcesWithEvents')) {
  1608. if (this.isEventsSet) {
  1609. events = this.getCurrentEvents();
  1610. a = this.filterResourcesWithEvents([resource], events);
  1611. if (a.length) {
  1612. return this.requestResourceRender(a[0]);
  1613. }
  1614. }
  1615. } else {
  1616. return this.requestResourceRender(resource);
  1617. }
  1618. } else {
  1619. return this.handleResources(this.getCurrentResources());
  1620. }
  1621. },
  1622. handleResourceRemove: function (resource) {
  1623. if (this.canRenderSpecificResources) {
  1624. return this.requestResourceUnrender(resource);
  1625. } else {
  1626. return this.handleResources(this.getCurrentResources());
  1627. }
  1628. },
  1629. requestResourcesRender: function (resources) {
  1630. return this.resourceRenderQueue.add((function (_this) {
  1631. return function () {
  1632. return _this.executeResourcesRender(resources);
  1633. };
  1634. })(this));
  1635. },
  1636. requestResourcesUnrender: function (teardownOptions) {
  1637. if (this.isResourcesRendered) {
  1638. return this.resourceRenderQueue.add((function (_this) {
  1639. return function () {
  1640. return _this.executeResourcesUnrender(teardownOptions);
  1641. };
  1642. })(this));
  1643. } else {
  1644. return Promise.resolve();
  1645. }
  1646. },
  1647. requestResourceRender: function (resource) {
  1648. return this.resourceRenderQueue.add((function (_this) {
  1649. return function () {
  1650. return _this.executeResourceRender(resource);
  1651. };
  1652. })(this));
  1653. },
  1654. requestResourceUnrender: function (resource) {
  1655. return this.resourceRenderQueue.add((function (_this) {
  1656. return function () {
  1657. return _this.executeResourceUnrender(resource);
  1658. };
  1659. })(this));
  1660. },
  1661. executeResourcesRender: function (resources) {
  1662. this.captureScroll();
  1663. this.freezeHeight();
  1664. return this.executeResourcesUnrender().then((function (_this) {
  1665. return function () {
  1666. _this.renderResources(resources);
  1667. _this.thawHeight();
  1668. _this.releaseScroll();
  1669. return _this.reportResourcesRender();
  1670. };
  1671. })(this));
  1672. },
  1673. executeResourcesUnrender: function (teardownOptions) {
  1674. if (this.isResourcesRendered) {
  1675. return this.requestEventsUnrender().then((function (_this) {
  1676. return function () {
  1677. _this.captureScroll();
  1678. _this.freezeHeight();
  1679. _this.unrenderResources(teardownOptions);
  1680. _this.thawHeight();
  1681. _this.releaseScroll();
  1682. return _this.reportResourcesUnrender();
  1683. };
  1684. })(this));
  1685. } else {
  1686. return Promise.resolve();
  1687. }
  1688. },
  1689. executeResourceRender: function (resource) {
  1690. if (this.isResourcesRendered) {
  1691. this.captureScroll();
  1692. this.freezeHeight();
  1693. this.renderResource(resource);
  1694. this.thawHeight();
  1695. return this.releaseScroll();
  1696. } else {
  1697. return Promise.reject();
  1698. }
  1699. },
  1700. executeResourceUnrender: function (resource) {
  1701. if (this.isResourcesRendered) {
  1702. this.captureScroll();
  1703. this.freezeHeight();
  1704. this.unrenderResource(resource);
  1705. this.thawHeight();
  1706. return this.releaseScroll();
  1707. } else {
  1708. return Promise.reject();
  1709. }
  1710. },
  1711. reportResourcesRender: function () {
  1712. this.isResourcesRendered = true;
  1713. this.trigger('resourcesRender');
  1714. if (this.isEventsSet) {
  1715. this.requestEventsRender(this.getCurrentEvents());
  1716. }
  1717. },
  1718. reportResourcesUnrender: function () {
  1719. this.isResourcesRendered = false;
  1720. return this.isResourcesDirty = false;
  1721. },
  1722. whenResourcesRendered: function () {
  1723. if (this.isResourcesRendered && !this.isResourcesDirty) {
  1724. return Promise.resolve();
  1725. } else {
  1726. return new Promise((function (_this) {
  1727. return function (resolve) {
  1728. return _this.one('resourcesRender', resolve);
  1729. };
  1730. })(this));
  1731. }
  1732. },
  1733. renderResources: function (resources) { },
  1734. unrenderResources: function (teardownOptions) { },
  1735. renderResource: function (resource) { },
  1736. unrenderResource: function (resource) { },
  1737. isEventDraggable: function (event) {
  1738. return this.isEventResourceEditable(event) || View.prototype.isEventDraggable.call(this, event);
  1739. },
  1740. isEventResourceEditable: function (event) {
  1741. var ref, ref1, ref2;
  1742. return (ref = (ref1 = (ref2 = event.resourceEditable) != null ? ref2 : (event.source || {}).resourceEditable) != null ? ref1 : this.opt('eventResourceEditable')) != null ? ref : this.isEventGenerallyEditable(event);
  1743. },
  1744. getResourceText: function (resource) {
  1745. return this.getResourceTextFunc()(resource);
  1746. },
  1747. getResourceTextFunc: function () {
  1748. var func;
  1749. if (this.resourceTextFunc) {
  1750. return this.resourceTextFunc;
  1751. } else {
  1752. func = this.opt('resourceText');
  1753. if (typeof func !== 'function') {
  1754. func = function (resource) {
  1755. return resource.title || resource.id;
  1756. };
  1757. }
  1758. return this.resourceTextFunc = func;
  1759. }
  1760. },
  1761. triggerDayClick: function (span, dayEl, ev) {
  1762. var resourceManager;
  1763. resourceManager = this.calendar.resourceManager;
  1764. return this.publiclyTrigger('dayClick', dayEl, this.calendar.applyTimezone(span.start), ev, this, resourceManager.getResourceById(span.resourceId));
  1765. },
  1766. triggerSelect: function (span, ev) {
  1767. var resourceManager;
  1768. resourceManager = this.calendar.resourceManager;
  1769. return this.publiclyTrigger('select', null, this.calendar.applyTimezone(span.start), this.calendar.applyTimezone(span.end), ev, this, resourceManager.getResourceById(span.resourceId));
  1770. },
  1771. triggerExternalDrop: function (event, dropLocation, el, ev, ui) {
  1772. this.publiclyTrigger('drop', el[0], dropLocation.start, ev, ui, dropLocation.resourceId);
  1773. if (event) {
  1774. return this.publiclyTrigger('eventReceive', null, event);
  1775. }
  1776. },
  1777. /* Hacks
  1778. * ------------------------------------------------------------------------------------------------------------------
  1779. These triggers usually call mutateEvent with dropLocation, which causes an event modification and rerender.
  1780. But mutateEvent isn't aware of eventResourceField, so it might be setting the wrong property. Workaround.
  1781. TODO: normalize somewhere else. maybe make a hook in core.
  1782. */
  1783. reportEventDrop: function () {
  1784. var dropLocation, event, otherArgs, ref;
  1785. event = arguments[0], dropLocation = arguments[1], otherArgs = 3 <= arguments.length ? slice.call(arguments, 2) : [];
  1786. dropLocation = this.normalizeDropLocation(dropLocation);
  1787. if (dropLocation.resourceId && event.resourceIds) {
  1788. dropLocation.resourceIds = null;
  1789. }
  1790. return (ref = View.prototype.reportEventDrop).call.apply(ref, [this, event, dropLocation].concat(slice.call(otherArgs)));
  1791. },
  1792. reportExternalDrop: function () {
  1793. var dropLocation, meta, otherArgs, ref;
  1794. meta = arguments[0], dropLocation = arguments[1], otherArgs = 3 <= arguments.length ? slice.call(arguments, 2) : [];
  1795. dropLocation = this.normalizeDropLocation(dropLocation);
  1796. return (ref = View.prototype.reportExternalDrop).call.apply(ref, [this, meta, dropLocation].concat(slice.call(otherArgs)));
  1797. },
  1798. normalizeDropLocation: function (dropLocation) {
  1799. var out;
  1800. out = $.extend({}, dropLocation);
  1801. delete out.resourceId;
  1802. this.calendar.setEventResourceId(out, dropLocation.resourceId);
  1803. return out;
  1804. },
  1805. filterResourcesWithEvents: function (resources, events) {
  1806. var event, j, k, len, len1, ref, resourceId, resourceIdHits;
  1807. resourceIdHits = {};
  1808. for (j = 0, len = events.length; j < len; j++) {
  1809. event = events[j];
  1810. ref = this.calendar.getEventResourceIds(event);
  1811. for (k = 0, len1 = ref.length; k < len1; k++) {
  1812. resourceId = ref[k];
  1813. resourceIdHits[resourceId] = true;
  1814. }
  1815. }
  1816. return _filterResourcesWithEvents(resources, resourceIdHits);
  1817. }
  1818. };
  1819. _filterResourcesWithEvents = function (sourceResources, resourceIdHits) {
  1820. var filteredChildren, filteredResource, filteredResources, j, len, sourceResource;
  1821. filteredResources = [];
  1822. for (j = 0, len = sourceResources.length; j < len; j++) {
  1823. sourceResource = sourceResources[j];
  1824. if (sourceResource.children.length) {
  1825. filteredChildren = _filterResourcesWithEvents(sourceResource.children, resourceIdHits);
  1826. if (filteredChildren.length || resourceIdHits[sourceResource.id]) {
  1827. filteredResource = createObject(sourceResource);
  1828. filteredResource.children = filteredChildren;
  1829. filteredResources.push(filteredResource);
  1830. }
  1831. } else {
  1832. if (resourceIdHits[sourceResource.id]) {
  1833. filteredResources.push(sourceResource);
  1834. }
  1835. }
  1836. }
  1837. return filteredResources;
  1838. };
  1839. /*
  1840. For vertical resource view.
  1841. For views that rely on grids that don't render their resources and dates together.
  1842. */
  1843. VertResourceViewMixin = $.extend({}, ResourceViewMixin, {
  1844. executeResourcesRender: function (resources) {
  1845. this.setResourcesOnGrids(resources);
  1846. if (this.isDateRendered) {
  1847. return this.requestDateRender().then((function (_this) {
  1848. return function () {
  1849. return _this.reportResourcesRender();
  1850. };
  1851. })(this));
  1852. } else {
  1853. return Promise.resolve();
  1854. }
  1855. },
  1856. executeResourcesUnrender: function (teardownOptions) {
  1857. if (teardownOptions == null) {
  1858. teardownOptions = {};
  1859. }
  1860. this.unsetResourcesOnGrids();
  1861. if (this.isDateRendered && !teardownOptions.skipRerender) {
  1862. return this.requestDateRender().then((function (_this) {
  1863. return function () {
  1864. return _this.reportResourcesUnrender();
  1865. };
  1866. })(this));
  1867. } else {
  1868. this.reportResourcesUnrender();
  1869. return Promise.resolve();
  1870. }
  1871. },
  1872. executeDateRender: function (date) {
  1873. return View.prototype.executeDateRender.apply(this, arguments).then((function (_this) {
  1874. return function () {
  1875. if (_this.isResourcesSet) {
  1876. return _this.reportResourcesRender();
  1877. }
  1878. };
  1879. })(this));
  1880. },
  1881. executeDateUnrender: function (date) {
  1882. return View.prototype.executeDateUnrender.apply(this, arguments).then((function (_this) {
  1883. return function () {
  1884. if (_this.isResourcesSet) {
  1885. return _this.reportResourcesUnrender();
  1886. }
  1887. };
  1888. })(this));
  1889. },
  1890. setResourcesOnGrids: function (resources) { },
  1891. unsetResourcesOnGrids: function () { }
  1892. });
  1893. ResourceGridMixin = {
  1894. allowCrossResource: true,
  1895. eventRangeToSpans: function (range, event) {
  1896. var j, len, resourceId, resourceIds, results;
  1897. resourceIds = this.view.calendar.getEventResourceIds(event);
  1898. if (resourceIds.length) {
  1899. results = [];
  1900. for (j = 0, len = resourceIds.length; j < len; j++) {
  1901. resourceId = resourceIds[j];
  1902. results.push($.extend({}, range, {
  1903. resourceId: resourceId
  1904. }));
  1905. }
  1906. return results;
  1907. } else if (FC.isBgEvent(event)) {
  1908. return Grid.prototype.eventRangeToSpans.apply(this, arguments);
  1909. } else {
  1910. return [];
  1911. }
  1912. },
  1913. fabricateHelperEvent: function (eventLocation, seg) {
  1914. var event;
  1915. event = Grid.prototype.fabricateHelperEvent.apply(this, arguments);
  1916. this.view.calendar.setEventResourceId(event, eventLocation.resourceId);
  1917. return event;
  1918. },
  1919. computeEventDrop: function (startSpan, endSpan, event) {
  1920. var dropLocation;
  1921. if (this.view.isEventStartEditable(event)) {
  1922. dropLocation = Grid.prototype.computeEventDrop.apply(this, arguments);
  1923. } else {
  1924. dropLocation = FC.pluckEventDateProps(event);
  1925. }
  1926. if (dropLocation) {
  1927. if (this.view.isEventResourceEditable(event)) {
  1928. dropLocation.resourceId = endSpan.resourceId;
  1929. } else {
  1930. dropLocation.resourceId = startSpan.resourceId;
  1931. }
  1932. }
  1933. return dropLocation;
  1934. },
  1935. computeExternalDrop: function (span, meta) {
  1936. var dropLocation;
  1937. dropLocation = Grid.prototype.computeExternalDrop.apply(this, arguments);
  1938. if (dropLocation) {
  1939. dropLocation.resourceId = span.resourceId;
  1940. }
  1941. return dropLocation;
  1942. },
  1943. computeEventResize: function (type, startSpan, endSpan, event) {
  1944. var resizeLocation;
  1945. if (!this.allowCrossResource && startSpan.resourceId !== endSpan.resourceId) {
  1946. return;
  1947. }
  1948. resizeLocation = Grid.prototype.computeEventResize.apply(this, arguments);
  1949. if (resizeLocation) {
  1950. resizeLocation.resourceId = startSpan.resourceId;
  1951. }
  1952. return resizeLocation;
  1953. },
  1954. computeSelectionSpan: function (startSpan, endSpan) {
  1955. var selectionSpan;
  1956. if (!this.allowCrossResource && startSpan.resourceId !== endSpan.resourceId) {
  1957. return;
  1958. }
  1959. selectionSpan = Grid.prototype.computeSelectionSpan.apply(this, arguments);
  1960. if (selectionSpan) {
  1961. selectionSpan.resourceId = startSpan.resourceId;
  1962. }
  1963. return selectionSpan;
  1964. }
  1965. };
  1966. /*
  1967. Requirements:
  1968. - must be a Grid
  1969. - grid must have a view that's a ResourceView
  1970. - DayTableMixin must already be mixed in
  1971. */
  1972. ResourceDayTableMixin = {
  1973. flattenedResources: null,
  1974. resourceCnt: 0,
  1975. datesAboveResources: false,
  1976. allowCrossResource: false,
  1977. setResources: function (resources) {
  1978. this.flattenedResources = this.flattenResources(resources);
  1979. this.resourceCnt = this.flattenedResources.length;
  1980. return this.updateDayTableCols();
  1981. },
  1982. unsetResources: function () {
  1983. this.flattenedResources = null;
  1984. this.resourceCnt = 0;
  1985. return this.updateDayTableCols();
  1986. },
  1987. flattenResources: function (resources) {
  1988. var orderSpecs, orderVal, res, sortFunc;
  1989. orderVal = this.view.opt('resourceOrder');
  1990. if (orderVal) {
  1991. orderSpecs = parseFieldSpecs(orderVal);
  1992. sortFunc = function (a, b) {
  1993. return compareByFieldSpecs(a, b, orderSpecs);
  1994. };
  1995. } else {
  1996. sortFunc = null;
  1997. }
  1998. res = [];
  1999. this.accumulateResources(resources, sortFunc, res);
  2000. return res;
  2001. },
  2002. accumulateResources: function (resources, sortFunc, res) {
  2003. var j, len, resource, results, sortedResources;
  2004. if (sortFunc) {
  2005. sortedResources = resources.slice(0);
  2006. sortedResources.sort(sortFunc);
  2007. } else {
  2008. sortedResources = resources;
  2009. }
  2010. results = [];
  2011. for (j = 0, len = sortedResources.length; j < len; j++) {
  2012. resource = sortedResources[j];
  2013. res.push(resource);
  2014. results.push(this.accumulateResources(resource.children, sortFunc, res));
  2015. }
  2016. return results;
  2017. },
  2018. updateDayTableCols: function () {
  2019. this.datesAboveResources = this.view.opt('groupByDateAndResource');
  2020. return FC.DayTableMixin.updateDayTableCols.call(this);
  2021. },
  2022. computeColCnt: function () {
  2023. return (this.resourceCnt || 1) * this.daysPerRow;
  2024. },
  2025. getColDayIndex: function (col) {
  2026. if (this.isRTL) {
  2027. col = this.colCnt - 1 - col;
  2028. }
  2029. if (this.datesAboveResources) {
  2030. return Math.floor(col / (this.resourceCnt || 1));
  2031. } else {
  2032. return col % this.daysPerRow;
  2033. }
  2034. },
  2035. getColResource: function (col) {
  2036. return this.flattenedResources[this.getColResourceIndex(col)];
  2037. },
  2038. getColResourceIndex: function (col) {
  2039. if (this.isRTL) {
  2040. col = this.colCnt - 1 - col;
  2041. }
  2042. if (this.datesAboveResources) {
  2043. return col % (this.resourceCnt || 1);
  2044. } else {
  2045. return Math.floor(col / this.daysPerRow);
  2046. }
  2047. },
  2048. indicesToCol: function (resourceIndex, dayIndex) {
  2049. var col;
  2050. col = this.datesAboveResources ? dayIndex * (this.resourceCnt || 1) + resourceIndex : resourceIndex * this.daysPerRow + dayIndex;
  2051. if (this.isRTL) {
  2052. col = this.colCnt - 1 - col;
  2053. }
  2054. return col;
  2055. },
  2056. renderHeadTrHtml: function () {
  2057. if (!this.resourceCnt) {
  2058. return FC.DayTableMixin.renderHeadTrHtml.call(this);
  2059. } else {
  2060. if (this.daysPerRow > 1) {
  2061. if (this.datesAboveResources) {
  2062. return this.renderHeadDateAndResourceHtml();
  2063. } else {
  2064. return this.renderHeadResourceAndDateHtml();
  2065. }
  2066. } else {
  2067. return this.renderHeadResourceHtml();
  2068. }
  2069. }
  2070. },
  2071. renderHeadResourceHtml: function () {
  2072. var j, len, ref, resource, resourceHtmls;
  2073. resourceHtmls = [];
  2074. ref = this.flattenedResources;
  2075. for (j = 0, len = ref.length; j < len; j++) {
  2076. resource = ref[j];
  2077. resourceHtmls.push(this.renderHeadResourceCellHtml(resource));
  2078. }
  2079. return this.wrapTr(resourceHtmls, 'renderHeadIntroHtml');
  2080. },
  2081. renderHeadResourceAndDateHtml: function () {
  2082. var date, dateHtmls, dayIndex, j, k, len, ref, ref1, resource, resourceHtmls;
  2083. resourceHtmls = [];
  2084. dateHtmls = [];
  2085. ref = this.flattenedResources;
  2086. for (j = 0, len = ref.length; j < len; j++) {
  2087. resource = ref[j];
  2088. resourceHtmls.push(this.renderHeadResourceCellHtml(resource, null, this.daysPerRow));
  2089. for (dayIndex = k = 0, ref1 = this.daysPerRow; k < ref1; dayIndex = k += 1) {
  2090. date = this.dayDates[dayIndex].clone();
  2091. dateHtmls.push(this.renderHeadResourceDateCellHtml(date, resource));
  2092. }
  2093. }
  2094. return this.wrapTr(resourceHtmls, 'renderHeadIntroHtml') + this.wrapTr(dateHtmls, 'renderHeadIntroHtml');
  2095. },
  2096. renderHeadDateAndResourceHtml: function () {
  2097. var date, dateHtmls, dayIndex, j, k, len, ref, ref1, resource, resourceHtmls;
  2098. dateHtmls = [];
  2099. resourceHtmls = [];
  2100. for (dayIndex = j = 0, ref = this.daysPerRow; j < ref; dayIndex = j += 1) {
  2101. date = this.dayDates[dayIndex].clone();
  2102. dateHtmls.push(this.renderHeadDateCellHtml(date, this.resourceCnt));
  2103. ref1 = this.flattenedResources;
  2104. for (k = 0, len = ref1.length; k < len; k++) {
  2105. resource = ref1[k];
  2106. resourceHtmls.push(this.renderHeadResourceCellHtml(resource, date));
  2107. }
  2108. }
  2109. return this.wrapTr(dateHtmls, 'renderHeadIntroHtml') + this.wrapTr(resourceHtmls, 'renderHeadIntroHtml');
  2110. },
  2111. renderHeadResourceCellHtml: function (resource, date, colspan) {
  2112. return '<th class="fc-resource-cell"' + ' data-resource-id="' + resource.id + '"' + (date ? ' data-date="' + date.format('YYYY-MM-DD') + '"' : '') + (colspan > 1 ? ' colspan="' + colspan + '"' : '') + '>' + htmlEscape(this.view.getResourceText(resource)) + '</th>';
  2113. },
  2114. renderHeadResourceDateCellHtml: function (date, resource, colspan) {
  2115. return this.renderHeadDateCellHtml(date, colspan, 'data-resource-id="' + resource.id + '"');
  2116. },
  2117. processHeadResourceEls: function (containerEl) {
  2118. return containerEl.find('.fc-resource-cell').each((function (_this) {
  2119. return function (col, node) {
  2120. var resource;
  2121. if (_this.datesAboveResources) {
  2122. resource = _this.getColResource(col);
  2123. } else {
  2124. resource = _this.flattenedResources[_this.isRTL ? _this.flattenedResources.length - 1 - col : col];
  2125. }
  2126. return _this.view.publiclyTrigger('resourceRender', resource, resource, $(node), $());
  2127. };
  2128. })(this));
  2129. },
  2130. renderBgCellsHtml: function (row) {
  2131. var col, date, htmls, j, ref, resource;
  2132. if (!this.resourceCnt) {
  2133. return FC.DayTableMixin.renderBgCellsHtml.call(this, row);
  2134. } else {
  2135. htmls = [];
  2136. for (col = j = 0, ref = this.colCnt; j < ref; col = j += 1) {
  2137. date = this.getCellDate(row, col);
  2138. resource = this.getColResource(col);
  2139. htmls.push(this.renderResourceBgCellHtml(date, resource));
  2140. }
  2141. return htmls.join('');
  2142. }
  2143. },
  2144. renderResourceBgCellHtml: function (date, resource) {
  2145. return this.renderBgCellHtml(date, 'data-resource-id="' + resource.id + '"');
  2146. },
  2147. wrapTr: function (cellHtmls, introMethodName) {
  2148. if (this.isRTL) {
  2149. cellHtmls.reverse();
  2150. return '<tr>' + cellHtmls.join('') + this[introMethodName]() + '</tr>';
  2151. } else {
  2152. return '<tr>' + this[introMethodName]() + cellHtmls.join('') + '</tr>';
  2153. }
  2154. },
  2155. /*
  2156. If there are no per-resource business hour definitions, returns null.
  2157. Otherwise, returns a list of business hours segs for *every* resource.
  2158. */
  2159. computePerResourceBusinessHourSegs: function (wholeDay) {
  2160. var allSegs, anyCustomBusinessHours, businessHours, event, events, j, k, l, len, len1, len2, ref, ref1, resource, segs;
  2161. if (this.flattenedResources) {
  2162. anyCustomBusinessHours = false;
  2163. ref = this.flattenedResources;
  2164. for (j = 0, len = ref.length; j < len; j++) {
  2165. resource = ref[j];
  2166. if (resource.businessHours) {
  2167. anyCustomBusinessHours = true;
  2168. }
  2169. }
  2170. if (anyCustomBusinessHours) {
  2171. allSegs = [];
  2172. ref1 = this.flattenedResources;
  2173. for (k = 0, len1 = ref1.length; k < len1; k++) {
  2174. resource = ref1[k];
  2175. businessHours = resource.businessHours || this.view.calendar.options.businessHours;
  2176. events = this.buildBusinessHourEvents(wholeDay, businessHours);
  2177. for (l = 0, len2 = events.length; l < len2; l++) {
  2178. event = events[l];
  2179. event.resourceId = resource.id;
  2180. }
  2181. segs = this.eventsToSegs(events);
  2182. allSegs.push.apply(allSegs, segs);
  2183. }
  2184. return allSegs;
  2185. }
  2186. }
  2187. return null;
  2188. }
  2189. };
  2190. ResourceDayGrid = (function (superClass) {
  2191. extend(ResourceDayGrid, superClass);
  2192. function ResourceDayGrid() {
  2193. return ResourceDayGrid.__super__.constructor.apply(this, arguments);
  2194. }
  2195. ResourceDayGrid.mixin(ResourceGridMixin);
  2196. ResourceDayGrid.mixin(ResourceDayTableMixin);
  2197. ResourceDayGrid.prototype.getHitSpan = function (hit) {
  2198. var span;
  2199. span = ResourceDayGrid.__super__.getHitSpan.apply(this, arguments);
  2200. if (this.resourceCnt) {
  2201. span.resourceId = this.getColResource(hit.col).id;
  2202. }
  2203. return span;
  2204. };
  2205. ResourceDayGrid.prototype.spanToSegs = function (span) {
  2206. var copy, genericSegs, j, k, l, len, len1, ref, resourceCnt, resourceIndex, resourceObj, resourceSegs, seg;
  2207. resourceCnt = this.resourceCnt;
  2208. genericSegs = this.datesAboveResources ? this.sliceRangeByDay(span) : this.sliceRangeByRow(span);
  2209. if (!resourceCnt) {
  2210. for (j = 0, len = genericSegs.length; j < len; j++) {
  2211. seg = genericSegs[j];
  2212. if (this.isRTL) {
  2213. seg.leftCol = seg.lastRowDayIndex;
  2214. seg.rightCol = seg.firstRowDayIndex;
  2215. } else {
  2216. seg.leftCol = seg.firstRowDayIndex;
  2217. seg.rightCol = seg.lastRowDayIndex;
  2218. }
  2219. }
  2220. return genericSegs;
  2221. } else {
  2222. resourceSegs = [];
  2223. for (k = 0, len1 = genericSegs.length; k < len1; k++) {
  2224. seg = genericSegs[k];
  2225. for (resourceIndex = l = 0, ref = resourceCnt; l < ref; resourceIndex = l += 1) {
  2226. resourceObj = this.flattenedResources[resourceIndex];
  2227. if (!span.resourceId || span.resourceId === resourceObj.id) {
  2228. copy = $.extend({}, seg);
  2229. copy.resource = resourceObj;
  2230. if (this.isRTL) {
  2231. copy.leftCol = this.indicesToCol(resourceIndex, seg.lastRowDayIndex);
  2232. copy.rightCol = this.indicesToCol(resourceIndex, seg.firstRowDayIndex);
  2233. } else {
  2234. copy.leftCol = this.indicesToCol(resourceIndex, seg.firstRowDayIndex);
  2235. copy.rightCol = this.indicesToCol(resourceIndex, seg.lastRowDayIndex);
  2236. }
  2237. resourceSegs.push(copy);
  2238. }
  2239. }
  2240. }
  2241. return resourceSegs;
  2242. }
  2243. };
  2244. ResourceDayGrid.prototype.renderBusinessHours = function () {
  2245. var segs;
  2246. segs = this.computePerResourceBusinessHourSegs(true);
  2247. if (segs) {
  2248. return this.renderFill('businessHours', segs, 'bgevent');
  2249. } else {
  2250. return ResourceDayGrid.__super__.renderBusinessHours.apply(this, arguments);
  2251. }
  2252. };
  2253. return ResourceDayGrid;
  2254. })(FC.DayGrid);
  2255. ResourceTimeGrid = (function (superClass) {
  2256. extend(ResourceTimeGrid, superClass);
  2257. function ResourceTimeGrid() {
  2258. return ResourceTimeGrid.__super__.constructor.apply(this, arguments);
  2259. }
  2260. ResourceTimeGrid.mixin(ResourceGridMixin);
  2261. ResourceTimeGrid.mixin(ResourceDayTableMixin);
  2262. ResourceTimeGrid.prototype.getHitSpan = function (hit) {
  2263. var span;
  2264. span = ResourceTimeGrid.__super__.getHitSpan.apply(this, arguments);
  2265. if (this.resourceCnt) {
  2266. span.resourceId = this.getColResource(hit.col).id;
  2267. }
  2268. return span;
  2269. };
  2270. ResourceTimeGrid.prototype.spanToSegs = function (span) {
  2271. var copy, genericSegs, j, k, l, len, len1, ref, resourceCnt, resourceIndex, resourceObj, resourceSegs, seg;
  2272. resourceCnt = this.resourceCnt;
  2273. genericSegs = this.sliceRangeByTimes(span);
  2274. if (!resourceCnt) {
  2275. for (j = 0, len = genericSegs.length; j < len; j++) {
  2276. seg = genericSegs[j];
  2277. seg.col = seg.dayIndex;
  2278. }
  2279. return genericSegs;
  2280. } else {
  2281. resourceSegs = [];
  2282. for (k = 0, len1 = genericSegs.length; k < len1; k++) {
  2283. seg = genericSegs[k];
  2284. for (resourceIndex = l = 0, ref = resourceCnt; l < ref; resourceIndex = l += 1) {
  2285. resourceObj = this.flattenedResources[resourceIndex];
  2286. if (!span.resourceId || span.resourceId === resourceObj.id) {
  2287. copy = $.extend({}, seg);
  2288. copy.resource = resourceObj;
  2289. copy.col = this.indicesToCol(resourceIndex, seg.dayIndex);
  2290. resourceSegs.push(copy);
  2291. }
  2292. }
  2293. }
  2294. return resourceSegs;
  2295. }
  2296. };
  2297. ResourceTimeGrid.prototype.renderBusinessHours = function () {
  2298. var segs;
  2299. segs = this.computePerResourceBusinessHourSegs(false);
  2300. if (segs) {
  2301. return this.renderBusinessSegs(segs);
  2302. } else {
  2303. return ResourceTimeGrid.__super__.renderBusinessHours.apply(this, arguments);
  2304. }
  2305. };
  2306. return ResourceTimeGrid;
  2307. })(FC.TimeGrid);
  2308. TimelineView = (function (superClass) {
  2309. extend(TimelineView, superClass);
  2310. function TimelineView() {
  2311. return TimelineView.__super__.constructor.apply(this, arguments);
  2312. }
  2313. TimelineView.prototype.timeGrid = null;
  2314. TimelineView.prototype.isScrolled = false;
  2315. TimelineView.prototype.initialize = function () {
  2316. this.timeGrid = this.instantiateGrid();
  2317. return this.intervalDuration = this.timeGrid.duration;
  2318. };
  2319. TimelineView.prototype.instantiateGrid = function () {
  2320. return new TimelineGrid(this);
  2321. };
  2322. TimelineView.prototype.setRange = function (range) {
  2323. TimelineView.__super__.setRange.apply(this, arguments);
  2324. return this.timeGrid.setRange(range);
  2325. };
  2326. TimelineView.prototype.renderSkeleton = function () {
  2327. this.el.addClass('fc-timeline');
  2328. if (this.opt('eventOverlap') === false) {
  2329. this.el.addClass('fc-no-overlap');
  2330. }
  2331. this.el.html(this.renderSkeletonHtml());
  2332. return this.renderTimeGridSkeleton();
  2333. };
  2334. TimelineView.prototype.renderSkeletonHtml = function () {
  2335. return '<table> <thead class="fc-head"> <tr> <td class="fc-time-area ' + this.widgetHeaderClass + '"></td> </tr> </thead> <tbody class="fc-body"> <tr> <td class="fc-time-area ' + this.widgetContentClass + '"></td> </tr> </tbody> </table>';
  2336. };
  2337. TimelineView.prototype.renderTimeGridSkeleton = function () {
  2338. this.timeGrid.setElement(this.el.find('tbody .fc-time-area'));
  2339. this.timeGrid.headEl = this.el.find('thead .fc-time-area');
  2340. this.timeGrid.renderSkeleton();
  2341. this.isScrolled = false;
  2342. return this.timeGrid.bodyScroller.on('scroll', proxy(this, 'handleBodyScroll'));
  2343. };
  2344. TimelineView.prototype.handleBodyScroll = function (top, left) {
  2345. if (top) {
  2346. if (!this.isScrolled) {
  2347. this.isScrolled = true;
  2348. return this.el.addClass('fc-scrolled');
  2349. }
  2350. } else {
  2351. if (this.isScrolled) {
  2352. this.isScrolled = false;
  2353. return this.el.removeClass('fc-scrolled');
  2354. }
  2355. }
  2356. };
  2357. TimelineView.prototype.unrenderSkeleton = function () {
  2358. this.timeGrid.removeElement();
  2359. this.handleBodyScroll(0);
  2360. return TimelineView.__super__.unrenderSkeleton.apply(this, arguments);
  2361. };
  2362. TimelineView.prototype.renderDates = function () {
  2363. return this.timeGrid.renderDates();
  2364. };
  2365. TimelineView.prototype.unrenderDates = function () {
  2366. return this.timeGrid.unrenderDates();
  2367. };
  2368. TimelineView.prototype.renderBusinessHours = function () {
  2369. return this.timeGrid.renderBusinessHours();
  2370. };
  2371. TimelineView.prototype.unrenderBusinessHours = function () {
  2372. return this.timeGrid.unrenderBusinessHours();
  2373. };
  2374. TimelineView.prototype.getNowIndicatorUnit = function () {
  2375. return this.timeGrid.getNowIndicatorUnit();
  2376. };
  2377. TimelineView.prototype.renderNowIndicator = function (date) {
  2378. return this.timeGrid.renderNowIndicator(date);
  2379. };
  2380. TimelineView.prototype.unrenderNowIndicator = function () {
  2381. return this.timeGrid.unrenderNowIndicator();
  2382. };
  2383. TimelineView.prototype.prepareHits = function () {
  2384. return this.timeGrid.prepareHits();
  2385. };
  2386. TimelineView.prototype.releaseHits = function () {
  2387. return this.timeGrid.releaseHits();
  2388. };
  2389. TimelineView.prototype.queryHit = function (leftOffset, topOffset) {
  2390. return this.timeGrid.queryHit(leftOffset, topOffset);
  2391. };
  2392. TimelineView.prototype.getHitSpan = function (hit) {
  2393. return this.timeGrid.getHitSpan(hit);
  2394. };
  2395. TimelineView.prototype.getHitEl = function (hit) {
  2396. return this.timeGrid.getHitEl(hit);
  2397. };
  2398. TimelineView.prototype.updateWidth = function () {
  2399. return this.timeGrid.updateWidth();
  2400. };
  2401. TimelineView.prototype.setHeight = function (totalHeight, isAuto) {
  2402. var bodyHeight;
  2403. if (isAuto) {
  2404. bodyHeight = 'auto';
  2405. } else {
  2406. bodyHeight = totalHeight - this.timeGrid.headHeight() - this.queryMiscHeight();
  2407. }
  2408. return this.timeGrid.bodyScroller.setHeight(bodyHeight);
  2409. };
  2410. TimelineView.prototype.queryMiscHeight = function () {
  2411. return this.el.outerHeight() - this.timeGrid.headScroller.el.outerHeight() - this.timeGrid.bodyScroller.el.outerHeight();
  2412. };
  2413. TimelineView.prototype.computeInitialScroll = function () {
  2414. var left, scrollTime;
  2415. left = 0;
  2416. if (this.timeGrid.isTimeScale) {
  2417. scrollTime = this.opt('scrollTime');
  2418. if (scrollTime) {
  2419. scrollTime = moment.duration(scrollTime);
  2420. left = this.timeGrid.dateToCoord(this.start.clone().time(scrollTime));
  2421. }
  2422. }
  2423. return {
  2424. left: left,
  2425. top: 0
  2426. };
  2427. };
  2428. TimelineView.prototype.queryScroll = function () {
  2429. return {
  2430. left: this.timeGrid.bodyScroller.getScrollLeft(),
  2431. top: this.timeGrid.bodyScroller.getScrollTop()
  2432. };
  2433. };
  2434. TimelineView.prototype.setScroll = function (scroll) {
  2435. this.timeGrid.headScroller.setScrollLeft(scroll.left);
  2436. this.timeGrid.bodyScroller.setScrollLeft(scroll.left);
  2437. return this.timeGrid.bodyScroller.setScrollTop(scroll.top);
  2438. };
  2439. TimelineView.prototype.renderEvents = function (events) {
  2440. this.timeGrid.renderEvents(events);
  2441. return this.updateWidth();
  2442. };
  2443. TimelineView.prototype.unrenderEvents = function () {
  2444. this.timeGrid.unrenderEvents();
  2445. return this.updateWidth();
  2446. };
  2447. TimelineView.prototype.renderDrag = function (dropLocation, seg) {
  2448. return this.timeGrid.renderDrag(dropLocation, seg);
  2449. };
  2450. TimelineView.prototype.unrenderDrag = function () {
  2451. return this.timeGrid.unrenderDrag();
  2452. };
  2453. TimelineView.prototype.getEventSegs = function () {
  2454. return this.timeGrid.getEventSegs();
  2455. };
  2456. TimelineView.prototype.renderSelection = function (range) {
  2457. return this.timeGrid.renderSelection(range);
  2458. };
  2459. TimelineView.prototype.unrenderSelection = function () {
  2460. return this.timeGrid.unrenderSelection();
  2461. };
  2462. return TimelineView;
  2463. })(View);
  2464. cssToStr = FC.cssToStr;
  2465. TimelineGrid = (function (superClass) {
  2466. extend(TimelineGrid, superClass);
  2467. TimelineGrid.prototype.slotDates = null;
  2468. TimelineGrid.prototype.slotCnt = null;
  2469. TimelineGrid.prototype.snapCnt = null;
  2470. TimelineGrid.prototype.snapsPerSlot = null;
  2471. TimelineGrid.prototype.snapDiffToIndex = null;
  2472. TimelineGrid.prototype.snapIndexToDiff = null;
  2473. TimelineGrid.prototype.headEl = null;
  2474. TimelineGrid.prototype.slatContainerEl = null;
  2475. TimelineGrid.prototype.slatEls = null;
  2476. TimelineGrid.prototype.containerCoordCache = null;
  2477. TimelineGrid.prototype.slatCoordCache = null;
  2478. TimelineGrid.prototype.slatInnerCoordCache = null;
  2479. TimelineGrid.prototype.headScroller = null;
  2480. TimelineGrid.prototype.bodyScroller = null;
  2481. TimelineGrid.prototype.joiner = null;
  2482. TimelineGrid.prototype.follower = null;
  2483. TimelineGrid.prototype.eventTitleFollower = null;
  2484. TimelineGrid.prototype.minTime = null;
  2485. TimelineGrid.prototype.maxTime = null;
  2486. TimelineGrid.prototype.timeWindowMs = null;
  2487. TimelineGrid.prototype.slotDuration = null;
  2488. TimelineGrid.prototype.snapDuration = null;
  2489. TimelineGrid.prototype.duration = null;
  2490. TimelineGrid.prototype.labelInterval = null;
  2491. TimelineGrid.prototype.headerFormats = null;
  2492. TimelineGrid.prototype.isTimeScale = null;
  2493. TimelineGrid.prototype.largeUnit = null;
  2494. TimelineGrid.prototype.emphasizeWeeks = false;
  2495. TimelineGrid.prototype.titleFollower = null;
  2496. TimelineGrid.prototype.segContainerEl = null;
  2497. TimelineGrid.prototype.segContainerHeight = null;
  2498. TimelineGrid.prototype.bgSegContainerEl = null;
  2499. TimelineGrid.prototype.helperEls = null;
  2500. TimelineGrid.prototype.innerEl = null;
  2501. function TimelineGrid() {
  2502. var input;
  2503. TimelineGrid.__super__.constructor.apply(this, arguments);
  2504. this.initScaleProps();
  2505. this.minTime = moment.duration(this.opt('minTime') || '00:00');
  2506. this.maxTime = moment.duration(this.opt('maxTime') || '24:00');
  2507. this.timeWindowMs = this.maxTime - this.minTime;
  2508. this.snapDuration = (input = this.opt('snapDuration')) ? moment.duration(input) : this.slotDuration;
  2509. this.minResizeDuration = this.snapDuration;
  2510. this.snapsPerSlot = divideDurationByDuration(this.slotDuration, this.snapDuration);
  2511. this.slotWidth = this.opt('slotWidth');
  2512. }
  2513. TimelineGrid.prototype.opt = function (name) {
  2514. return this.view.opt(name);
  2515. };
  2516. TimelineGrid.prototype.isValidDate = function (date) {
  2517. var ms;
  2518. if (this.view.isHiddenDay(date)) {
  2519. return false;
  2520. } else if (this.isTimeScale) {
  2521. ms = date.time() - this.minTime;
  2522. ms = ((ms % 86400000) + 86400000) % 86400000;
  2523. return ms < this.timeWindowMs;
  2524. } else {
  2525. return true;
  2526. }
  2527. };
  2528. TimelineGrid.prototype.computeDisplayEventTime = function () {
  2529. return !this.isTimeScale;
  2530. };
  2531. TimelineGrid.prototype.computeDisplayEventEnd = function () {
  2532. return false;
  2533. };
  2534. TimelineGrid.prototype.computeEventTimeFormat = function () {
  2535. return this.opt('extraSmallTimeFormat');
  2536. };
  2537. /*
  2538. Makes the given date consistent with isTimeScale/largeUnit,
  2539. so, either removes the times, ensures a time, or makes it the startOf largeUnit.
  2540. Strips all timezones. Returns new copy.
  2541. TODO: should maybe be called "normalizeRangeDate".
  2542. */
  2543. TimelineGrid.prototype.normalizeGridDate = function (date) {
  2544. var normalDate;
  2545. if (this.isTimeScale) {
  2546. normalDate = date.clone();
  2547. if (!normalDate.hasTime()) {
  2548. normalDate.time(0);
  2549. }
  2550. } else {
  2551. normalDate = date.clone().stripTime();
  2552. if (this.largeUnit) {
  2553. normalDate.startOf(this.largeUnit);
  2554. }
  2555. }
  2556. return normalDate;
  2557. };
  2558. TimelineGrid.prototype.normalizeGridRange = function (range) {
  2559. var adjustedEnd, normalRange;
  2560. if (this.isTimeScale) {
  2561. normalRange = {
  2562. start: this.normalizeGridDate(range.start),
  2563. end: this.normalizeGridDate(range.end)
  2564. };
  2565. } else {
  2566. normalRange = this.view.computeDayRange(range);
  2567. if (this.largeUnit) {
  2568. normalRange.start.startOf(this.largeUnit);
  2569. adjustedEnd = normalRange.end.clone().startOf(this.largeUnit);
  2570. if (!adjustedEnd.isSame(normalRange.end) || !adjustedEnd.isAfter(normalRange.start)) {
  2571. adjustedEnd.add(this.slotDuration);
  2572. }
  2573. normalRange.end = adjustedEnd;
  2574. }
  2575. }
  2576. return normalRange;
  2577. };
  2578. TimelineGrid.prototype.rangeUpdated = function () {
  2579. var date, slotDates;
  2580. this.start = this.normalizeGridDate(this.start);
  2581. this.end = this.normalizeGridDate(this.end);
  2582. if (this.isTimeScale) {
  2583. this.start.add(this.minTime);
  2584. this.end.subtract(1, 'day').add(this.maxTime);
  2585. }
  2586. slotDates = [];
  2587. date = this.start.clone();
  2588. while (date < this.end) {
  2589. if (this.isValidDate(date)) {
  2590. slotDates.push(date.clone());
  2591. }
  2592. date.add(this.slotDuration);
  2593. }
  2594. this.slotDates = slotDates;
  2595. return this.updateGridDates();
  2596. };
  2597. TimelineGrid.prototype.updateGridDates = function () {
  2598. var date, snapDiff, snapDiffToIndex, snapIndex, snapIndexToDiff;
  2599. snapIndex = -1;
  2600. snapDiff = 0;
  2601. snapDiffToIndex = [];
  2602. snapIndexToDiff = [];
  2603. date = this.start.clone();
  2604. while (date < this.end) {
  2605. if (this.isValidDate(date)) {
  2606. snapIndex++;
  2607. snapDiffToIndex.push(snapIndex);
  2608. snapIndexToDiff.push(snapDiff);
  2609. } else {
  2610. snapDiffToIndex.push(snapIndex + 0.5);
  2611. }
  2612. date.add(this.snapDuration);
  2613. snapDiff++;
  2614. }
  2615. this.snapDiffToIndex = snapDiffToIndex;
  2616. this.snapIndexToDiff = snapIndexToDiff;
  2617. this.snapCnt = snapIndex + 1;
  2618. return this.slotCnt = this.snapCnt / this.snapsPerSlot;
  2619. };
  2620. TimelineGrid.prototype.spanToSegs = function (span) {
  2621. var normalRange, seg;
  2622. normalRange = this.normalizeGridRange(span);
  2623. if (this.computeDateSnapCoverage(span.start) < this.computeDateSnapCoverage(span.end)) {
  2624. seg = intersectRanges(normalRange, this);
  2625. if (seg) {
  2626. if (seg.isStart && !this.isValidDate(seg.start)) {
  2627. seg.isStart = false;
  2628. }
  2629. if (seg.isEnd && seg.end && !this.isValidDate(seg.end.clone().subtract(1))) {
  2630. seg.isEnd = false;
  2631. }
  2632. return [seg];
  2633. }
  2634. }
  2635. return [];
  2636. };
  2637. TimelineGrid.prototype.prepareHits = function () {
  2638. return this.buildCoords();
  2639. };
  2640. TimelineGrid.prototype.queryHit = function (leftOffset, topOffset) {
  2641. var containerCoordCache, localSnapIndex, partial, slatCoordCache, slatIndex, slatLeft, slatRight, slatWidth, snapIndex, snapLeft, snapRight, snapsPerSlot;
  2642. snapsPerSlot = this.snapsPerSlot;
  2643. slatCoordCache = this.slatCoordCache;
  2644. containerCoordCache = this.containerCoordCache;
  2645. if (containerCoordCache.isTopInBounds(topOffset)) {
  2646. slatIndex = slatCoordCache.getHorizontalIndex(leftOffset);
  2647. if (slatIndex != null) {
  2648. slatWidth = slatCoordCache.getWidth(slatIndex);
  2649. if (this.isRTL) {
  2650. slatRight = slatCoordCache.getRightOffset(slatIndex);
  2651. partial = (slatRight - leftOffset) / slatWidth;
  2652. localSnapIndex = Math.floor(partial * snapsPerSlot);
  2653. snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
  2654. snapRight = slatRight - (localSnapIndex / snapsPerSlot) * slatWidth;
  2655. snapLeft = snapRight - ((localSnapIndex + 1) / snapsPerSlot) * slatWidth;
  2656. } else {
  2657. slatLeft = slatCoordCache.getLeftOffset(slatIndex);
  2658. partial = (leftOffset - slatLeft) / slatWidth;
  2659. localSnapIndex = Math.floor(partial * snapsPerSlot);
  2660. snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
  2661. snapLeft = slatLeft + (localSnapIndex / snapsPerSlot) * slatWidth;
  2662. snapRight = slatLeft + ((localSnapIndex + 1) / snapsPerSlot) * slatWidth;
  2663. }
  2664. return {
  2665. snap: snapIndex,
  2666. component: this,
  2667. left: snapLeft,
  2668. right: snapRight,
  2669. top: containerCoordCache.getTopOffset(0),
  2670. bottom: containerCoordCache.getBottomOffset(0)
  2671. };
  2672. }
  2673. }
  2674. };
  2675. TimelineGrid.prototype.getHitSpan = function (hit) {
  2676. return this.getSnapRange(hit.snap);
  2677. };
  2678. TimelineGrid.prototype.getHitEl = function (hit) {
  2679. return this.getSnapEl(hit.snap);
  2680. };
  2681. TimelineGrid.prototype.getSnapRange = function (snapIndex) {
  2682. var end, start;
  2683. start = this.start.clone();
  2684. start.add(multiplyDuration(this.snapDuration, this.snapIndexToDiff[snapIndex]));
  2685. end = start.clone().add(this.snapDuration);
  2686. return {
  2687. start: start,
  2688. end: end
  2689. };
  2690. };
  2691. TimelineGrid.prototype.getSnapEl = function (snapIndex) {
  2692. return this.slatEls.eq(Math.floor(snapIndex / this.snapsPerSlot));
  2693. };
  2694. TimelineGrid.prototype.renderSkeleton = function () {
  2695. this.headScroller = new ClippedScroller({
  2696. overflowX: 'clipped-scroll',
  2697. overflowY: 'hidden'
  2698. });
  2699. this.headScroller.canvas = new ScrollerCanvas();
  2700. this.headScroller.render();
  2701. this.headEl.append(this.headScroller.el);
  2702. this.bodyScroller = new ClippedScroller();
  2703. this.bodyScroller.canvas = new ScrollerCanvas();
  2704. this.bodyScroller.render();
  2705. this.el.append(this.bodyScroller.el);
  2706. this.innerEl = this.bodyScroller.canvas.contentEl;
  2707. this.slatContainerEl = $('<div class="fc-slats"/>').appendTo(this.bodyScroller.canvas.bgEl);
  2708. this.segContainerEl = $('<div class="fc-event-container"/>').appendTo(this.bodyScroller.canvas.contentEl);
  2709. this.bgSegContainerEl = this.bodyScroller.canvas.bgEl;
  2710. this.containerCoordCache = new CoordCache({
  2711. els: this.bodyScroller.canvas.el,
  2712. isHorizontal: true,
  2713. isVertical: true
  2714. });
  2715. this.joiner = new ScrollJoiner('horizontal', [this.headScroller, this.bodyScroller]);
  2716. if (true) {
  2717. this.follower = new ScrollFollower(this.headScroller, true);
  2718. }
  2719. if (true) {
  2720. this.eventTitleFollower = new ScrollFollower(this.bodyScroller);
  2721. this.eventTitleFollower.minTravel = 50;
  2722. if (this.isRTL) {
  2723. this.eventTitleFollower.containOnNaturalRight = true;
  2724. } else {
  2725. this.eventTitleFollower.containOnNaturalLeft = true;
  2726. }
  2727. }
  2728. return TimelineGrid.__super__.renderSkeleton.apply(this, arguments);
  2729. };
  2730. TimelineGrid.prototype.headColEls = null;
  2731. TimelineGrid.prototype.slatColEls = null;
  2732. TimelineGrid.prototype.renderDates = function () {
  2733. var date, i, j, len, ref;
  2734. this.headScroller.canvas.contentEl.html(this.renderHeadHtml());
  2735. this.headColEls = this.headScroller.canvas.contentEl.find('col');
  2736. this.slatContainerEl.html(this.renderSlatHtml());
  2737. this.slatColEls = this.slatContainerEl.find('col');
  2738. this.slatEls = this.slatContainerEl.find('td');
  2739. this.slatCoordCache = new CoordCache({
  2740. els: this.slatEls,
  2741. isHorizontal: true
  2742. });
  2743. this.slatInnerCoordCache = new CoordCache({
  2744. els: this.slatEls.find('> div'),
  2745. isHorizontal: true,
  2746. offsetParent: this.bodyScroller.canvas.el
  2747. });
  2748. ref = this.slotDates;
  2749. for (i = j = 0, len = ref.length; j < len; i = ++j) {
  2750. date = ref[i];
  2751. this.view.publiclyTrigger('dayRender', null, date, this.slatEls.eq(i));
  2752. }
  2753. if (this.follower) {
  2754. return this.follower.setSprites(this.headEl.find('tr:not(:last-child) .fc-cell-text'));
  2755. }
  2756. };
  2757. TimelineGrid.prototype.unrenderDates = function () {
  2758. if (this.follower) {
  2759. this.follower.clearSprites();
  2760. }
  2761. this.headScroller.canvas.contentEl.empty();
  2762. this.slatContainerEl.empty();
  2763. this.headScroller.canvas.clearWidth();
  2764. return this.bodyScroller.canvas.clearWidth();
  2765. };
  2766. TimelineGrid.prototype.renderHeadHtml = function () {
  2767. var cell, cellRows, date, format, formats, headerCellClassNames, html, i, isChrono, isLast, isSingleDay, isSuperRow, isWeekStart, j, k, l, labelInterval, leadingCell, len, len1, len2, len3, len4, len5, len6, m, n, newCell, p, prevWeekNumber, q, row, rowCells, rowUnits, slatHtml, slotCells, slotDates, text, weekNumber;
  2768. labelInterval = this.labelInterval;
  2769. formats = this.headerFormats;
  2770. cellRows = (function () {
  2771. var j, len, results;
  2772. results = [];
  2773. for (j = 0, len = formats.length; j < len; j++) {
  2774. format = formats[j];
  2775. results.push([]);
  2776. }
  2777. return results;
  2778. })();
  2779. leadingCell = null;
  2780. prevWeekNumber = null;
  2781. slotDates = this.slotDates;
  2782. slotCells = [];
  2783. rowUnits = (function () {
  2784. var j, len, results;
  2785. results = [];
  2786. for (j = 0, len = formats.length; j < len; j++) {
  2787. format = formats[j];
  2788. results.push(FC.queryMostGranularFormatUnit(format));
  2789. }
  2790. return results;
  2791. })();
  2792. for (j = 0, len = slotDates.length; j < len; j++) {
  2793. date = slotDates[j];
  2794. weekNumber = date.week();
  2795. isWeekStart = this.emphasizeWeeks && prevWeekNumber !== null && prevWeekNumber !== weekNumber;
  2796. for (row = k = 0, len1 = formats.length; k < len1; row = ++k) {
  2797. format = formats[row];
  2798. rowCells = cellRows[row];
  2799. leadingCell = rowCells[rowCells.length - 1];
  2800. isSuperRow = formats.length > 1 && row < formats.length - 1;
  2801. newCell = null;
  2802. if (isSuperRow) {
  2803. text = date.format(format);
  2804. if (!leadingCell || leadingCell.text !== text) {
  2805. newCell = this.buildCellObject(date, text, rowUnits[row]);
  2806. } else {
  2807. leadingCell.colspan += 1;
  2808. }
  2809. } else {
  2810. if (!leadingCell || isInt(divideRangeByDuration(this.start, date, labelInterval))) {
  2811. text = date.format(format);
  2812. newCell = this.buildCellObject(date, text, rowUnits[row]);
  2813. } else {
  2814. leadingCell.colspan += 1;
  2815. }
  2816. }
  2817. if (newCell) {
  2818. newCell.weekStart = isWeekStart;
  2819. rowCells.push(newCell);
  2820. }
  2821. }
  2822. slotCells.push({
  2823. weekStart: isWeekStart
  2824. });
  2825. prevWeekNumber = weekNumber;
  2826. }
  2827. isChrono = labelInterval > this.slotDuration;
  2828. isSingleDay = this.slotDuration.as('days') === 1;
  2829. html = '<table>';
  2830. html += '<colgroup>';
  2831. for (l = 0, len2 = slotDates.length; l < len2; l++) {
  2832. date = slotDates[l];
  2833. html += '<col/>';
  2834. }
  2835. html += '</colgroup>';
  2836. html += '<tbody>';
  2837. for (i = m = 0, len3 = cellRows.length; m < len3; i = ++m) {
  2838. rowCells = cellRows[i];
  2839. isLast = i === cellRows.length - 1;
  2840. html += '<tr' + (isChrono && isLast ? ' class="fc-chrono"' : '') + '>';
  2841. for (n = 0, len4 = rowCells.length; n < len4; n++) {
  2842. cell = rowCells[n];
  2843. headerCellClassNames = [this.view.widgetHeaderClass];
  2844. if (cell.weekStart) {
  2845. headerCellClassNames.push('fc-em-cell');
  2846. }
  2847. if (isSingleDay) {
  2848. headerCellClassNames = headerCellClassNames.concat(this.getDayClasses(cell.date, true));
  2849. }
  2850. html += '<th class="' + headerCellClassNames.join(' ') + '"' + ' data-date="' + cell.date.format() + '"' + (cell.colspan > 1 ? ' colspan="' + cell.colspan + '"' : '') + '>' + '<div class="fc-cell-content">' + cell.spanHtml + '</div>' + '</th>';
  2851. }
  2852. html += '</tr>';
  2853. }
  2854. html += '</tbody></table>';
  2855. slatHtml = '<table>';
  2856. slatHtml += '<colgroup>';
  2857. for (p = 0, len5 = slotCells.length; p < len5; p++) {
  2858. cell = slotCells[p];
  2859. slatHtml += '<col/>';
  2860. }
  2861. slatHtml += '</colgroup>';
  2862. slatHtml += '<tbody><tr>';
  2863. for (i = q = 0, len6 = slotCells.length; q < len6; i = ++q) {
  2864. cell = slotCells[i];
  2865. date = slotDates[i];
  2866. slatHtml += this.slatCellHtml(date, cell.weekStart);
  2867. }
  2868. slatHtml += '</tr></tbody></table>';
  2869. this._slatHtml = slatHtml;
  2870. return html;
  2871. };
  2872. TimelineGrid.prototype.buildCellObject = function (date, text, rowUnit) {
  2873. var spanHtml;
  2874. date = date.clone();
  2875. spanHtml = this.view.buildGotoAnchorHtml({
  2876. date: date,
  2877. type: rowUnit,
  2878. forceOff: !rowUnit
  2879. }, {
  2880. 'class': 'fc-cell-text'
  2881. }, htmlEscape(text));
  2882. return {
  2883. text: text,
  2884. spanHtml: spanHtml,
  2885. date: date,
  2886. colspan: 1
  2887. };
  2888. };
  2889. TimelineGrid.prototype.renderSlatHtml = function () {
  2890. return this._slatHtml;
  2891. };
  2892. TimelineGrid.prototype.slatCellHtml = function (date, isEm) {
  2893. var classes;
  2894. if (this.isTimeScale) {
  2895. classes = [];
  2896. classes.push(isInt(divideRangeByDuration(this.start, date, this.labelInterval)) ? 'fc-major' : 'fc-minor');
  2897. } else {
  2898. classes = this.getDayClasses(date);
  2899. classes.push('fc-day');
  2900. }
  2901. classes.unshift(this.view.widgetContentClass);
  2902. if (isEm) {
  2903. classes.push('fc-em-cell');
  2904. }
  2905. return '<td class="' + classes.join(' ') + '"' + ' data-date="' + date.format() + '"' + '><div /></td>';
  2906. };
  2907. TimelineGrid.prototype.businessHourSegs = null;
  2908. TimelineGrid.prototype.renderBusinessHours = function () {
  2909. var segs;
  2910. if (!this.largeUnit) {
  2911. segs = this.businessHourSegs = this.buildBusinessHourSegs(!this.isTimeScale);
  2912. return this.renderFill('businessHours', segs, 'bgevent');
  2913. }
  2914. };
  2915. TimelineGrid.prototype.unrenderBusinessHours = function () {
  2916. return this.unrenderFill('businessHours');
  2917. };
  2918. TimelineGrid.prototype.nowIndicatorEls = null;
  2919. TimelineGrid.prototype.getNowIndicatorUnit = function () {
  2920. if (this.isTimeScale) {
  2921. return computeIntervalUnit(this.slotDuration);
  2922. }
  2923. };
  2924. TimelineGrid.prototype.renderNowIndicator = function (date) {
  2925. var coord, css, nodes;
  2926. nodes = [];
  2927. date = this.normalizeGridDate(date);
  2928. if (date >= this.start && date < this.end) {
  2929. coord = this.dateToCoord(date);
  2930. css = this.isRTL ? {
  2931. right: -coord
  2932. } : {
  2933. left: coord
  2934. };
  2935. nodes.push($("<div class='fc-now-indicator fc-now-indicator-arrow'></div>").css(css).appendTo(this.headScroller.canvas.el)[0]);
  2936. nodes.push($("<div class='fc-now-indicator fc-now-indicator-line'></div>").css(css).appendTo(this.bodyScroller.canvas.el)[0]);
  2937. }
  2938. return this.nowIndicatorEls = $(nodes);
  2939. };
  2940. TimelineGrid.prototype.unrenderNowIndicator = function () {
  2941. if (this.nowIndicatorEls) {
  2942. this.nowIndicatorEls.remove();
  2943. return this.nowIndicatorEls = null;
  2944. }
  2945. };
  2946. TimelineGrid.prototype.explicitSlotWidth = null;
  2947. TimelineGrid.prototype.defaultSlotWidth = null;
  2948. TimelineGrid.prototype.updateWidth = function () {
  2949. var availableWidth, containerMinWidth, containerWidth, isDatesRendered, nonLastSlotWidth, slotWidth;
  2950. isDatesRendered = this.headColEls;
  2951. if (isDatesRendered) {
  2952. slotWidth = Math.round(this.slotWidth || (this.slotWidth = this.computeSlotWidth()));
  2953. containerWidth = slotWidth * this.slotDates.length;
  2954. containerMinWidth = '';
  2955. nonLastSlotWidth = slotWidth;
  2956. availableWidth = this.bodyScroller.getClientWidth();
  2957. if (availableWidth > containerWidth) {
  2958. containerMinWidth = availableWidth;
  2959. containerWidth = '';
  2960. nonLastSlotWidth = Math.floor(availableWidth / this.slotDates.length);
  2961. }
  2962. } else {
  2963. containerWidth = '';
  2964. containerMinWidth = '';
  2965. }
  2966. this.headScroller.canvas.setWidth(containerWidth);
  2967. this.headScroller.canvas.setMinWidth(containerMinWidth);
  2968. this.bodyScroller.canvas.setWidth(containerWidth);
  2969. this.bodyScroller.canvas.setMinWidth(containerMinWidth);
  2970. if (isDatesRendered) {
  2971. this.headColEls.slice(0, -1).add(this.slatColEls.slice(0, -1)).width(nonLastSlotWidth);
  2972. }
  2973. this.headScroller.updateSize();
  2974. this.bodyScroller.updateSize();
  2975. this.joiner.update();
  2976. if (isDatesRendered) {
  2977. this.buildCoords();
  2978. this.updateSegPositions();
  2979. this.view.updateNowIndicator();
  2980. }
  2981. if (this.follower) {
  2982. this.follower.update();
  2983. }
  2984. if (this.eventTitleFollower) {
  2985. return this.eventTitleFollower.update();
  2986. }
  2987. };
  2988. TimelineGrid.prototype.computeSlotWidth = function () {
  2989. var headerWidth, innerEls, maxInnerWidth, minWidth, slotWidth, slotsPerLabel;
  2990. maxInnerWidth = 0;
  2991. innerEls = this.headEl.find('tr:last-child th .fc-cell-text');
  2992. innerEls.each(function (i, node) {
  2993. var innerWidth;
  2994. innerWidth = $(node).outerWidth();
  2995. return maxInnerWidth = Math.max(maxInnerWidth, innerWidth);
  2996. });
  2997. headerWidth = maxInnerWidth + 1;
  2998. slotsPerLabel = divideDurationByDuration(this.labelInterval, this.slotDuration);
  2999. slotWidth = Math.ceil(headerWidth / slotsPerLabel);
  3000. minWidth = this.headColEls.eq(0).css('min-width');
  3001. if (minWidth) {
  3002. minWidth = parseInt(minWidth, 10);
  3003. if (minWidth) {
  3004. slotWidth = Math.max(slotWidth, minWidth);
  3005. }
  3006. }
  3007. return slotWidth;
  3008. };
  3009. TimelineGrid.prototype.buildCoords = function () {
  3010. this.containerCoordCache.build();
  3011. this.slatCoordCache.build();
  3012. return this.slatInnerCoordCache.build();
  3013. };
  3014. TimelineGrid.prototype.computeDateSnapCoverage = function (date) {
  3015. var snapCoverage, snapDiff, snapDiffInt;
  3016. snapDiff = divideRangeByDuration(this.start, date, this.snapDuration);
  3017. if (snapDiff < 0) {
  3018. return 0;
  3019. } else if (snapDiff >= this.snapDiffToIndex.length) {
  3020. return this.snapCnt;
  3021. } else {
  3022. snapDiffInt = Math.floor(snapDiff);
  3023. snapCoverage = this.snapDiffToIndex[snapDiffInt];
  3024. if (isInt(snapCoverage)) {
  3025. snapCoverage += snapDiff - snapDiffInt;
  3026. } else {
  3027. snapCoverage = Math.ceil(snapCoverage);
  3028. }
  3029. return snapCoverage;
  3030. }
  3031. };
  3032. TimelineGrid.prototype.dateToCoord = function (date) {
  3033. var coordCache, partial, slotCoverage, slotIndex, snapCoverage;
  3034. snapCoverage = this.computeDateSnapCoverage(date);
  3035. slotCoverage = snapCoverage / this.snapsPerSlot;
  3036. slotIndex = Math.floor(slotCoverage);
  3037. slotIndex = Math.min(slotIndex, this.slotCnt - 1);
  3038. partial = slotCoverage - slotIndex;
  3039. coordCache = this.slatInnerCoordCache;
  3040. if (this.isRTL) {
  3041. return (coordCache.getRightPosition(slotIndex) - coordCache.getWidth(slotIndex) * partial) - this.containerCoordCache.getWidth(0);
  3042. } else {
  3043. return coordCache.getLeftPosition(slotIndex) + coordCache.getWidth(slotIndex) * partial;
  3044. }
  3045. };
  3046. TimelineGrid.prototype.rangeToCoords = function (range) {
  3047. if (this.isRTL) {
  3048. return {
  3049. right: this.dateToCoord(range.start),
  3050. left: this.dateToCoord(range.end)
  3051. };
  3052. } else {
  3053. return {
  3054. left: this.dateToCoord(range.start),
  3055. right: this.dateToCoord(range.end)
  3056. };
  3057. }
  3058. };
  3059. TimelineGrid.prototype.headHeight = function () {
  3060. var table;
  3061. table = this.headScroller.canvas.contentEl.find('table');
  3062. return table.height.apply(table, arguments);
  3063. };
  3064. TimelineGrid.prototype.updateSegPositions = function () {
  3065. var coords, j, len, seg, segs;
  3066. segs = (this.segs || []).concat(this.businessHourSegs || []);
  3067. for (j = 0, len = segs.length; j < len; j++) {
  3068. seg = segs[j];
  3069. coords = this.rangeToCoords(seg);
  3070. seg.el.css({
  3071. left: (seg.left = coords.left),
  3072. right: -(seg.right = coords.right)
  3073. });
  3074. }
  3075. };
  3076. TimelineGrid.prototype.renderFgSegs = function (segs) {
  3077. segs = this.renderFgSegEls(segs);
  3078. this.renderFgSegsInContainers([[this, segs]]);
  3079. this.updateSegFollowers(segs);
  3080. return segs;
  3081. };
  3082. TimelineGrid.prototype.unrenderFgSegs = function () {
  3083. this.clearSegFollowers();
  3084. return this.unrenderFgContainers([this]);
  3085. };
  3086. TimelineGrid.prototype.renderFgSegsInContainers = function (pairs) {
  3087. var container, coords, j, k, l, len, len1, len2, len3, len4, len5, len6, len7, m, n, p, q, r, ref, ref1, ref2, ref3, results, seg, segs;
  3088. for (j = 0, len = pairs.length; j < len; j++) {
  3089. ref = pairs[j], container = ref[0], segs = ref[1];
  3090. for (k = 0, len1 = segs.length; k < len1; k++) {
  3091. seg = segs[k];
  3092. coords = this.rangeToCoords(seg);
  3093. seg.el.css({
  3094. left: (seg.left = coords.left),
  3095. right: -(seg.right = coords.right)
  3096. });
  3097. }
  3098. }
  3099. for (l = 0, len2 = pairs.length; l < len2; l++) {
  3100. ref1 = pairs[l], container = ref1[0], segs = ref1[1];
  3101. for (m = 0, len3 = segs.length; m < len3; m++) {
  3102. seg = segs[m];
  3103. seg.el.appendTo(container.segContainerEl);
  3104. }
  3105. }
  3106. for (n = 0, len4 = pairs.length; n < len4; n++) {
  3107. ref2 = pairs[n], container = ref2[0], segs = ref2[1];
  3108. for (p = 0, len5 = segs.length; p < len5; p++) {
  3109. seg = segs[p];
  3110. seg.height = seg.el.outerHeight(true);
  3111. }
  3112. this.buildSegLevels(segs);
  3113. container.segContainerHeight = computeOffsetForSegs(segs);
  3114. }
  3115. results = [];
  3116. for (q = 0, len6 = pairs.length; q < len6; q++) {
  3117. ref3 = pairs[q], container = ref3[0], segs = ref3[1];
  3118. for (r = 0, len7 = segs.length; r < len7; r++) {
  3119. seg = segs[r];
  3120. seg.el.css('top', seg.top);
  3121. }
  3122. results.push(container.segContainerEl.height(container.segContainerHeight));
  3123. }
  3124. return results;
  3125. };
  3126. TimelineGrid.prototype.buildSegLevels = function (segs) {
  3127. var belowSeg, isLevelCollision, j, k, l, len, len1, len2, level, placedSeg, ref, ref1, segLevels, unplacedSeg;
  3128. segLevels = [];
  3129. this.sortEventSegs(segs);
  3130. for (j = 0, len = segs.length; j < len; j++) {
  3131. unplacedSeg = segs[j];
  3132. unplacedSeg.above = [];
  3133. level = 0;
  3134. while (level < segLevels.length) {
  3135. isLevelCollision = false;
  3136. ref = segLevels[level];
  3137. for (k = 0, len1 = ref.length; k < len1; k++) {
  3138. placedSeg = ref[k];
  3139. if (timeRowSegsCollide(unplacedSeg, placedSeg)) {
  3140. unplacedSeg.above.push(placedSeg);
  3141. isLevelCollision = true;
  3142. }
  3143. }
  3144. if (isLevelCollision) {
  3145. level += 1;
  3146. } else {
  3147. break;
  3148. }
  3149. }
  3150. (segLevels[level] || (segLevels[level] = [])).push(unplacedSeg);
  3151. level += 1;
  3152. while (level < segLevels.length) {
  3153. ref1 = segLevels[level];
  3154. for (l = 0, len2 = ref1.length; l < len2; l++) {
  3155. belowSeg = ref1[l];
  3156. if (timeRowSegsCollide(unplacedSeg, belowSeg)) {
  3157. belowSeg.above.push(unplacedSeg);
  3158. }
  3159. }
  3160. level += 1;
  3161. }
  3162. }
  3163. return segLevels;
  3164. };
  3165. TimelineGrid.prototype.unrenderFgContainers = function (containers) {
  3166. var container, j, len, results;
  3167. results = [];
  3168. for (j = 0, len = containers.length; j < len; j++) {
  3169. container = containers[j];
  3170. container.segContainerEl.empty();
  3171. container.segContainerEl.height('');
  3172. results.push(container.segContainerHeight = null);
  3173. }
  3174. return results;
  3175. };
  3176. TimelineGrid.prototype.fgSegHtml = function (seg, disableResizing) {
  3177. var classes, event, isDraggable, isResizableFromEnd, isResizableFromStart, timeText;
  3178. event = seg.event;
  3179. isDraggable = this.view.isEventDraggable(event);
  3180. isResizableFromStart = seg.isStart && this.view.isEventResizableFromStart(event);
  3181. isResizableFromEnd = seg.isEnd && this.view.isEventResizableFromEnd(event);
  3182. classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
  3183. classes.unshift('fc-timeline-event', 'fc-h-event');
  3184. timeText = this.getEventTimeText(event);
  3185. return '<a class="' + classes.join(' ') + '" style="' + cssToStr(this.getSegSkinCss(seg)) + '"' + (event.url ? ' href="' + htmlEscape(event.url) + '"' : '') + '>' + '<div class="fc-content">' + (timeText ? '<span class="fc-time">' + htmlEscape(timeText) + '</span>' : '') + '<span class="fc-title">' + (event.title ? htmlEscape(event.title) : '&nbsp;') + '</span>' + '</div>' + '<div class="fc-bg" />' + (isResizableFromStart ? '<div class="fc-resizer fc-start-resizer"></div>' : '') + (isResizableFromEnd ? '<div class="fc-resizer fc-end-resizer"></div>' : '') + '</a>';
  3186. };
  3187. TimelineGrid.prototype.updateSegFollowers = function (segs) {
  3188. var j, len, seg, sprites, titleEl;
  3189. if (this.eventTitleFollower) {
  3190. sprites = [];
  3191. for (j = 0, len = segs.length; j < len; j++) {
  3192. seg = segs[j];
  3193. titleEl = seg.el.find('.fc-title');
  3194. if (titleEl.length) {
  3195. sprites.push(new ScrollFollowerSprite(titleEl));
  3196. }
  3197. }
  3198. return this.eventTitleFollower.setSprites(sprites);
  3199. }
  3200. };
  3201. TimelineGrid.prototype.clearSegFollowers = function () {
  3202. if (this.eventTitleFollower) {
  3203. return this.eventTitleFollower.clearSprites();
  3204. }
  3205. };
  3206. TimelineGrid.prototype.segDragStart = function () {
  3207. TimelineGrid.__super__.segDragStart.apply(this, arguments);
  3208. if (this.eventTitleFollower) {
  3209. return this.eventTitleFollower.forceRelative();
  3210. }
  3211. };
  3212. TimelineGrid.prototype.segDragEnd = function () {
  3213. TimelineGrid.__super__.segDragEnd.apply(this, arguments);
  3214. if (this.eventTitleFollower) {
  3215. return this.eventTitleFollower.clearForce();
  3216. }
  3217. };
  3218. TimelineGrid.prototype.segResizeStart = function () {
  3219. TimelineGrid.__super__.segResizeStart.apply(this, arguments);
  3220. if (this.eventTitleFollower) {
  3221. return this.eventTitleFollower.forceRelative();
  3222. }
  3223. };
  3224. TimelineGrid.prototype.segResizeEnd = function () {
  3225. TimelineGrid.__super__.segResizeEnd.apply(this, arguments);
  3226. if (this.eventTitleFollower) {
  3227. return this.eventTitleFollower.clearForce();
  3228. }
  3229. };
  3230. TimelineGrid.prototype.renderHelper = function (event, sourceSeg) {
  3231. var segs;
  3232. segs = this.eventToSegs(event);
  3233. segs = this.renderFgSegEls(segs);
  3234. return this.renderHelperSegsInContainers([[this, segs]], sourceSeg);
  3235. };
  3236. TimelineGrid.prototype.renderHelperSegsInContainers = function (pairs, sourceSeg) {
  3237. var containerObj, coords, helperContainerEl, helperNodes, j, k, l, len, len1, len2, len3, m, ref, ref1, ref2, seg, segNodes, segs;
  3238. helperNodes = [];
  3239. segNodes = [];
  3240. for (j = 0, len = pairs.length; j < len; j++) {
  3241. ref = pairs[j], containerObj = ref[0], segs = ref[1];
  3242. for (k = 0, len1 = segs.length; k < len1; k++) {
  3243. seg = segs[k];
  3244. coords = this.rangeToCoords(seg);
  3245. seg.el.css({
  3246. left: (seg.left = coords.left),
  3247. right: -(seg.right = coords.right)
  3248. });
  3249. if (sourceSeg && sourceSeg.resourceId === ((ref1 = containerObj.resource) != null ? ref1.id : void 0)) {
  3250. seg.el.css('top', sourceSeg.el.css('top'));
  3251. } else {
  3252. seg.el.css('top', 0);
  3253. }
  3254. }
  3255. }
  3256. for (l = 0, len2 = pairs.length; l < len2; l++) {
  3257. ref2 = pairs[l], containerObj = ref2[0], segs = ref2[1];
  3258. helperContainerEl = $('<div class="fc-event-container fc-helper-container"/>').appendTo(containerObj.innerEl);
  3259. helperNodes.push(helperContainerEl[0]);
  3260. for (m = 0, len3 = segs.length; m < len3; m++) {
  3261. seg = segs[m];
  3262. helperContainerEl.append(seg.el);
  3263. segNodes.push(seg.el[0]);
  3264. }
  3265. }
  3266. if (this.helperEls) {
  3267. this.helperEls = this.helperEls.add($(helperNodes));
  3268. } else {
  3269. this.helperEls = $(helperNodes);
  3270. }
  3271. return $(segNodes);
  3272. };
  3273. TimelineGrid.prototype.unrenderHelper = function () {
  3274. if (this.helperEls) {
  3275. this.helperEls.remove();
  3276. return this.helperEls = null;
  3277. }
  3278. };
  3279. TimelineGrid.prototype.renderEventResize = function (resizeLocation, seg) {
  3280. this.renderHighlight(this.eventToSpan(resizeLocation));
  3281. return this.renderEventLocationHelper(resizeLocation, seg);
  3282. };
  3283. TimelineGrid.prototype.unrenderEventResize = function () {
  3284. this.unrenderHighlight();
  3285. return this.unrenderHelper();
  3286. };
  3287. TimelineGrid.prototype.renderFill = function (type, segs, className) {
  3288. segs = this.renderFillSegEls(type, segs);
  3289. this.renderFillInContainers(type, [[this, segs]], className);
  3290. return segs;
  3291. };
  3292. TimelineGrid.prototype.renderFillInContainers = function (type, pairs, className) {
  3293. var containerObj, j, len, ref, results, segs;
  3294. results = [];
  3295. for (j = 0, len = pairs.length; j < len; j++) {
  3296. ref = pairs[j], containerObj = ref[0], segs = ref[1];
  3297. results.push(this.renderFillInContainer(type, containerObj, segs, className));
  3298. }
  3299. return results;
  3300. };
  3301. TimelineGrid.prototype.renderFillInContainer = function (type, containerObj, segs, className) {
  3302. var containerEl, coords, j, len, seg;
  3303. if (segs.length) {
  3304. className || (className = type.toLowerCase());
  3305. containerEl = $('<div class="fc-' + className + '-container" />').appendTo(containerObj.bgSegContainerEl);
  3306. for (j = 0, len = segs.length; j < len; j++) {
  3307. seg = segs[j];
  3308. coords = this.rangeToCoords(seg);
  3309. seg.el.css({
  3310. left: (seg.left = coords.left),
  3311. right: -(seg.right = coords.right)
  3312. });
  3313. seg.el.appendTo(containerEl);
  3314. }
  3315. if (this.elsByFill[type]) {
  3316. return this.elsByFill[type] = this.elsByFill[type].add(containerEl);
  3317. } else {
  3318. return this.elsByFill[type] = containerEl;
  3319. }
  3320. }
  3321. };
  3322. TimelineGrid.prototype.renderDrag = function (dropLocation, seg) {
  3323. if (seg) {
  3324. return this.renderEventLocationHelper(dropLocation, seg);
  3325. } else {
  3326. this.renderHighlight(this.eventToSpan(dropLocation));
  3327. return null;
  3328. }
  3329. };
  3330. TimelineGrid.prototype.unrenderDrag = function () {
  3331. this.unrenderHelper();
  3332. return this.unrenderHighlight();
  3333. };
  3334. return TimelineGrid;
  3335. })(Grid);
  3336. computeOffsetForSegs = function (segs) {
  3337. var j, len, max, seg;
  3338. max = 0;
  3339. for (j = 0, len = segs.length; j < len; j++) {
  3340. seg = segs[j];
  3341. max = Math.max(max, computeOffsetForSeg(seg));
  3342. }
  3343. return max;
  3344. };
  3345. computeOffsetForSeg = function (seg) {
  3346. if (seg.top == null) {
  3347. seg.top = computeOffsetForSegs(seg.above);
  3348. }
  3349. return seg.top + seg.height;
  3350. };
  3351. timeRowSegsCollide = function (seg0, seg1) {
  3352. return seg0.left < seg1.right && seg0.right > seg1.left;
  3353. };
  3354. MIN_AUTO_LABELS = 18;
  3355. MAX_AUTO_SLOTS_PER_LABEL = 6;
  3356. MAX_AUTO_CELLS = 200;
  3357. MAX_CELLS = 1000;
  3358. DEFAULT_GRID_DURATION = {
  3359. months: 1
  3360. };
  3361. STOCK_SUB_DURATIONS = [
  3362. {
  3363. years: 1
  3364. }, {
  3365. months: 1
  3366. }, {
  3367. days: 1
  3368. }, {
  3369. hours: 1
  3370. }, {
  3371. minutes: 30
  3372. }, {
  3373. minutes: 15
  3374. }, {
  3375. minutes: 10
  3376. }, {
  3377. minutes: 5
  3378. }, {
  3379. minutes: 1
  3380. }, {
  3381. seconds: 30
  3382. }, {
  3383. seconds: 15
  3384. }, {
  3385. seconds: 10
  3386. }, {
  3387. seconds: 5
  3388. }, {
  3389. seconds: 1
  3390. }, {
  3391. milliseconds: 500
  3392. }, {
  3393. milliseconds: 100
  3394. }, {
  3395. milliseconds: 10
  3396. }, {
  3397. milliseconds: 1
  3398. }
  3399. ];
  3400. TimelineGrid.prototype.initScaleProps = function () {
  3401. var input, slotUnit, type;
  3402. this.labelInterval = this.queryDurationOption('slotLabelInterval');
  3403. this.slotDuration = this.queryDurationOption('slotDuration');
  3404. this.ensureGridDuration();
  3405. this.validateLabelAndSlot();
  3406. this.ensureLabelInterval();
  3407. this.ensureSlotDuration();
  3408. input = this.opt('slotLabelFormat');
  3409. type = $.type(input);
  3410. this.headerFormats = type === 'array' ? input : type === 'string' ? [input] : this.computeHeaderFormats();
  3411. this.isTimeScale = durationHasTime(this.slotDuration);
  3412. this.largeUnit = !this.isTimeScale ? (slotUnit = computeIntervalUnit(this.slotDuration), /year|month|week/.test(slotUnit) ? slotUnit : void 0) : void 0;
  3413. return this.emphasizeWeeks = this.slotDuration.as('days') === 1 && this.duration.as('weeks') >= 2 && !this.opt('businessHours');
  3414. /*
  3415. console.log('view duration =', @duration.humanize())
  3416. console.log('label interval =', @labelInterval.humanize())
  3417. console.log('slot duration =', @slotDuration.humanize())
  3418. console.log('header formats =', @headerFormats)
  3419. console.log('isTimeScale', @isTimeScale)
  3420. console.log('largeUnit', @largeUnit)
  3421. */
  3422. };
  3423. TimelineGrid.prototype.queryDurationOption = function (name) {
  3424. var dur, input;
  3425. input = this.opt(name);
  3426. if (input != null) {
  3427. dur = moment.duration(input);
  3428. if (+dur) {
  3429. return dur;
  3430. }
  3431. }
  3432. };
  3433. TimelineGrid.prototype.validateLabelAndSlot = function () {
  3434. var labelCnt, slotCnt, slotsPerLabel;
  3435. if (this.labelInterval) {
  3436. labelCnt = divideDurationByDuration(this.duration, this.labelInterval);
  3437. if (labelCnt > MAX_CELLS) {
  3438. FC.warn('slotLabelInterval results in too many cells');
  3439. this.labelInterval = null;
  3440. }
  3441. }
  3442. if (this.slotDuration) {
  3443. slotCnt = divideDurationByDuration(this.duration, this.slotDuration);
  3444. if (slotCnt > MAX_CELLS) {
  3445. FC.warn('slotDuration results in too many cells');
  3446. this.slotDuration = null;
  3447. }
  3448. }
  3449. if (this.labelInterval && this.slotDuration) {
  3450. slotsPerLabel = divideDurationByDuration(this.labelInterval, this.slotDuration);
  3451. if (!isInt(slotsPerLabel) || slotsPerLabel < 1) {
  3452. FC.warn('slotLabelInterval must be a multiple of slotDuration');
  3453. return this.slotDuration = null;
  3454. }
  3455. }
  3456. };
  3457. TimelineGrid.prototype.ensureGridDuration = function () {
  3458. var gridDuration, input, j, labelCnt, labelInterval;
  3459. gridDuration = this.duration;
  3460. if (!gridDuration) {
  3461. gridDuration = this.view.intervalDuration;
  3462. if (!gridDuration) {
  3463. if (!this.labelInterval && !this.slotDuration) {
  3464. gridDuration = moment.duration(DEFAULT_GRID_DURATION);
  3465. } else {
  3466. labelInterval = this.ensureLabelInterval();
  3467. for (j = STOCK_SUB_DURATIONS.length - 1; j >= 0; j += -1) {
  3468. input = STOCK_SUB_DURATIONS[j];
  3469. gridDuration = moment.duration(input);
  3470. labelCnt = divideDurationByDuration(gridDuration, labelInterval);
  3471. if (labelCnt >= MIN_AUTO_LABELS) {
  3472. break;
  3473. }
  3474. }
  3475. }
  3476. }
  3477. this.duration = gridDuration;
  3478. }
  3479. return gridDuration;
  3480. };
  3481. TimelineGrid.prototype.ensureLabelInterval = function () {
  3482. var input, j, k, labelCnt, labelInterval, len, len1, slotsPerLabel, tryLabelInterval;
  3483. labelInterval = this.labelInterval;
  3484. if (!labelInterval) {
  3485. if (!this.duration && !this.slotDuration) {
  3486. this.ensureGridDuration();
  3487. }
  3488. if (this.slotDuration) {
  3489. for (j = 0, len = STOCK_SUB_DURATIONS.length; j < len; j++) {
  3490. input = STOCK_SUB_DURATIONS[j];
  3491. tryLabelInterval = moment.duration(input);
  3492. slotsPerLabel = divideDurationByDuration(tryLabelInterval, this.slotDuration);
  3493. if (isInt(slotsPerLabel) && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
  3494. labelInterval = tryLabelInterval;
  3495. break;
  3496. }
  3497. }
  3498. if (!labelInterval) {
  3499. labelInterval = this.slotDuration;
  3500. }
  3501. } else {
  3502. for (k = 0, len1 = STOCK_SUB_DURATIONS.length; k < len1; k++) {
  3503. input = STOCK_SUB_DURATIONS[k];
  3504. labelInterval = moment.duration(input);
  3505. labelCnt = divideDurationByDuration(this.duration, labelInterval);
  3506. if (labelCnt >= MIN_AUTO_LABELS) {
  3507. break;
  3508. }
  3509. }
  3510. }
  3511. this.labelInterval = labelInterval;
  3512. }
  3513. return labelInterval;
  3514. };
  3515. TimelineGrid.prototype.ensureSlotDuration = function () {
  3516. var input, j, labelInterval, len, slotCnt, slotDuration, slotsPerLabel, trySlotDuration;
  3517. slotDuration = this.slotDuration;
  3518. if (!slotDuration) {
  3519. labelInterval = this.ensureLabelInterval();
  3520. for (j = 0, len = STOCK_SUB_DURATIONS.length; j < len; j++) {
  3521. input = STOCK_SUB_DURATIONS[j];
  3522. trySlotDuration = moment.duration(input);
  3523. slotsPerLabel = divideDurationByDuration(labelInterval, trySlotDuration);
  3524. if (isInt(slotsPerLabel) && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
  3525. slotDuration = trySlotDuration;
  3526. break;
  3527. }
  3528. }
  3529. if (slotDuration && this.duration) {
  3530. slotCnt = divideDurationByDuration(this.duration, slotDuration);
  3531. if (slotCnt > MAX_AUTO_CELLS) {
  3532. slotDuration = null;
  3533. }
  3534. }
  3535. if (!slotDuration) {
  3536. slotDuration = labelInterval;
  3537. }
  3538. this.slotDuration = slotDuration;
  3539. }
  3540. return slotDuration;
  3541. };
  3542. TimelineGrid.prototype.computeHeaderFormats = function () {
  3543. var format0, format1, format2, gridDuration, labelInterval, unit, view, weekNumbersVisible;
  3544. view = this.view;
  3545. gridDuration = this.duration;
  3546. labelInterval = this.labelInterval;
  3547. unit = computeIntervalUnit(labelInterval);
  3548. weekNumbersVisible = this.opt('weekNumbers');
  3549. format0 = format1 = format2 = null;
  3550. if (unit === 'week' && !weekNumbersVisible) {
  3551. unit = 'day';
  3552. }
  3553. switch (unit) {
  3554. case 'year':
  3555. format0 = 'YYYY';
  3556. break;
  3557. case 'month':
  3558. if (gridDuration.asYears() > 1) {
  3559. format0 = 'YYYY';
  3560. }
  3561. format1 = 'MMM';
  3562. break;
  3563. case 'week':
  3564. if (gridDuration.asYears() > 1) {
  3565. format0 = 'YYYY';
  3566. }
  3567. format1 = this.opt('shortWeekFormat');
  3568. break;
  3569. case 'day':
  3570. if (gridDuration.asYears() > 1) {
  3571. format0 = this.opt('monthYearFormat');
  3572. } else if (gridDuration.asMonths() > 1) {
  3573. format0 = 'MMMM';
  3574. }
  3575. if (weekNumbersVisible) {
  3576. format1 = this.opt('weekFormat');
  3577. }
  3578. format2 = 'dd D';
  3579. break;
  3580. case 'hour':
  3581. if (weekNumbersVisible) {
  3582. format0 = this.opt('weekFormat');
  3583. }
  3584. if (gridDuration.asDays() > 1) {
  3585. format1 = this.opt('dayOfMonthFormat');
  3586. }
  3587. format2 = this.opt('smallTimeFormat');
  3588. break;
  3589. case 'minute':
  3590. if (labelInterval.asMinutes() / 60 >= MAX_AUTO_SLOTS_PER_LABEL) {
  3591. format0 = this.opt('hourFormat');
  3592. format1 = '[:]mm';
  3593. } else {
  3594. format0 = this.opt('mediumTimeFormat');
  3595. }
  3596. break;
  3597. case 'second':
  3598. if (labelInterval.asSeconds() / 60 >= MAX_AUTO_SLOTS_PER_LABEL) {
  3599. format0 = 'LT';
  3600. format1 = '[:]ss';
  3601. } else {
  3602. format0 = 'LTS';
  3603. }
  3604. break;
  3605. case 'millisecond':
  3606. format0 = 'LTS';
  3607. format1 = '[.]SSS';
  3608. }
  3609. return [].concat(format0 || [], format1 || [], format2 || []);
  3610. };
  3611. FC.views.timeline = {
  3612. "class": TimelineView,
  3613. defaults: {
  3614. eventResizableFromStart: true
  3615. }
  3616. };
  3617. FC.views.timelineDay = {
  3618. type: 'timeline',
  3619. duration: {
  3620. days: 1
  3621. }
  3622. };
  3623. FC.views.timelineWeek = {
  3624. type: 'timeline',
  3625. duration: {
  3626. weeks: 1
  3627. }
  3628. };
  3629. FC.views.timelineMonth = {
  3630. type: 'timeline',
  3631. duration: {
  3632. months: 1
  3633. }
  3634. };
  3635. FC.views.timelineYear = {
  3636. type: 'timeline',
  3637. duration: {
  3638. years: 1
  3639. }
  3640. };
  3641. ResourceTimelineView = (function (superClass) {
  3642. extend(ResourceTimelineView, superClass);
  3643. function ResourceTimelineView() {
  3644. return ResourceTimelineView.__super__.constructor.apply(this, arguments);
  3645. }
  3646. ResourceTimelineView.mixin(ResourceViewMixin);
  3647. ResourceTimelineView.prototype.canRenderSpecificResources = true;
  3648. ResourceTimelineView.prototype.resourceGrid = null;
  3649. ResourceTimelineView.prototype.tbodyHash = null;
  3650. ResourceTimelineView.prototype.joiner = null;
  3651. ResourceTimelineView.prototype.dividerEls = null;
  3652. ResourceTimelineView.prototype.superHeaderText = null;
  3653. ResourceTimelineView.prototype.isVGrouping = null;
  3654. ResourceTimelineView.prototype.isHGrouping = null;
  3655. ResourceTimelineView.prototype.groupSpecs = null;
  3656. ResourceTimelineView.prototype.colSpecs = null;
  3657. ResourceTimelineView.prototype.orderSpecs = null;
  3658. ResourceTimelineView.prototype.rowHierarchy = null;
  3659. ResourceTimelineView.prototype.resourceRowHash = null;
  3660. ResourceTimelineView.prototype.nestingCnt = 0;
  3661. ResourceTimelineView.prototype.isNesting = null;
  3662. ResourceTimelineView.prototype.dividerWidth = null;
  3663. ResourceTimelineView.prototype.initialize = function () {
  3664. ResourceTimelineView.__super__.initialize.apply(this, arguments);
  3665. this.processResourceOptions();
  3666. this.resourceGrid = new Spreadsheet(this);
  3667. this.rowHierarchy = new RowParent(this);
  3668. return this.resourceRowHash = {};
  3669. };
  3670. ResourceTimelineView.prototype.instantiateGrid = function () {
  3671. return new ResourceTimelineGrid(this);
  3672. };
  3673. ResourceTimelineView.prototype.processResourceOptions = function () {
  3674. var allColSpecs, allOrderSpecs, colSpec, defaultLabelText, groupColSpecs, groupSpec, groupSpecs, hGroupField, isGroup, isHGrouping, isVGrouping, j, k, l, labelText, len, len1, len2, orderSpec, plainColSpecs, plainOrderSpecs, superHeaderText;
  3675. allColSpecs = this.opt('resourceColumns') || [];
  3676. labelText = this.opt('resourceLabelText');
  3677. defaultLabelText = 'Resources';
  3678. superHeaderText = null;
  3679. if (!allColSpecs.length) {
  3680. allColSpecs.push({
  3681. labelText: labelText || defaultLabelText,
  3682. text: this.getResourceTextFunc()
  3683. });
  3684. } else {
  3685. superHeaderText = labelText;
  3686. }
  3687. plainColSpecs = [];
  3688. groupColSpecs = [];
  3689. groupSpecs = [];
  3690. isVGrouping = false;
  3691. isHGrouping = false;
  3692. for (j = 0, len = allColSpecs.length; j < len; j++) {
  3693. colSpec = allColSpecs[j];
  3694. if (colSpec.group) {
  3695. groupColSpecs.push(colSpec);
  3696. } else {
  3697. plainColSpecs.push(colSpec);
  3698. }
  3699. }
  3700. plainColSpecs[0].isMain = true;
  3701. if (groupColSpecs.length) {
  3702. groupSpecs = groupColSpecs;
  3703. isVGrouping = true;
  3704. } else {
  3705. hGroupField = this.opt('resourceGroupField');
  3706. if (hGroupField) {
  3707. isHGrouping = true;
  3708. groupSpecs.push({
  3709. field: hGroupField,
  3710. text: this.opt('resourceGroupText'),
  3711. render: this.opt('resourceGroupRender')
  3712. });
  3713. }
  3714. }
  3715. allOrderSpecs = parseFieldSpecs(this.opt('resourceOrder'));
  3716. plainOrderSpecs = [];
  3717. for (k = 0, len1 = allOrderSpecs.length; k < len1; k++) {
  3718. orderSpec = allOrderSpecs[k];
  3719. isGroup = false;
  3720. for (l = 0, len2 = groupSpecs.length; l < len2; l++) {
  3721. groupSpec = groupSpecs[l];
  3722. if (groupSpec.field === orderSpec.field) {
  3723. groupSpec.order = orderSpec.order;
  3724. isGroup = true;
  3725. break;
  3726. }
  3727. }
  3728. if (!isGroup) {
  3729. plainOrderSpecs.push(orderSpec);
  3730. }
  3731. }
  3732. this.superHeaderText = superHeaderText;
  3733. this.isVGrouping = isVGrouping;
  3734. this.isHGrouping = isHGrouping;
  3735. this.groupSpecs = groupSpecs;
  3736. this.colSpecs = groupColSpecs.concat(plainColSpecs);
  3737. return this.orderSpecs = plainOrderSpecs;
  3738. };
  3739. ResourceTimelineView.prototype.renderSkeleton = function () {
  3740. ResourceTimelineView.__super__.renderSkeleton.apply(this, arguments);
  3741. this.renderResourceGridSkeleton();
  3742. this.tbodyHash = {
  3743. spreadsheet: this.resourceGrid.tbodyEl,
  3744. event: this.timeGrid.tbodyEl
  3745. };
  3746. this.joiner = new ScrollJoiner('vertical', [this.resourceGrid.bodyScroller, this.timeGrid.bodyScroller]);
  3747. return this.initDividerMoving();
  3748. };
  3749. ResourceTimelineView.prototype.renderSkeletonHtml = function () {
  3750. return '<table> <thead class="fc-head"> <tr> <td class="fc-resource-area ' + this.widgetHeaderClass + '"></td> <td class="fc-divider fc-col-resizer ' + this.widgetHeaderClass + '"></td> <td class="fc-time-area ' + this.widgetHeaderClass + '"></td> </tr> </thead> <tbody class="fc-body"> <tr> <td class="fc-resource-area ' + this.widgetContentClass + '"></td> <td class="fc-divider fc-col-resizer ' + this.widgetHeaderClass + '"></td> <td class="fc-time-area ' + this.widgetContentClass + '"></td> </tr> </tbody> </table>';
  3751. };
  3752. ResourceTimelineView.prototype.renderResourceGridSkeleton = function () {
  3753. this.resourceGrid.el = this.el.find('tbody .fc-resource-area');
  3754. this.resourceGrid.headEl = this.el.find('thead .fc-resource-area');
  3755. return this.resourceGrid.renderSkeleton();
  3756. };
  3757. ResourceTimelineView.prototype.initDividerMoving = function () {
  3758. var ref;
  3759. this.dividerEls = this.el.find('.fc-divider');
  3760. this.dividerWidth = (ref = this.opt('resourceAreaWidth')) != null ? ref : this.resourceGrid.tableWidth;
  3761. if (this.dividerWidth != null) {
  3762. this.positionDivider(this.dividerWidth);
  3763. }
  3764. return this.dividerEls.on('mousedown', (function (_this) {
  3765. return function (ev) {
  3766. return _this.dividerMousedown(ev);
  3767. };
  3768. })(this));
  3769. };
  3770. ResourceTimelineView.prototype.dividerMousedown = function (ev) {
  3771. var dragListener, isRTL, maxWidth, minWidth, origWidth;
  3772. isRTL = this.opt('isRTL');
  3773. minWidth = 30;
  3774. maxWidth = this.el.width() - 30;
  3775. origWidth = this.getNaturalDividerWidth();
  3776. dragListener = new DragListener({
  3777. dragStart: (function (_this) {
  3778. return function () {
  3779. return _this.dividerEls.addClass('fc-active');
  3780. };
  3781. })(this),
  3782. drag: (function (_this) {
  3783. return function (dx, dy) {
  3784. var width;
  3785. if (isRTL) {
  3786. width = origWidth - dx;
  3787. } else {
  3788. width = origWidth + dx;
  3789. }
  3790. width = Math.max(width, minWidth);
  3791. width = Math.min(width, maxWidth);
  3792. _this.dividerWidth = width;
  3793. _this.positionDivider(width);
  3794. return _this.updateWidth();
  3795. };
  3796. })(this),
  3797. dragEnd: (function (_this) {
  3798. return function () {
  3799. return _this.dividerEls.removeClass('fc-active');
  3800. };
  3801. })(this)
  3802. });
  3803. return dragListener.startInteraction(ev);
  3804. };
  3805. ResourceTimelineView.prototype.getNaturalDividerWidth = function () {
  3806. return this.el.find('.fc-resource-area').width();
  3807. };
  3808. ResourceTimelineView.prototype.positionDivider = function (w) {
  3809. return this.el.find('.fc-resource-area').width(w);
  3810. };
  3811. ResourceTimelineView.prototype.renderEvents = function (events) {
  3812. this.timeGrid.renderEvents(events);
  3813. this.syncRowHeights();
  3814. return this.updateWidth();
  3815. };
  3816. ResourceTimelineView.prototype.unrenderEvents = function () {
  3817. this.timeGrid.unrenderEvents();
  3818. this.syncRowHeights();
  3819. return this.updateWidth();
  3820. };
  3821. ResourceTimelineView.prototype.updateWidth = function () {
  3822. ResourceTimelineView.__super__.updateWidth.apply(this, arguments);
  3823. this.resourceGrid.updateWidth();
  3824. this.joiner.update();
  3825. if (this.cellFollower) {
  3826. return this.cellFollower.update();
  3827. }
  3828. };
  3829. ResourceTimelineView.prototype.updateHeight = function (isResize) {
  3830. ResourceTimelineView.__super__.updateHeight.apply(this, arguments);
  3831. if (isResize) {
  3832. return this.syncRowHeights();
  3833. }
  3834. };
  3835. ResourceTimelineView.prototype.setHeight = function (totalHeight, isAuto) {
  3836. var bodyHeight, headHeight;
  3837. headHeight = this.syncHeadHeights();
  3838. if (isAuto) {
  3839. bodyHeight = 'auto';
  3840. } else {
  3841. bodyHeight = totalHeight - headHeight - this.queryMiscHeight();
  3842. }
  3843. this.timeGrid.bodyScroller.setHeight(bodyHeight);
  3844. return this.resourceGrid.bodyScroller.setHeight(bodyHeight);
  3845. };
  3846. ResourceTimelineView.prototype.queryMiscHeight = function () {
  3847. return this.el.outerHeight() - Math.max(this.resourceGrid.headScroller.el.outerHeight(), this.timeGrid.headScroller.el.outerHeight()) - Math.max(this.resourceGrid.bodyScroller.el.outerHeight(), this.timeGrid.bodyScroller.el.outerHeight());
  3848. };
  3849. ResourceTimelineView.prototype.syncHeadHeights = function () {
  3850. var headHeight;
  3851. this.resourceGrid.headHeight('auto');
  3852. this.timeGrid.headHeight('auto');
  3853. headHeight = Math.max(this.resourceGrid.headHeight(), this.timeGrid.headHeight());
  3854. this.resourceGrid.headHeight(headHeight);
  3855. this.timeGrid.headHeight(headHeight);
  3856. return headHeight;
  3857. };
  3858. ResourceTimelineView.prototype.renderResources = function (resources) {
  3859. var j, len, resource;
  3860. this.batchRows();
  3861. for (j = 0, len = resources.length; j < len; j++) {
  3862. resource = resources[j];
  3863. this.insertResource(resource);
  3864. }
  3865. this.rowHierarchy.show();
  3866. this.unbatchRows();
  3867. return this.reinitializeCellFollowers();
  3868. };
  3869. ResourceTimelineView.prototype.unrenderResources = function () {
  3870. this.batchRows();
  3871. this.rowHierarchy.removeChildren();
  3872. this.unbatchRows();
  3873. return this.reinitializeCellFollowers();
  3874. };
  3875. /*
  3876. TODO: the scenario where there were previously unassociated events that are now
  3877. attached to this resource. should render those events immediately.
  3878. Responsible for rendering the new resource
  3879. */
  3880. ResourceTimelineView.prototype.renderResource = function (resource) {
  3881. this.insertResource(resource);
  3882. return this.reinitializeCellFollowers();
  3883. };
  3884. ResourceTimelineView.prototype.unrenderResource = function (resource) {
  3885. var row;
  3886. row = this.getResourceRow(resource.id);
  3887. if (row) {
  3888. this.batchRows();
  3889. row.remove();
  3890. this.unbatchRows();
  3891. return this.reinitializeCellFollowers();
  3892. }
  3893. };
  3894. ResourceTimelineView.prototype.cellFollower = null;
  3895. ResourceTimelineView.prototype.reinitializeCellFollowers = function () {
  3896. var cellContent, j, len, nodes, ref, row;
  3897. if (this.cellFollower) {
  3898. this.cellFollower.clearSprites();
  3899. }
  3900. this.cellFollower = new ScrollFollower(this.resourceGrid.bodyScroller, true);
  3901. this.cellFollower.isHFollowing = false;
  3902. this.cellFollower.isVFollowing = true;
  3903. nodes = [];
  3904. ref = this.rowHierarchy.getNodes();
  3905. for (j = 0, len = ref.length; j < len; j++) {
  3906. row = ref[j];
  3907. if (row instanceof VRowGroup) {
  3908. if (row.groupTd) {
  3909. cellContent = row.groupTd.find('.fc-cell-content');
  3910. if (cellContent.length) {
  3911. nodes.push(cellContent[0]);
  3912. }
  3913. }
  3914. }
  3915. }
  3916. return this.cellFollower.setSprites($(nodes));
  3917. };
  3918. ResourceTimelineView.prototype.insertResource = function (resource, parentResourceRow) {
  3919. var childResource, j, len, parentId, ref, results, row;
  3920. row = new ResourceRow(this, resource);
  3921. if (parentResourceRow == null) {
  3922. parentId = resource.parentId;
  3923. if (parentId) {
  3924. parentResourceRow = this.getResourceRow(parentId);
  3925. }
  3926. }
  3927. if (parentResourceRow) {
  3928. this.insertRowAsChild(row, parentResourceRow);
  3929. } else {
  3930. this.insertRow(row);
  3931. }
  3932. ref = resource.children;
  3933. results = [];
  3934. for (j = 0, len = ref.length; j < len; j++) {
  3935. childResource = ref[j];
  3936. results.push(this.insertResource(childResource, row));
  3937. }
  3938. return results;
  3939. };
  3940. ResourceTimelineView.prototype.insertRow = function (row, parent, groupSpecs) {
  3941. var group;
  3942. if (parent == null) {
  3943. parent = this.rowHierarchy;
  3944. }
  3945. if (groupSpecs == null) {
  3946. groupSpecs = this.groupSpecs;
  3947. }
  3948. if (groupSpecs.length) {
  3949. group = this.ensureResourceGroup(row, parent, groupSpecs[0]);
  3950. if (group instanceof HRowGroup) {
  3951. return this.insertRowAsChild(row, group);
  3952. } else {
  3953. return this.insertRow(row, group, groupSpecs.slice(1));
  3954. }
  3955. } else {
  3956. return this.insertRowAsChild(row, parent);
  3957. }
  3958. };
  3959. ResourceTimelineView.prototype.insertRowAsChild = function (row, parent) {
  3960. return parent.addChild(row, this.computeChildRowPosition(row, parent));
  3961. };
  3962. ResourceTimelineView.prototype.computeChildRowPosition = function (child, parent) {
  3963. var cmp, i, j, len, ref, sibling;
  3964. if (this.orderSpecs.length) {
  3965. ref = parent.children;
  3966. for (i = j = 0, len = ref.length; j < len; i = ++j) {
  3967. sibling = ref[i];
  3968. cmp = this.compareResources(sibling.resource || {}, child.resource || {});
  3969. if (cmp > 0) {
  3970. return i;
  3971. }
  3972. }
  3973. }
  3974. return null;
  3975. };
  3976. ResourceTimelineView.prototype.compareResources = function (a, b) {
  3977. return compareByFieldSpecs(a, b, this.orderSpecs);
  3978. };
  3979. ResourceTimelineView.prototype.ensureResourceGroup = function (row, parent, spec) {
  3980. var cmp, group, groupValue, i, j, k, len, len1, ref, ref1, testGroup;
  3981. groupValue = (row.resource || {})[spec.field];
  3982. group = null;
  3983. if (spec.order) {
  3984. ref = parent.children;
  3985. for (i = j = 0, len = ref.length; j < len; i = ++j) {
  3986. testGroup = ref[i];
  3987. cmp = flexibleCompare(testGroup.groupValue, groupValue) * spec.order;
  3988. if (cmp === 0) {
  3989. group = testGroup;
  3990. break;
  3991. } else if (cmp > 0) {
  3992. break;
  3993. }
  3994. }
  3995. } else {
  3996. ref1 = parent.children;
  3997. for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) {
  3998. testGroup = ref1[i];
  3999. if (testGroup.groupValue === groupValue) {
  4000. group = testGroup;
  4001. break;
  4002. }
  4003. }
  4004. }
  4005. if (!group) {
  4006. if (this.isVGrouping) {
  4007. group = new VRowGroup(this, spec, groupValue);
  4008. } else {
  4009. group = new HRowGroup(this, spec, groupValue);
  4010. }
  4011. parent.addChild(group, i);
  4012. }
  4013. return group;
  4014. };
  4015. ResourceTimelineView.prototype.pairSegsWithRows = function (segs) {
  4016. var j, len, pair, pairs, pairsById, resourceId, rowObj, seg;
  4017. pairs = [];
  4018. pairsById = {};
  4019. for (j = 0, len = segs.length; j < len; j++) {
  4020. seg = segs[j];
  4021. resourceId = seg.resourceId;
  4022. if (resourceId) {
  4023. rowObj = this.getResourceRow(resourceId);
  4024. if (rowObj) {
  4025. pair = pairsById[resourceId];
  4026. if (!pair) {
  4027. pair = [rowObj, []];
  4028. pairs.push(pair);
  4029. pairsById[resourceId] = pair;
  4030. }
  4031. pair[1].push(seg);
  4032. }
  4033. }
  4034. }
  4035. return pairs;
  4036. };
  4037. ResourceTimelineView.prototype.rowAdded = function (row) {
  4038. var isNesting, wasNesting;
  4039. if (row instanceof ResourceRow) {
  4040. this.resourceRowHash[row.resource.id] = row;
  4041. this.timeGrid.assignRowBusinessHourSegs(row);
  4042. }
  4043. wasNesting = this.isNesting;
  4044. isNesting = Boolean(this.nestingCnt += row.depth ? 1 : 0);
  4045. if (wasNesting !== isNesting) {
  4046. this.el.toggleClass('fc-nested', isNesting);
  4047. this.el.toggleClass('fc-flat', !isNesting);
  4048. }
  4049. return this.isNesting = isNesting;
  4050. };
  4051. ResourceTimelineView.prototype.rowRemoved = function (row) {
  4052. var isNesting, wasNesting;
  4053. if (row instanceof ResourceRow) {
  4054. delete this.resourceRowHash[row.resource.id];
  4055. this.timeGrid.destroyRowBusinessHourSegs(row);
  4056. }
  4057. wasNesting = this.isNesting;
  4058. isNesting = Boolean(this.nestingCnt -= row.depth ? 1 : 0);
  4059. if (wasNesting !== isNesting) {
  4060. this.el.toggleClass('fc-nested', isNesting);
  4061. this.el.toggleClass('fc-flat', !isNesting);
  4062. }
  4063. return this.isNesting = isNesting;
  4064. };
  4065. ResourceTimelineView.prototype.batchRowDepth = 0;
  4066. ResourceTimelineView.prototype.shownRowBatch = null;
  4067. ResourceTimelineView.prototype.hiddenRowBatch = null;
  4068. ResourceTimelineView.prototype.batchRows = function () {
  4069. if (!(this.batchRowDepth++)) {
  4070. this.shownRowBatch = [];
  4071. return this.hiddenRowBatch = [];
  4072. }
  4073. };
  4074. ResourceTimelineView.prototype.unbatchRows = function () {
  4075. if (!(--this.batchRowDepth)) {
  4076. if (this.hiddenRowBatch.length) {
  4077. this.rowsHidden(this.hiddenRowBatch);
  4078. }
  4079. if (this.shownRowBatch.length) {
  4080. this.rowsShown(this.shownRowBatch);
  4081. }
  4082. this.hiddenRowBatch = null;
  4083. return this.shownRowBatch = null;
  4084. }
  4085. };
  4086. ResourceTimelineView.prototype.rowShown = function (row) {
  4087. if (this.shownRowBatch) {
  4088. return this.shownRowBatch.push(row);
  4089. } else {
  4090. return this.rowsShown([row]);
  4091. }
  4092. };
  4093. ResourceTimelineView.prototype.rowHidden = function (row) {
  4094. if (this.hiddenRowBatch) {
  4095. return this.hiddenRowBatch.push(row);
  4096. } else {
  4097. return this.rowsHidden([row]);
  4098. }
  4099. };
  4100. ResourceTimelineView.prototype.rowsShown = function (rows) {
  4101. this.syncRowHeights(rows);
  4102. return this.updateWidth();
  4103. };
  4104. ResourceTimelineView.prototype.rowsHidden = function (rows) {
  4105. return this.updateWidth();
  4106. };
  4107. ResourceTimelineView.prototype.syncRowHeights = function (visibleRows, safe) {
  4108. var h, h1, h2, i, innerHeights, j, k, len, len1, row;
  4109. if (safe == null) {
  4110. safe = false;
  4111. }
  4112. if (visibleRows == null) {
  4113. visibleRows = this.getVisibleRows();
  4114. }
  4115. for (j = 0, len = visibleRows.length; j < len; j++) {
  4116. row = visibleRows[j];
  4117. row.setTrInnerHeight('');
  4118. }
  4119. innerHeights = (function () {
  4120. var k, len1, results;
  4121. results = [];
  4122. for (k = 0, len1 = visibleRows.length; k < len1; k++) {
  4123. row = visibleRows[k];
  4124. h = row.getMaxTrInnerHeight();
  4125. if (safe) {
  4126. h += h % 2;
  4127. }
  4128. results.push(h);
  4129. }
  4130. return results;
  4131. })();
  4132. for (i = k = 0, len1 = visibleRows.length; k < len1; i = ++k) {
  4133. row = visibleRows[i];
  4134. row.setTrInnerHeight(innerHeights[i]);
  4135. }
  4136. if (!safe) {
  4137. h1 = this.resourceGrid.tbodyEl.height();
  4138. h2 = this.timeGrid.tbodyEl.height();
  4139. if (Math.abs(h1 - h2) > 1) {
  4140. return this.syncRowHeights(visibleRows, true);
  4141. }
  4142. }
  4143. };
  4144. ResourceTimelineView.prototype.getVisibleRows = function () {
  4145. var j, len, ref, results, row;
  4146. ref = this.rowHierarchy.getRows();
  4147. results = [];
  4148. for (j = 0, len = ref.length; j < len; j++) {
  4149. row = ref[j];
  4150. if (row.isShown) {
  4151. results.push(row);
  4152. }
  4153. }
  4154. return results;
  4155. };
  4156. ResourceTimelineView.prototype.getEventRows = function () {
  4157. var j, len, ref, results, row;
  4158. ref = this.rowHierarchy.getRows();
  4159. results = [];
  4160. for (j = 0, len = ref.length; j < len; j++) {
  4161. row = ref[j];
  4162. if (row instanceof EventRow) {
  4163. results.push(row);
  4164. }
  4165. }
  4166. return results;
  4167. };
  4168. ResourceTimelineView.prototype.getResourceRow = function (resourceId) {
  4169. return this.resourceRowHash[resourceId];
  4170. };
  4171. ResourceTimelineView.prototype.queryScroll = function () {
  4172. var el, elBottom, j, len, ref, rowObj, scroll, scrollerTop;
  4173. scroll = ResourceTimelineView.__super__.queryScroll.apply(this, arguments);
  4174. scrollerTop = this.timeGrid.bodyScroller.scrollEl.offset().top;
  4175. ref = this.getVisibleRows();
  4176. for (j = 0, len = ref.length; j < len; j++) {
  4177. rowObj = ref[j];
  4178. if (rowObj.resource) {
  4179. el = rowObj.getTr('event');
  4180. elBottom = el.offset().top + el.outerHeight();
  4181. if (elBottom > scrollerTop) {
  4182. scroll.resourceId = rowObj.resource.id;
  4183. scroll.bottom = elBottom - scrollerTop;
  4184. break;
  4185. }
  4186. }
  4187. }
  4188. return scroll;
  4189. };
  4190. ResourceTimelineView.prototype.setScroll = function (scroll) {
  4191. var el, elBottom, innerTop, row;
  4192. if (scroll.resourceId) {
  4193. row = this.getResourceRow(scroll.resourceId);
  4194. if (row) {
  4195. el = row.getTr('event');
  4196. if (el) {
  4197. innerTop = this.timeGrid.bodyScroller.canvas.el.offset().top;
  4198. elBottom = el.offset().top + el.outerHeight();
  4199. scroll.top = elBottom - scroll.bottom - innerTop;
  4200. }
  4201. }
  4202. }
  4203. ResourceTimelineView.__super__.setScroll.call(this, scroll);
  4204. return this.resourceGrid.bodyScroller.setScrollTop(scroll.top);
  4205. };
  4206. ResourceTimelineView.prototype.scrollToResource = function (resource) {
  4207. var el, innerTop, row, scrollTop;
  4208. row = this.getResourceRow(resource.id);
  4209. if (row) {
  4210. el = row.getTr('event');
  4211. if (el) {
  4212. innerTop = this.timeGrid.bodyScroller.canvas.el.offset().top;
  4213. scrollTop = el.offset().top - innerTop;
  4214. this.timeGrid.bodyScroller.setScrollTop(scrollTop);
  4215. return this.resourceGrid.bodyScroller.setScrollTop(scrollTop);
  4216. }
  4217. }
  4218. };
  4219. return ResourceTimelineView;
  4220. })(TimelineView);
  4221. ResourceTimelineGrid = (function (superClass) {
  4222. extend(ResourceTimelineGrid, superClass);
  4223. function ResourceTimelineGrid() {
  4224. return ResourceTimelineGrid.__super__.constructor.apply(this, arguments);
  4225. }
  4226. ResourceTimelineGrid.mixin(ResourceGridMixin);
  4227. ResourceTimelineGrid.prototype.eventRows = null;
  4228. ResourceTimelineGrid.prototype.shownEventRows = null;
  4229. ResourceTimelineGrid.prototype.tbodyEl = null;
  4230. ResourceTimelineGrid.prototype.rowCoordCache = null;
  4231. ResourceTimelineGrid.prototype.spanToSegs = function (span) {
  4232. var calendar, j, len, resourceId, seg, segs;
  4233. segs = ResourceTimelineGrid.__super__.spanToSegs.apply(this, arguments);
  4234. calendar = this.view.calendar;
  4235. resourceId = span.resourceId;
  4236. if (resourceId) {
  4237. for (j = 0, len = segs.length; j < len; j++) {
  4238. seg = segs[j];
  4239. seg.resource = calendar.getResourceById(resourceId);
  4240. seg.resourceId = resourceId;
  4241. }
  4242. }
  4243. return segs;
  4244. };
  4245. ResourceTimelineGrid.prototype.prepareHits = function () {
  4246. var row, trArray;
  4247. ResourceTimelineGrid.__super__.prepareHits.apply(this, arguments);
  4248. this.eventRows = this.view.getEventRows();
  4249. this.shownEventRows = (function () {
  4250. var j, len, ref, results;
  4251. ref = this.eventRows;
  4252. results = [];
  4253. for (j = 0, len = ref.length; j < len; j++) {
  4254. row = ref[j];
  4255. if (row.isShown) {
  4256. results.push(row);
  4257. }
  4258. }
  4259. return results;
  4260. }).call(this);
  4261. trArray = (function () {
  4262. var j, len, ref, results;
  4263. ref = this.shownEventRows;
  4264. results = [];
  4265. for (j = 0, len = ref.length; j < len; j++) {
  4266. row = ref[j];
  4267. results.push(row.getTr('event')[0]);
  4268. }
  4269. return results;
  4270. }).call(this);
  4271. this.rowCoordCache = new CoordCache({
  4272. els: trArray,
  4273. isVertical: true
  4274. });
  4275. return this.rowCoordCache.build();
  4276. };
  4277. ResourceTimelineGrid.prototype.releaseHits = function () {
  4278. ResourceTimelineGrid.__super__.releaseHits.apply(this, arguments);
  4279. this.eventRows = null;
  4280. this.shownEventRows = null;
  4281. return this.rowCoordCache.clear();
  4282. };
  4283. ResourceTimelineGrid.prototype.queryHit = function (leftOffset, topOffset) {
  4284. var rowIndex, simpleHit;
  4285. simpleHit = ResourceTimelineGrid.__super__.queryHit.apply(this, arguments);
  4286. if (simpleHit) {
  4287. rowIndex = this.rowCoordCache.getVerticalIndex(topOffset);
  4288. if (rowIndex != null) {
  4289. return {
  4290. resourceId: this.shownEventRows[rowIndex].resource.id,
  4291. snap: simpleHit.snap,
  4292. component: this,
  4293. left: simpleHit.left,
  4294. right: simpleHit.right,
  4295. top: this.rowCoordCache.getTopOffset(rowIndex),
  4296. bottom: this.rowCoordCache.getBottomOffset(rowIndex)
  4297. };
  4298. }
  4299. }
  4300. };
  4301. ResourceTimelineGrid.prototype.getHitSpan = function (hit) {
  4302. var span;
  4303. span = this.getSnapRange(hit.snap);
  4304. span.resourceId = hit.resourceId;
  4305. return span;
  4306. };
  4307. ResourceTimelineGrid.prototype.getHitEl = function (hit) {
  4308. return this.getSnapEl(hit.snap);
  4309. };
  4310. ResourceTimelineGrid.prototype.renderSkeleton = function () {
  4311. var rowContainerEl;
  4312. ResourceTimelineGrid.__super__.renderSkeleton.apply(this, arguments);
  4313. this.segContainerEl.remove();
  4314. this.segContainerEl = null;
  4315. rowContainerEl = $('<div class="fc-rows"><table><tbody/></table></div>').appendTo(this.bodyScroller.canvas.contentEl);
  4316. return this.tbodyEl = rowContainerEl.find('tbody');
  4317. };
  4318. ResourceTimelineGrid.prototype.renderFgSegs = function (segs) {
  4319. var containerObj, containerSegs, j, len, pair, pairs, visiblePairs;
  4320. segs = this.renderFgSegEls(segs);
  4321. pairs = this.view.pairSegsWithRows(segs);
  4322. visiblePairs = [];
  4323. for (j = 0, len = pairs.length; j < len; j++) {
  4324. pair = pairs[j];
  4325. containerObj = pair[0], containerSegs = pair[1];
  4326. containerObj.fgSegs = containerSegs;
  4327. if (containerObj.isShown) {
  4328. containerObj.isSegsRendered = true;
  4329. visiblePairs.push(pair);
  4330. }
  4331. }
  4332. this.renderFgSegsInContainers(visiblePairs);
  4333. this.updateSegFollowers(segs);
  4334. return segs;
  4335. };
  4336. ResourceTimelineGrid.prototype.unrenderFgSegs = function () {
  4337. var eventRow, eventRows, j, len;
  4338. this.clearSegFollowers();
  4339. eventRows = this.view.getEventRows();
  4340. for (j = 0, len = eventRows.length; j < len; j++) {
  4341. eventRow = eventRows[j];
  4342. eventRow.fgSegs = null;
  4343. eventRow.isSegsRendered = false;
  4344. }
  4345. return this.unrenderFgContainers(eventRows);
  4346. };
  4347. ResourceTimelineGrid.prototype.rowCntWithCustomBusinessHours = 0;
  4348. ResourceTimelineGrid.prototype.renderBusinessHours = function () {
  4349. if (this.rowCntWithCustomBusinessHours) {
  4350. return this.ensureIndividualBusinessHours();
  4351. } else {
  4352. return ResourceTimelineGrid.__super__.renderBusinessHours.apply(this, arguments);
  4353. }
  4354. };
  4355. ResourceTimelineGrid.prototype.unrenderBusinessHours = function () {
  4356. if (this.rowCntWithCustomBusinessHours) {
  4357. return this.clearIndividualBusinessHours();
  4358. } else {
  4359. return ResourceTimelineGrid.__super__.unrenderBusinessHours.apply(this, arguments);
  4360. }
  4361. };
  4362. /*
  4363. Ensures that all rows have their individual business hours DISPLAYED.
  4364. */
  4365. ResourceTimelineGrid.prototype.ensureIndividualBusinessHours = function () {
  4366. var j, len, ref, results, row;
  4367. ref = this.view.getEventRows();
  4368. results = [];
  4369. for (j = 0, len = ref.length; j < len; j++) {
  4370. row = ref[j];
  4371. if (this.view.isDateSet && !row.businessHourSegs) {
  4372. this.populateRowBusinessHoursSegs(row);
  4373. }
  4374. if (row.isShown) {
  4375. results.push(row.ensureBusinessHourSegsRendered());
  4376. } else {
  4377. results.push(void 0);
  4378. }
  4379. }
  4380. return results;
  4381. };
  4382. /*
  4383. Ensures that all rows have their individual business hours CLEARED.
  4384. */
  4385. ResourceTimelineGrid.prototype.clearIndividualBusinessHours = function () {
  4386. var j, len, ref, results, row;
  4387. ref = this.view.getEventRows();
  4388. results = [];
  4389. for (j = 0, len = ref.length; j < len; j++) {
  4390. row = ref[j];
  4391. results.push(row.clearBusinessHourSegs());
  4392. }
  4393. return results;
  4394. };
  4395. /*
  4396. Called when a row has been added to the tree data structure, but before it's rendered.
  4397. Computes and assigns business hour data *if necessary*. To be rendered soon after.
  4398. */
  4399. ResourceTimelineGrid.prototype.assignRowBusinessHourSegs = function (row) {
  4400. if (row.resource.businessHours) {
  4401. if (!this.rowCntWithCustomBusinessHours) {
  4402. TimelineGrid.prototype.unrenderBusinessHours.call(this);
  4403. this.ensureIndividualBusinessHours();
  4404. }
  4405. this.rowCntWithCustomBusinessHours += 1;
  4406. }
  4407. if (this.view.isDateSet && this.rowCntWithCustomBusinessHours) {
  4408. return this.populateRowBusinessHoursSegs(row);
  4409. }
  4410. };
  4411. /*
  4412. Called when a row has been removed from the tree data structure.
  4413. Unrenders the row's segs and, if necessary, forces businessHours back to generic rendering.
  4414. */
  4415. ResourceTimelineGrid.prototype.destroyRowBusinessHourSegs = function (row) {
  4416. row.clearBusinessHourSegs();
  4417. if (row.resource.businessHours) {
  4418. this.rowCntWithCustomBusinessHours -= 1;
  4419. if (!this.rowCntWithCustomBusinessHours) {
  4420. this.clearIndividualBusinessHours();
  4421. return TimelineGrid.prototype.renderBusinessHours.call(this);
  4422. }
  4423. }
  4424. };
  4425. /*
  4426. Compute and assign to row.businessHourSegs unconditionally
  4427. */
  4428. ResourceTimelineGrid.prototype.populateRowBusinessHoursSegs = function (row) {
  4429. var businessHourSegs, businessHours, businessHoursEvents;
  4430. businessHours = row.resource.businessHours || this.view.opt('businessHours');
  4431. businessHoursEvents = this.view.calendar.computeBusinessHourEvents(!this.isTimeScale, businessHours);
  4432. businessHourSegs = this.eventsToSegs(businessHoursEvents);
  4433. businessHourSegs = this.renderFillSegEls('businessHours', businessHourSegs);
  4434. row.businessHourSegs = businessHourSegs;
  4435. };
  4436. ResourceTimelineGrid.prototype.renderFill = function (type, segs, className) {
  4437. var j, k, len, len1, nonResourceSegs, pair, pairs, resourceSegs, rowObj, rowSegs, seg, visiblePairs;
  4438. segs = this.renderFillSegEls(type, segs);
  4439. resourceSegs = [];
  4440. nonResourceSegs = [];
  4441. for (j = 0, len = segs.length; j < len; j++) {
  4442. seg = segs[j];
  4443. if (seg.resourceId) {
  4444. resourceSegs.push(seg);
  4445. } else {
  4446. nonResourceSegs.push(seg);
  4447. }
  4448. }
  4449. pairs = this.view.pairSegsWithRows(resourceSegs);
  4450. visiblePairs = [];
  4451. for (k = 0, len1 = pairs.length; k < len1; k++) {
  4452. pair = pairs[k];
  4453. rowObj = pair[0], rowSegs = pair[1];
  4454. if (type === 'bgEvent') {
  4455. rowObj.bgSegs = rowSegs;
  4456. }
  4457. if (rowObj.isShown) {
  4458. visiblePairs.push(pair);
  4459. }
  4460. }
  4461. if (nonResourceSegs.length) {
  4462. visiblePairs.unshift([this, nonResourceSegs]);
  4463. }
  4464. this.renderFillInContainers(type, visiblePairs, className);
  4465. return segs;
  4466. };
  4467. ResourceTimelineGrid.prototype.renderHelper = function (event, sourceSeg) {
  4468. var pairs, segs;
  4469. segs = this.eventToSegs(event);
  4470. segs = this.renderFgSegEls(segs);
  4471. pairs = this.view.pairSegsWithRows(segs);
  4472. return this.renderHelperSegsInContainers(pairs, sourceSeg);
  4473. };
  4474. return ResourceTimelineGrid;
  4475. })(TimelineGrid);
  4476. COL_MIN_WIDTH = 30;
  4477. Spreadsheet = (function () {
  4478. Spreadsheet.prototype.view = null;
  4479. Spreadsheet.prototype.headEl = null;
  4480. Spreadsheet.prototype.el = null;
  4481. Spreadsheet.prototype.tbodyEl = null;
  4482. Spreadsheet.prototype.headScroller = null;
  4483. Spreadsheet.prototype.bodyScroller = null;
  4484. Spreadsheet.prototype.joiner = null;
  4485. function Spreadsheet(view1) {
  4486. var colSpec;
  4487. this.view = view1;
  4488. this.isRTL = this.view.opt('isRTL');
  4489. this.givenColWidths = this.colWidths = (function () {
  4490. var j, len, ref, results;
  4491. ref = this.view.colSpecs;
  4492. results = [];
  4493. for (j = 0, len = ref.length; j < len; j++) {
  4494. colSpec = ref[j];
  4495. results.push(colSpec.width);
  4496. }
  4497. return results;
  4498. }).call(this);
  4499. }
  4500. Spreadsheet.prototype.colGroupHtml = '';
  4501. Spreadsheet.prototype.headTable = null;
  4502. Spreadsheet.prototype.headColEls = null;
  4503. Spreadsheet.prototype.headCellEls = null;
  4504. Spreadsheet.prototype.bodyColEls = null;
  4505. Spreadsheet.prototype.bodyTable = null;
  4506. Spreadsheet.prototype.renderSkeleton = function () {
  4507. this.headScroller = new ClippedScroller({
  4508. overflowX: 'clipped-scroll',
  4509. overflowY: 'hidden'
  4510. });
  4511. this.headScroller.canvas = new ScrollerCanvas();
  4512. this.headScroller.render();
  4513. this.headScroller.canvas.contentEl.html(this.renderHeadHtml());
  4514. this.headEl.append(this.headScroller.el);
  4515. this.bodyScroller = new ClippedScroller({
  4516. overflowY: 'clipped-scroll'
  4517. });
  4518. this.bodyScroller.canvas = new ScrollerCanvas();
  4519. this.bodyScroller.render();
  4520. this.bodyScroller.canvas.contentEl.html('<div class="fc-rows"><table>' + this.colGroupHtml + '<tbody/></table></div>');
  4521. this.tbodyEl = this.bodyScroller.canvas.contentEl.find('tbody');
  4522. this.el.append(this.bodyScroller.el);
  4523. this.joiner = new ScrollJoiner('horizontal', [this.headScroller, this.bodyScroller]);
  4524. this.headTable = this.headEl.find('table');
  4525. this.headColEls = this.headEl.find('col');
  4526. this.headCellEls = this.headScroller.canvas.contentEl.find('tr:last-child th');
  4527. this.bodyColEls = this.el.find('col');
  4528. this.bodyTable = this.el.find('table');
  4529. this.colMinWidths = this.computeColMinWidths();
  4530. this.applyColWidths();
  4531. return this.initColResizing();
  4532. };
  4533. Spreadsheet.prototype.renderHeadHtml = function () {
  4534. var colGroupHtml, colSpecs, html, i, isLast, isMainCol, j, k, len, len1, o;
  4535. colSpecs = this.view.colSpecs;
  4536. html = '<table>';
  4537. colGroupHtml = '<colgroup>';
  4538. for (j = 0, len = colSpecs.length; j < len; j++) {
  4539. o = colSpecs[j];
  4540. if (o.isMain) {
  4541. colGroupHtml += '<col class="fc-main-col"/>';
  4542. } else {
  4543. colGroupHtml += '<col/>';
  4544. }
  4545. }
  4546. colGroupHtml += '</colgroup>';
  4547. this.colGroupHtml = colGroupHtml;
  4548. html += colGroupHtml;
  4549. html += '<tbody>';
  4550. if (this.view.superHeaderText) {
  4551. html += '<tr class="fc-super">' + '<th class="' + this.view.widgetHeaderClass + '" colspan="' + colSpecs.length + '">' + '<div class="fc-cell-content">' + '<span class="fc-cell-text">' + htmlEscape(this.view.superHeaderText) + '</span>' + '</div>' + '</th>' + '</tr>';
  4552. }
  4553. html += '<tr>';
  4554. isMainCol = true;
  4555. for (i = k = 0, len1 = colSpecs.length; k < len1; i = ++k) {
  4556. o = colSpecs[i];
  4557. isLast = i === colSpecs.length - 1;
  4558. html += '<th class="' + this.view.widgetHeaderClass + '">' + '<div>' + '<div class="fc-cell-content">' + (o.isMain ? '<span class="fc-expander-space">' + '<span class="fc-icon"></span>' + '</span>' : '') + '<span class="fc-cell-text">' + htmlEscape(o.labelText || '') + '</span>' + '</div>' + (!isLast ? '<div class="fc-col-resizer"></div>' : '') + '</div>' + '</th>';
  4559. }
  4560. html += '</tr>';
  4561. html += '</tbody></table>';
  4562. return html;
  4563. };
  4564. Spreadsheet.prototype.givenColWidths = null;
  4565. Spreadsheet.prototype.colWidths = null;
  4566. Spreadsheet.prototype.colMinWidths = null;
  4567. Spreadsheet.prototype.tableWidth = null;
  4568. Spreadsheet.prototype.tableMinWidth = null;
  4569. Spreadsheet.prototype.initColResizing = function () {
  4570. return this.headEl.find('th .fc-col-resizer').each((function (_this) {
  4571. return function (i, resizerEl) {
  4572. resizerEl = $(resizerEl);
  4573. return resizerEl.on('mousedown', function (ev) {
  4574. return _this.colResizeMousedown(i, ev, resizerEl);
  4575. });
  4576. };
  4577. })(this));
  4578. };
  4579. Spreadsheet.prototype.colResizeMousedown = function (i, ev, resizerEl) {
  4580. var colWidths, dragListener, minWidth, origColWidth;
  4581. colWidths = this.colWidths = this.queryColWidths();
  4582. colWidths.pop();
  4583. colWidths.push(null);
  4584. origColWidth = colWidths[i];
  4585. minWidth = Math.min(this.colMinWidths[i], COL_MIN_WIDTH);
  4586. dragListener = new DragListener({
  4587. dragStart: (function (_this) {
  4588. return function () {
  4589. return resizerEl.addClass('fc-active');
  4590. };
  4591. })(this),
  4592. drag: (function (_this) {
  4593. return function (dx, dy) {
  4594. var width;
  4595. width = origColWidth + (_this.isRTL ? -dx : dx);
  4596. width = Math.max(width, minWidth);
  4597. colWidths[i] = width;
  4598. return _this.applyColWidths();
  4599. };
  4600. })(this),
  4601. dragEnd: (function (_this) {
  4602. return function () {
  4603. return resizerEl.removeClass('fc-active');
  4604. };
  4605. })(this)
  4606. });
  4607. return dragListener.startInteraction(ev);
  4608. };
  4609. Spreadsheet.prototype.applyColWidths = function () {
  4610. var allNumbers, anyPercentages, colMinWidths, colWidth, colWidths, cssWidth, cssWidths, defaultCssWidth, i, j, k, l, len, len1, len2, tableMinWidth, total;
  4611. colMinWidths = this.colMinWidths;
  4612. colWidths = this.colWidths;
  4613. allNumbers = true;
  4614. anyPercentages = false;
  4615. total = 0;
  4616. for (j = 0, len = colWidths.length; j < len; j++) {
  4617. colWidth = colWidths[j];
  4618. if (typeof colWidth === 'number') {
  4619. total += colWidth;
  4620. } else {
  4621. allNumbers = false;
  4622. if (colWidth) {
  4623. anyPercentages = true;
  4624. }
  4625. }
  4626. }
  4627. defaultCssWidth = anyPercentages && !this.view.isHGrouping ? 'auto' : '';
  4628. cssWidths = (function () {
  4629. var k, len1, results;
  4630. results = [];
  4631. for (i = k = 0, len1 = colWidths.length; k < len1; i = ++k) {
  4632. colWidth = colWidths[i];
  4633. results.push(colWidth != null ? colWidth : defaultCssWidth);
  4634. }
  4635. return results;
  4636. })();
  4637. tableMinWidth = 0;
  4638. for (i = k = 0, len1 = cssWidths.length; k < len1; i = ++k) {
  4639. cssWidth = cssWidths[i];
  4640. tableMinWidth += typeof cssWidth === 'number' ? cssWidth : colMinWidths[i];
  4641. }
  4642. for (i = l = 0, len2 = cssWidths.length; l < len2; i = ++l) {
  4643. cssWidth = cssWidths[i];
  4644. this.headColEls.eq(i).width(cssWidth);
  4645. this.bodyColEls.eq(i).width(cssWidth);
  4646. }
  4647. this.headScroller.canvas.setMinWidth(tableMinWidth);
  4648. this.bodyScroller.canvas.setMinWidth(tableMinWidth);
  4649. this.tableMinWidth = tableMinWidth;
  4650. return this.tableWidth = allNumbers ? total : void 0;
  4651. };
  4652. Spreadsheet.prototype.computeColMinWidths = function () {
  4653. var i, j, len, ref, results, width;
  4654. ref = this.givenColWidths;
  4655. results = [];
  4656. for (i = j = 0, len = ref.length; j < len; i = ++j) {
  4657. width = ref[i];
  4658. if (typeof width === 'number') {
  4659. results.push(width);
  4660. } else {
  4661. results.push(parseInt(this.headColEls.eq(i).css('min-width')) || COL_MIN_WIDTH);
  4662. }
  4663. }
  4664. return results;
  4665. };
  4666. Spreadsheet.prototype.queryColWidths = function () {
  4667. var j, len, node, ref, results;
  4668. ref = this.headCellEls;
  4669. results = [];
  4670. for (j = 0, len = ref.length; j < len; j++) {
  4671. node = ref[j];
  4672. results.push($(node).outerWidth());
  4673. }
  4674. return results;
  4675. };
  4676. Spreadsheet.prototype.updateWidth = function () {
  4677. this.headScroller.updateSize();
  4678. this.bodyScroller.updateSize();
  4679. this.joiner.update();
  4680. if (this.follower) {
  4681. return this.follower.update();
  4682. }
  4683. };
  4684. Spreadsheet.prototype.headHeight = function () {
  4685. var table;
  4686. table = this.headScroller.canvas.contentEl.find('table');
  4687. return table.height.apply(table, arguments);
  4688. };
  4689. return Spreadsheet;
  4690. })();
  4691. /*
  4692. An abstract node in a row-hierarchy tree.
  4693. May be a self-contained single row, a row with subrows,
  4694. OR a grouping of rows without its own distinct row.
  4695. */
  4696. RowParent = (function () {
  4697. RowParent.prototype.view = null;
  4698. RowParent.prototype.parent = null;
  4699. RowParent.prototype.prevSibling = null;
  4700. RowParent.prototype.children = null;
  4701. RowParent.prototype.depth = 0;
  4702. RowParent.prototype.hasOwnRow = false;
  4703. RowParent.prototype.trHash = null;
  4704. RowParent.prototype.trs = null;
  4705. RowParent.prototype.isRendered = false;
  4706. RowParent.prototype.isExpanded = true;
  4707. RowParent.prototype.isShown = false;
  4708. function RowParent(view1) {
  4709. this.view = view1;
  4710. this.children = [];
  4711. this.trHash = {};
  4712. this.trs = $();
  4713. }
  4714. /*
  4715. Adds the given node as a child.
  4716. Will be inserted at the `index`. If not given, will be appended to the end.
  4717. */
  4718. RowParent.prototype.addChild = function (child, index) {
  4719. var children, j, len, node, ref;
  4720. child.remove();
  4721. children = this.children;
  4722. if (index != null) {
  4723. children.splice(index, 0, child);
  4724. } else {
  4725. index = children.length;
  4726. children.push(child);
  4727. }
  4728. child.prevSibling = index > 0 ? children[index - 1] : null;
  4729. if (index < children.length - 1) {
  4730. children[index + 1].prevSibling = child;
  4731. }
  4732. child.parent = this;
  4733. child.depth = this.depth + (this.hasOwnRow ? 1 : 0);
  4734. ref = child.getNodes();
  4735. for (j = 0, len = ref.length; j < len; j++) {
  4736. node = ref[j];
  4737. node.added();
  4738. }
  4739. if (this.isShown && this.isExpanded) {
  4740. return child.show();
  4741. }
  4742. };
  4743. /*
  4744. Removes the given child from the node. Assumes it is a direct child.
  4745. If not a direct child, returns false and nothing happens.
  4746. Unrenders the child and triggers handlers.
  4747. */
  4748. RowParent.prototype.removeChild = function (child) {
  4749. var children, i, isFound, j, k, len, len1, ref, row, testChild;
  4750. children = this.children;
  4751. isFound = false;
  4752. for (i = j = 0, len = children.length; j < len; i = ++j) {
  4753. testChild = children[i];
  4754. if (testChild === child) {
  4755. isFound = true;
  4756. break;
  4757. }
  4758. }
  4759. if (!isFound) {
  4760. return false;
  4761. } else {
  4762. if (i < children.length - 1) {
  4763. children[i + 1].prevSibling = child.prevSibling;
  4764. }
  4765. children.splice(i, 1);
  4766. child.recursivelyUnrender();
  4767. ref = child.getNodes();
  4768. for (k = 0, len1 = ref.length; k < len1; k++) {
  4769. row = ref[k];
  4770. row.removed();
  4771. }
  4772. child.parent = null;
  4773. child.prevSibling = null;
  4774. return child;
  4775. }
  4776. };
  4777. /*
  4778. Removes all of the node's children from the hierarchy. Unrenders them and triggers callbacks.
  4779. NOTE: batchRows/unbatchRows should probably be called before this happens :(
  4780. */
  4781. RowParent.prototype.removeChildren = function () {
  4782. var child, j, k, len, len1, ref, ref1;
  4783. ref = this.children;
  4784. for (j = 0, len = ref.length; j < len; j++) {
  4785. child = ref[j];
  4786. child.recursivelyUnrender();
  4787. }
  4788. ref1 = this.getDescendants();
  4789. for (k = 0, len1 = ref1.length; k < len1; k++) {
  4790. child = ref1[k];
  4791. child.removed();
  4792. }
  4793. return this.children = [];
  4794. };
  4795. /*
  4796. Removes this node from its parent
  4797. */
  4798. RowParent.prototype.remove = function () {
  4799. if (this.parent) {
  4800. return this.parent.removeChild(this);
  4801. }
  4802. };
  4803. /*
  4804. Gets the last direct child node
  4805. */
  4806. RowParent.prototype.getLastChild = function () {
  4807. var children;
  4808. children = this.children;
  4809. return children[children.length - 1];
  4810. };
  4811. /*
  4812. Walks backward in the hierarchy to find the previous row leaf node.
  4813. When looking at the hierarchy in a flat linear fashion, this is the revealed row just before the current.
  4814. */
  4815. RowParent.prototype.getPrevRow = function () {
  4816. var lastChild, node;
  4817. node = this;
  4818. while (node) {
  4819. if (node.prevSibling) {
  4820. node = node.prevSibling;
  4821. while ((lastChild = node.getLastChild())) {
  4822. node = lastChild;
  4823. }
  4824. } else {
  4825. node = node.parent;
  4826. }
  4827. if (node && node.hasOwnRow && node.isShown) {
  4828. return node;
  4829. }
  4830. }
  4831. return null;
  4832. };
  4833. /*
  4834. Returns the first node in the subtree that has a revealed row
  4835. */
  4836. RowParent.prototype.getLeadingRow = function () {
  4837. if (this.hasOwnRow) {
  4838. return this;
  4839. } else if (this.isExpanded && this.children.length) {
  4840. return this.children[0].getLeadingRow();
  4841. }
  4842. };
  4843. /*
  4844. Generates a flat array containing all the row-nodes of the subtree. Descendants + self
  4845. */
  4846. RowParent.prototype.getRows = function (batchArray) {
  4847. var child, j, len, ref;
  4848. if (batchArray == null) {
  4849. batchArray = [];
  4850. }
  4851. if (this.hasOwnRow) {
  4852. batchArray.push(this);
  4853. }
  4854. ref = this.children;
  4855. for (j = 0, len = ref.length; j < len; j++) {
  4856. child = ref[j];
  4857. child.getRows(batchArray);
  4858. }
  4859. return batchArray;
  4860. };
  4861. /*
  4862. Generates a flat array containing all the nodes (row/non-row) of the subtree. Descendants + self
  4863. */
  4864. RowParent.prototype.getNodes = function (batchArray) {
  4865. var child, j, len, ref;
  4866. if (batchArray == null) {
  4867. batchArray = [];
  4868. }
  4869. batchArray.push(this);
  4870. ref = this.children;
  4871. for (j = 0, len = ref.length; j < len; j++) {
  4872. child = ref[j];
  4873. child.getNodes(batchArray);
  4874. }
  4875. return batchArray;
  4876. };
  4877. /*
  4878. Generates a flat array containing all the descendant nodes the current node
  4879. */
  4880. RowParent.prototype.getDescendants = function () {
  4881. var batchArray, child, j, len, ref;
  4882. batchArray = [];
  4883. ref = this.children;
  4884. for (j = 0, len = ref.length; j < len; j++) {
  4885. child = ref[j];
  4886. child.getNodes(batchArray);
  4887. }
  4888. return batchArray;
  4889. };
  4890. /*
  4891. Builds and populates the TRs for each row type. Inserts them into the DOM.
  4892. Does this only for this single row. Not recursive. If not a row (hasOwnRow=false), does not render anything.
  4893. PRECONDITION: assumes the parent has already been rendered.
  4894. */
  4895. RowParent.prototype.render = function () {
  4896. var prevRow, ref, renderMethodName, tbody, tr, trNodes, type;
  4897. this.trHash = {};
  4898. trNodes = [];
  4899. if (this.hasOwnRow) {
  4900. prevRow = this.getPrevRow();
  4901. ref = this.view.tbodyHash;
  4902. for (type in ref) {
  4903. tbody = ref[type];
  4904. tr = $('<tr/>');
  4905. this.trHash[type] = tr;
  4906. trNodes.push(tr[0]);
  4907. renderMethodName = 'render' + capitaliseFirstLetter(type) + 'Content';
  4908. if (this[renderMethodName]) {
  4909. this[renderMethodName](tr);
  4910. }
  4911. if (prevRow) {
  4912. prevRow.trHash[type].after(tr);
  4913. } else {
  4914. tbody.prepend(tr);
  4915. }
  4916. }
  4917. }
  4918. this.trs = $(trNodes).on('click', '.fc-expander', proxy(this, 'toggleExpanded'));
  4919. return this.isRendered = true;
  4920. };
  4921. /*
  4922. Unpopulates and removes all of this row's TRs from the DOM. Only for this single row. Not recursive.
  4923. Will trigger "hidden".
  4924. */
  4925. RowParent.prototype.unrender = function () {
  4926. var ref, tr, type, unrenderMethodName;
  4927. if (this.isRendered) {
  4928. ref = this.trHash;
  4929. for (type in ref) {
  4930. tr = ref[type];
  4931. unrenderMethodName = 'unrender' + capitaliseFirstLetter(type) + 'Content';
  4932. if (this[unrenderMethodName]) {
  4933. this[unrenderMethodName](tr);
  4934. }
  4935. }
  4936. this.trHash = {};
  4937. this.trs.remove();
  4938. this.trs = $();
  4939. this.isRendered = false;
  4940. this.isShown = false;
  4941. return this.hidden();
  4942. }
  4943. };
  4944. /*
  4945. Like unrender(), but does it for this row AND all descendants.
  4946. NOTE: batchRows/unbatchRows should probably be called before this happens :(
  4947. */
  4948. RowParent.prototype.recursivelyUnrender = function () {
  4949. var child, j, len, ref, results;
  4950. this.unrender();
  4951. ref = this.children;
  4952. results = [];
  4953. for (j = 0, len = ref.length; j < len; j++) {
  4954. child = ref[j];
  4955. results.push(child.recursivelyUnrender());
  4956. }
  4957. return results;
  4958. };
  4959. /*
  4960. A simple getter for retrieving a TR jQuery object of a certain row type
  4961. */
  4962. RowParent.prototype.getTr = function (type) {
  4963. return this.trHash[type];
  4964. };
  4965. /*
  4966. Renders this row if not already rendered, making sure it is visible.
  4967. Also renders descendants of this subtree, based on whether they are expanded or not.
  4968. NOTE: If called externally, batchRows/unbatchRows should probably be called before this happens :(
  4969. */
  4970. RowParent.prototype.show = function () {
  4971. var child, j, len, ref, results;
  4972. if (!this.isShown) {
  4973. if (!this.isRendered) {
  4974. this.render();
  4975. } else {
  4976. this.trs.css('display', '');
  4977. }
  4978. if (this.ensureSegsRendered) {
  4979. this.ensureSegsRendered();
  4980. }
  4981. if (this.isExpanded) {
  4982. this.indicateExpanded();
  4983. } else {
  4984. this.indicateCollapsed();
  4985. }
  4986. this.isShown = true;
  4987. this.shown();
  4988. if (this.isExpanded) {
  4989. ref = this.children;
  4990. results = [];
  4991. for (j = 0, len = ref.length; j < len; j++) {
  4992. child = ref[j];
  4993. results.push(child.show());
  4994. }
  4995. return results;
  4996. }
  4997. }
  4998. };
  4999. /*
  5000. Temporarily hides this node's TRs (if applicable) as well as all nodes in the subtree
  5001. */
  5002. RowParent.prototype.hide = function () {
  5003. var child, j, len, ref, results;
  5004. if (this.isShown) {
  5005. if (this.isRendered) {
  5006. this.trs.hide();
  5007. }
  5008. this.isShown = false;
  5009. this.hidden();
  5010. if (this.isExpanded) {
  5011. ref = this.children;
  5012. results = [];
  5013. for (j = 0, len = ref.length; j < len; j++) {
  5014. child = ref[j];
  5015. results.push(child.hide());
  5016. }
  5017. return results;
  5018. }
  5019. }
  5020. };
  5021. /*
  5022. Reveals this node's children if they have not already been revealed. Changes any expander icon.
  5023. */
  5024. RowParent.prototype.expand = function () {
  5025. var child, j, len, ref;
  5026. if (!this.isExpanded) {
  5027. this.isExpanded = true;
  5028. this.indicateExpanded();
  5029. this.view.batchRows();
  5030. ref = this.children;
  5031. for (j = 0, len = ref.length; j < len; j++) {
  5032. child = ref[j];
  5033. child.show();
  5034. }
  5035. this.view.unbatchRows();
  5036. return this.animateExpand();
  5037. }
  5038. };
  5039. /*
  5040. Hides this node's children if they are not already hidden. Changes any expander icon.
  5041. */
  5042. RowParent.prototype.collapse = function () {
  5043. var child, j, len, ref;
  5044. if (this.isExpanded) {
  5045. this.isExpanded = false;
  5046. this.indicateCollapsed();
  5047. this.view.batchRows();
  5048. ref = this.children;
  5049. for (j = 0, len = ref.length; j < len; j++) {
  5050. child = ref[j];
  5051. child.hide();
  5052. }
  5053. return this.view.unbatchRows();
  5054. }
  5055. };
  5056. /*
  5057. Switches between expanded/collapsed states
  5058. */
  5059. RowParent.prototype.toggleExpanded = function () {
  5060. if (this.isExpanded) {
  5061. return this.collapse();
  5062. } else {
  5063. return this.expand();
  5064. }
  5065. };
  5066. /*
  5067. Changes the expander icon to the "expanded" state
  5068. */
  5069. RowParent.prototype.indicateExpanded = function () {
  5070. return this.trs.find('.fc-expander .fc-icon').removeClass(this.getCollapsedIcon()).addClass(this.getExpandedIcon());
  5071. };
  5072. /*
  5073. Changes the expander icon to the "collapsed" state
  5074. */
  5075. RowParent.prototype.indicateCollapsed = function () {
  5076. return this.trs.find('.fc-expander .fc-icon').removeClass(this.getExpandedIcon()).addClass(this.getCollapsedIcon());
  5077. };
  5078. /*
  5079. */
  5080. RowParent.prototype.enableExpanding = function () {
  5081. return this.trs.find('.fc-expander-space').addClass('fc-expander');
  5082. };
  5083. /*
  5084. */
  5085. RowParent.prototype.disableExpanding = function () {
  5086. return this.trs.find('.fc-expander-space').removeClass('fc-expander').find('.fc-icon').removeClass(this.getExpandedIcon()).removeClass(this.getCollapsedIcon());
  5087. };
  5088. RowParent.prototype.getExpandedIcon = function () {
  5089. return 'fc-icon-down-triangle';
  5090. };
  5091. RowParent.prototype.getCollapsedIcon = function () {
  5092. var dir;
  5093. dir = this.view.isRTL ? 'left' : 'right';
  5094. return 'fc-icon-' + dir + '-triangle';
  5095. };
  5096. /*
  5097. Causes a slide-down CSS transition to demonstrate that the expand has happened
  5098. */
  5099. RowParent.prototype.animateExpand = function () {
  5100. var ref, ref1, trs;
  5101. trs = (ref = this.children[0]) != null ? (ref1 = ref.getLeadingRow()) != null ? ref1.trs : void 0 : void 0;
  5102. if (trs) {
  5103. trs.addClass('fc-collapsed');
  5104. setTimeout(function () {
  5105. trs.addClass('fc-transitioning');
  5106. return trs.removeClass('fc-collapsed');
  5107. });
  5108. return trs.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
  5109. return trs.removeClass('fc-transitioning');
  5110. });
  5111. }
  5112. };
  5113. /*
  5114. Find each TRs "inner div" (div within first cell). This div controls each TRs height.
  5115. Returns the max pixel height.
  5116. */
  5117. RowParent.prototype.getMaxTrInnerHeight = function () {
  5118. var max;
  5119. max = 0;
  5120. $.each(this.trHash, (function (_this) {
  5121. return function (type, tr) {
  5122. var innerEl;
  5123. innerEl = getOwnCells(tr).find('> div:not(.fc-cell-content):first');
  5124. return max = Math.max(innerEl.height(), max);
  5125. };
  5126. })(this));
  5127. return max;
  5128. };
  5129. /*
  5130. Find each TRs "inner div" and sets all of their heights to the same value.
  5131. */
  5132. RowParent.prototype.setTrInnerHeight = function (height) {
  5133. return $.each(this.trHash, (function (_this) {
  5134. return function (type, tr) {
  5135. return getOwnCells(tr).find('> div:not(.fc-cell-content):first').height(height);
  5136. };
  5137. })(this));
  5138. };
  5139. /*
  5140. Triggered when the current node has been shown (either freshly rendered or re-shown)
  5141. when it had previously been unrendered or hidden. `shown` does not bubble up the hierarchy.
  5142. */
  5143. RowParent.prototype.shown = function () {
  5144. if (this.hasOwnRow) {
  5145. return this.rowShown(this);
  5146. }
  5147. };
  5148. /*
  5149. Triggered when the current node has been hidden (either temporarily or permanently)
  5150. when it had previously been shown. `hidden` does not bubble up the hierarchy.
  5151. */
  5152. RowParent.prototype.hidden = function () {
  5153. if (this.hasOwnRow) {
  5154. return this.rowHidden(this);
  5155. }
  5156. };
  5157. /*
  5158. Just like `shown`, but only triggered for nodes that are actual rows. Bubbles up the hierarchy.
  5159. */
  5160. RowParent.prototype.rowShown = function (row) {
  5161. return (this.parent || this.view).rowShown(row);
  5162. };
  5163. /*
  5164. Just like `hidden`, but only triggered for nodes that are actual rows. Bubbles up the hierarchy.
  5165. */
  5166. RowParent.prototype.rowHidden = function (row) {
  5167. return (this.parent || this.view).rowHidden(row);
  5168. };
  5169. /*
  5170. Triggered when the current node has been added to the hierarchy. `added` does not bubble up.
  5171. */
  5172. RowParent.prototype.added = function () {
  5173. if (this.hasOwnRow) {
  5174. return this.rowAdded(this);
  5175. }
  5176. };
  5177. /*
  5178. Triggered when the current node has been removed from the hierarchy. `removed` does not bubble up.
  5179. */
  5180. RowParent.prototype.removed = function () {
  5181. if (this.hasOwnRow) {
  5182. return this.rowRemoved(this);
  5183. }
  5184. };
  5185. /*
  5186. Just like `added`, but only triggered for nodes that are actual rows. Bubbles up the hierarchy.
  5187. */
  5188. RowParent.prototype.rowAdded = function (row) {
  5189. return (this.parent || this.view).rowAdded(row);
  5190. };
  5191. /*
  5192. Just like `removed`, but only triggered for nodes that are actual rows. Bubbles up the hierarchy.
  5193. */
  5194. RowParent.prototype.rowRemoved = function (row) {
  5195. return (this.parent || this.view).rowRemoved(row);
  5196. };
  5197. return RowParent;
  5198. })();
  5199. /*
  5200. An abstract node in a row-hierarchy tree that contains other nodes.
  5201. Will have some sort of rendered label indicating the grouping,
  5202. up to the subclass for determining what to do with it.
  5203. */
  5204. RowGroup = (function (superClass) {
  5205. extend(RowGroup, superClass);
  5206. RowGroup.prototype.groupSpec = null;
  5207. RowGroup.prototype.groupValue = null;
  5208. function RowGroup(view, groupSpec1, groupValue1) {
  5209. this.groupSpec = groupSpec1;
  5210. this.groupValue = groupValue1;
  5211. RowGroup.__super__.constructor.apply(this, arguments);
  5212. }
  5213. /*
  5214. Called when this row (if it renders a row) or a subrow is removed
  5215. */
  5216. RowGroup.prototype.rowRemoved = function (row) {
  5217. RowGroup.__super__.rowRemoved.apply(this, arguments);
  5218. if (row !== this && !this.children.length) {
  5219. return this.remove();
  5220. }
  5221. };
  5222. /*
  5223. Renders the content wrapper element that will be inserted into this row's TD cell
  5224. */
  5225. RowGroup.prototype.renderGroupContentEl = function () {
  5226. var contentEl, filter;
  5227. contentEl = $('<div class="fc-cell-content" />').append(this.renderGroupTextEl());
  5228. filter = this.groupSpec.render;
  5229. if (typeof filter === 'function') {
  5230. contentEl = filter(contentEl, this.groupValue) || contentEl;
  5231. }
  5232. return contentEl;
  5233. };
  5234. /*
  5235. Renders the text span element that will be inserted into this row's TD cell.
  5236. Goes within the content element.
  5237. */
  5238. RowGroup.prototype.renderGroupTextEl = function () {
  5239. var filter, text;
  5240. text = this.groupValue || '';
  5241. filter = this.groupSpec.text;
  5242. if (typeof filter === 'function') {
  5243. text = filter(text) || text;
  5244. }
  5245. return $('<span class="fc-cell-text" />').text(text);
  5246. };
  5247. return RowGroup;
  5248. })(RowParent);
  5249. /*
  5250. A row grouping that renders as a single solid row that spans width-wise (like a horizontal rule)
  5251. */
  5252. HRowGroup = (function (superClass) {
  5253. extend(HRowGroup, superClass);
  5254. function HRowGroup() {
  5255. return HRowGroup.__super__.constructor.apply(this, arguments);
  5256. }
  5257. HRowGroup.prototype.hasOwnRow = true;
  5258. /*
  5259. Renders this row's TR for the "spreadsheet" quadrant, the area with info about each resource
  5260. */
  5261. HRowGroup.prototype.renderSpreadsheetContent = function (tr) {
  5262. var contentEl;
  5263. contentEl = this.renderGroupContentEl();
  5264. contentEl.prepend('<span class="fc-expander">' + '<span class="fc-icon"></span>' + '</span>');
  5265. return $('<td class="fc-divider" />').attr('colspan', this.view.colSpecs.length).append($('<div/>').append(contentEl)).appendTo(tr);
  5266. };
  5267. /*
  5268. Renders this row's TR for the quadrant that contains a resource's events
  5269. */
  5270. HRowGroup.prototype.renderEventContent = function (tr) {
  5271. return tr.append('<td class="fc-divider"> <div/> </td>');
  5272. };
  5273. return HRowGroup;
  5274. })(RowGroup);
  5275. /*
  5276. A row grouping that renders as a tall multi-cell vertical span in the "spreadsheet" area
  5277. */
  5278. VRowGroup = (function (superClass) {
  5279. extend(VRowGroup, superClass);
  5280. function VRowGroup() {
  5281. return VRowGroup.__super__.constructor.apply(this, arguments);
  5282. }
  5283. VRowGroup.prototype.rowspan = 0;
  5284. VRowGroup.prototype.leadingTr = null;
  5285. VRowGroup.prototype.groupTd = null;
  5286. /*
  5287. Called when a row somewhere within the grouping is shown
  5288. */
  5289. VRowGroup.prototype.rowShown = function (row) {
  5290. this.rowspan += 1;
  5291. this.renderRowspan();
  5292. return VRowGroup.__super__.rowShown.apply(this, arguments);
  5293. };
  5294. /*
  5295. Called when a row somewhere within the grouping is hidden
  5296. */
  5297. VRowGroup.prototype.rowHidden = function (row) {
  5298. this.rowspan -= 1;
  5299. this.renderRowspan();
  5300. return VRowGroup.__super__.rowHidden.apply(this, arguments);
  5301. };
  5302. /*
  5303. Makes sure the groupTd has the correct rowspan / place in the DOM.
  5304. PRECONDITION: in the case of multiple group nesting, a child's renderRowspan()
  5305. will be called before the parent's renderRowspan().
  5306. */
  5307. VRowGroup.prototype.renderRowspan = function () {
  5308. var leadingTr;
  5309. if (this.rowspan) {
  5310. if (!this.groupTd) {
  5311. this.groupTd = $('<td class="' + this.view.widgetContentClass + '"/>').append(this.renderGroupContentEl());
  5312. }
  5313. this.groupTd.attr('rowspan', this.rowspan);
  5314. leadingTr = this.getLeadingRow().getTr('spreadsheet');
  5315. if (leadingTr !== this.leadingTr) {
  5316. if (leadingTr) {
  5317. leadingTr.prepend(this.groupTd);
  5318. }
  5319. return this.leadingTr = leadingTr;
  5320. }
  5321. } else {
  5322. if (this.groupTd) {
  5323. this.groupTd.remove();
  5324. this.groupTd = null;
  5325. }
  5326. return this.leadingTr = null;
  5327. }
  5328. };
  5329. return VRowGroup;
  5330. })(RowGroup);
  5331. EventRow = (function (superClass) {
  5332. extend(EventRow, superClass);
  5333. function EventRow() {
  5334. return EventRow.__super__.constructor.apply(this, arguments);
  5335. }
  5336. EventRow.prototype.hasOwnRow = true;
  5337. EventRow.prototype.segContainerEl = null;
  5338. EventRow.prototype.segContainerHeight = null;
  5339. EventRow.prototype.innerEl = null;
  5340. EventRow.prototype.bgSegContainerEl = null;
  5341. EventRow.prototype.isSegsRendered = false;
  5342. EventRow.prototype.isBusinessHourSegsRendered = false;
  5343. EventRow.prototype.businessHourSegs = null;
  5344. EventRow.prototype.bgSegs = null;
  5345. EventRow.prototype.fgSegs = null;
  5346. EventRow.prototype.renderEventContent = function (tr) {
  5347. tr.html('<td class="' + this.view.widgetContentClass + '"> <div> <div class="fc-event-container" /> </div> </td>');
  5348. this.segContainerEl = tr.find('.fc-event-container');
  5349. this.innerEl = this.bgSegContainerEl = tr.find('td > div');
  5350. return this.ensureSegsRendered();
  5351. };
  5352. EventRow.prototype.ensureSegsRendered = function () {
  5353. if (!this.isSegsRendered) {
  5354. this.ensureBusinessHourSegsRendered();
  5355. if (this.bgSegs) {
  5356. this.view.timeGrid.renderFillInContainer('bgEvent', this, this.bgSegs);
  5357. }
  5358. if (this.fgSegs) {
  5359. this.view.timeGrid.renderFgSegsInContainers([[this, this.fgSegs]]);
  5360. }
  5361. return this.isSegsRendered = true;
  5362. }
  5363. };
  5364. EventRow.prototype.ensureBusinessHourSegsRendered = function () {
  5365. if (this.businessHourSegs && !this.isBusinessHourSegsRendered) {
  5366. this.view.timeGrid.renderFillInContainer('businessHours', this, this.businessHourSegs, 'bgevent');
  5367. return this.isBusinessHourSegsRendered = true;
  5368. }
  5369. };
  5370. EventRow.prototype.unrenderEventContent = function () {
  5371. this.clearBusinessHourSegs();
  5372. this.bgSegs = null;
  5373. this.fgSegs = null;
  5374. return this.isSegsRendered = false;
  5375. };
  5376. EventRow.prototype.clearBusinessHourSegs = function () {
  5377. var j, len, ref, seg;
  5378. if (this.businessHourSegs) {
  5379. ref = this.businessHourSegs;
  5380. for (j = 0, len = ref.length; j < len; j++) {
  5381. seg = ref[j];
  5382. if (seg.el) {
  5383. seg.el.remove();
  5384. }
  5385. }
  5386. this.businessHourSegs = null;
  5387. }
  5388. return this.isBusinessHourSegsRendered = false;
  5389. };
  5390. return EventRow;
  5391. })(RowParent);
  5392. /*
  5393. A row that renders information about a particular resource, as well as it events (handled by superclass)
  5394. */
  5395. ResourceRow = (function (superClass) {
  5396. extend(ResourceRow, superClass);
  5397. ResourceRow.prototype.resource = null;
  5398. function ResourceRow(view, resource1) {
  5399. this.resource = resource1;
  5400. ResourceRow.__super__.constructor.apply(this, arguments);
  5401. }
  5402. /*
  5403. Called when a row in the tree has been added
  5404. */
  5405. ResourceRow.prototype.rowAdded = function (row) {
  5406. ResourceRow.__super__.rowAdded.apply(this, arguments);
  5407. if (row !== this && this.isRendered) {
  5408. if (this.children.length === 1) {
  5409. this.enableExpanding();
  5410. if (this.isExpanded) {
  5411. return this.indicateExpanded();
  5412. } else {
  5413. return this.indicateCollapsed();
  5414. }
  5415. }
  5416. }
  5417. };
  5418. /*
  5419. Called when a row in the tree has been removed
  5420. */
  5421. ResourceRow.prototype.rowRemoved = function (row) {
  5422. ResourceRow.__super__.rowRemoved.apply(this, arguments);
  5423. if (row !== this && this.isRendered) {
  5424. if (!this.children.length) {
  5425. return this.disableExpanding();
  5426. }
  5427. }
  5428. };
  5429. ResourceRow.prototype.render = function () {
  5430. ResourceRow.__super__.render.apply(this, arguments);
  5431. if (this.children.length > 0) {
  5432. this.enableExpanding();
  5433. } else {
  5434. this.disableExpanding();
  5435. }
  5436. return this.view.publiclyTrigger('resourceRender', this.resource, this.resource, this.getTr('spreadsheet').find('> td'), this.getTr('event').find('> td'));
  5437. };
  5438. ResourceRow.prototype.renderEventContent = function (tr) {
  5439. ResourceRow.__super__.renderEventContent.apply(this, arguments);
  5440. return tr.attr('data-resource-id', this.resource.id);
  5441. };
  5442. /*
  5443. Populates the TR with cells containing data about the resource
  5444. */
  5445. ResourceRow.prototype.renderSpreadsheetContent = function (tr) {
  5446. var colSpec, contentEl, input, j, len, ref, resource, td, text;
  5447. resource = this.resource;
  5448. ref = this.view.colSpecs;
  5449. for (j = 0, len = ref.length; j < len; j++) {
  5450. colSpec = ref[j];
  5451. if (colSpec.group) {
  5452. continue;
  5453. }
  5454. input = colSpec.field ? resource[colSpec.field] || null : resource;
  5455. text = typeof colSpec.text === 'function' ? colSpec.text(resource, input) : input;
  5456. contentEl = $('<div class="fc-cell-content">' + (colSpec.isMain ? this.renderGutterHtml() : '') + '<span class="fc-cell-text">' + (text ? htmlEscape(text) : '&nbsp;') + '</span>' + '</div>');
  5457. if (typeof colSpec.render === 'function') {
  5458. contentEl = colSpec.render(resource, contentEl, input) || contentEl;
  5459. }
  5460. td = $('<td class="' + this.view.widgetContentClass + '"/>').append(contentEl);
  5461. if (colSpec.isMain) {
  5462. td.wrapInner('<div/>');
  5463. }
  5464. tr.append(td);
  5465. }
  5466. return tr.attr('data-resource-id', resource.id);
  5467. };
  5468. /*
  5469. Renders the HTML responsible for the subrow expander area,
  5470. as well as the space before it (used to align expanders of similar depths)
  5471. */
  5472. ResourceRow.prototype.renderGutterHtml = function () {
  5473. var html, i, j, ref;
  5474. html = '';
  5475. for (i = j = 0, ref = this.depth; j < ref; i = j += 1) {
  5476. html += '<span class="fc-icon"/>';
  5477. }
  5478. html += '<span class="fc-expander-space">' + '<span class="fc-icon"></span>' + '</span>';
  5479. return html;
  5480. };
  5481. return ResourceRow;
  5482. })(EventRow);
  5483. FC.views.timeline.resourceClass = ResourceTimelineView;
  5484. ResourceAgendaView = (function (superClass) {
  5485. extend(ResourceAgendaView, superClass);
  5486. function ResourceAgendaView() {
  5487. return ResourceAgendaView.__super__.constructor.apply(this, arguments);
  5488. }
  5489. ResourceAgendaView.mixin(VertResourceViewMixin);
  5490. ResourceAgendaView.prototype.timeGridClass = ResourceTimeGrid;
  5491. ResourceAgendaView.prototype.dayGridClass = ResourceDayGrid;
  5492. ResourceAgendaView.prototype.renderHead = function () {
  5493. ResourceAgendaView.__super__.renderHead.apply(this, arguments);
  5494. return this.timeGrid.processHeadResourceEls(this.headContainerEl);
  5495. };
  5496. ResourceAgendaView.prototype.setResourcesOnGrids = function (resources) {
  5497. this.timeGrid.setResources(resources);
  5498. if (this.dayGrid) {
  5499. return this.dayGrid.setResources(resources);
  5500. }
  5501. };
  5502. ResourceAgendaView.prototype.unsetResourcesOnGrids = function () {
  5503. this.timeGrid.unsetResources();
  5504. if (this.dayGrid) {
  5505. return this.dayGrid.unsetResources();
  5506. }
  5507. };
  5508. return ResourceAgendaView;
  5509. })(FC.AgendaView);
  5510. FC.views.agenda.queryResourceClass = function (viewSpec) {
  5511. var ref;
  5512. if ((ref = viewSpec.options.groupByResource || viewSpec.options.groupByDateAndResource) != null ? ref : viewSpec.duration.as('days') === 1) {
  5513. return ResourceAgendaView;
  5514. }
  5515. };
  5516. ResourceBasicView = (function (superClass) {
  5517. extend(ResourceBasicView, superClass);
  5518. function ResourceBasicView() {
  5519. return ResourceBasicView.__super__.constructor.apply(this, arguments);
  5520. }
  5521. ResourceBasicView.mixin(VertResourceViewMixin);
  5522. ResourceBasicView.prototype.dayGridClass = ResourceDayGrid;
  5523. ResourceBasicView.prototype.renderHead = function () {
  5524. ResourceBasicView.__super__.renderHead.apply(this, arguments);
  5525. return this.dayGrid.processHeadResourceEls(this.headContainerEl);
  5526. };
  5527. ResourceBasicView.prototype.setResourcesOnGrids = function (resources) {
  5528. return this.dayGrid.setResources(resources);
  5529. };
  5530. ResourceBasicView.prototype.unsetResourcesOnGrids = function () {
  5531. return this.dayGrid.unsetResources();
  5532. };
  5533. return ResourceBasicView;
  5534. })(FC.BasicView);
  5535. ResourceMonthView = (function (superClass) {
  5536. extend(ResourceMonthView, superClass);
  5537. function ResourceMonthView() {
  5538. return ResourceMonthView.__super__.constructor.apply(this, arguments);
  5539. }
  5540. ResourceMonthView.mixin(VertResourceViewMixin);
  5541. ResourceMonthView.prototype.dayGridClass = ResourceDayGrid;
  5542. ResourceMonthView.prototype.renderHead = function () {
  5543. ResourceMonthView.__super__.renderHead.apply(this, arguments);
  5544. return this.dayGrid.processHeadResourceEls(this.headContainerEl);
  5545. };
  5546. ResourceMonthView.prototype.setResourcesOnGrids = function (resources) {
  5547. return this.dayGrid.setResources(resources);
  5548. };
  5549. ResourceMonthView.prototype.unsetResourcesOnGrids = function () {
  5550. return this.dayGrid.unsetResources();
  5551. };
  5552. return ResourceMonthView;
  5553. })(FC.MonthView);
  5554. FC.views.basic.queryResourceClass = function (viewSpec) {
  5555. var ref;
  5556. if ((ref = viewSpec.options.groupByResource || viewSpec.options.groupByDateAndResource) != null ? ref : viewSpec.duration.as('days') === 1) {
  5557. return ResourceBasicView;
  5558. }
  5559. };
  5560. FC.views.month.queryResourceClass = function (viewSpec) {
  5561. if (viewSpec.options.groupByResource || viewSpec.options.groupByDateAndResource) {
  5562. return ResourceMonthView;
  5563. }
  5564. };
  5565. RELEASE_DATE = '2016-12-05';
  5566. UPGRADE_WINDOW = {
  5567. years: 1,
  5568. weeks: 1
  5569. };
  5570. LICENSE_INFO_URL = 'http://fullcalendar.io/scheduler/license/';
  5571. PRESET_LICENSE_KEYS = ['GPL-My-Project-Is-Open-Source', 'CC-Attribution-NonCommercial-NoDerivatives'];
  5572. processLicenseKey = function (key, containerEl) {
  5573. if (!isImmuneUrl(window.location.href) && !isValidKey(key)) {
  5574. if (!detectWarningInContainer(containerEl)) {
  5575. return renderingWarningInContainer('Please use a valid license key. <a href="' + LICENSE_INFO_URL + '">More Info</a>', containerEl);
  5576. }
  5577. }
  5578. };
  5579. /*
  5580. This decryption is not meant to be bulletproof. Just a way to remind about an upgrade.
  5581. */
  5582. isValidKey = function (key) {
  5583. var minPurchaseDate, parts, purchaseDate, releaseDate;
  5584. if ($.inArray(key, PRESET_LICENSE_KEYS) !== -1) {
  5585. return true;
  5586. }
  5587. parts = (key || '').match(/^(\d+)\-fcs\-(\d+)$/);
  5588. if (parts && parts[1].length === 10) {
  5589. purchaseDate = moment.utc(parseInt(parts[2]) * 1000);
  5590. releaseDate = moment.utc(FC.mockSchedulerReleaseDate || RELEASE_DATE);
  5591. if (releaseDate.isValid()) {
  5592. minPurchaseDate = releaseDate.clone().subtract(UPGRADE_WINDOW);
  5593. if (purchaseDate.isAfter(minPurchaseDate)) {
  5594. return true;
  5595. }
  5596. }
  5597. }
  5598. return false;
  5599. };
  5600. isImmuneUrl = function (url) {
  5601. return Boolean(url.match(/\w+\:\/\/fullcalendar\.io\/|\/demos\/[\w-]+\.html$/));
  5602. };
  5603. renderingWarningInContainer = function (messageHtml, containerEl) {
  5604. return containerEl.append($('<div class="fc-license-message" />').html(messageHtml));
  5605. };
  5606. detectWarningInContainer = function (containerEl) {
  5607. return containerEl.find('.fc-license-message').length >= 1;
  5608. };
  5609. });