unserver-unify
Version:
1,133 lines (1,114 loc) • 263 kB
JavaScript
/*!
* FullCalendar Scheduler v1.9.1
* Docs & License: https://fullcalendar.io/scheduler/
* (c) 2017 Adam Shaw
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("fullcalendar"), require("jquery"), require("moment"));
else if(typeof define === 'function' && define.amd)
define(["fullcalendar", "jquery", "moment"], factory);
else {
var a = typeof exports === 'object' ? factory(require("fullcalendar"), require("jquery"), require("moment")) : factory(root["FullCalendar"], root["jQuery"], root["moment"]);
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_15__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 36);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
/***/ }),
/* 1 */
/***/ (function(module, exports) {
/*
derived from:
https://github.com/Microsoft/tslib/blob/v1.6.0/tslib.js
only include the helpers we need, to keep down filesize
*/
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b)
if (b.hasOwnProperty(p))
d[p] = b[p]; };
exports.__extends = function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/***/ }),
/* 2 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_2__;
/***/ }),
/* 3 */,
/* 4 */,
/* 5 */,
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(1);
var fullcalendar_1 = __webpack_require__(0);
var ResourceComponentFootprint = /** @class */ (function (_super) {
tslib_1.__extends(ResourceComponentFootprint, _super);
function ResourceComponentFootprint(unzonedRange, isAllDay, resourceId) {
var _this = _super.call(this, unzonedRange, isAllDay) || this;
_this.resourceId = resourceId;
return _this;
}
ResourceComponentFootprint.prototype.toLegacy = function (calendar) {
var obj = _super.prototype.toLegacy.call(this, calendar);
obj.resourceId = this.resourceId;
return obj;
};
return ResourceComponentFootprint;
}(fullcalendar_1.ComponentFootprint));
exports.default = ResourceComponentFootprint;
/***/ }),
/* 7 */,
/* 8 */,
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(1);
var $ = __webpack_require__(2);
var fullcalendar_1 = __webpack_require__(0);
var ResourceViewMixin = /** @class */ (function (_super) {
tslib_1.__extends(ResourceViewMixin, _super);
function ResourceViewMixin() {
return _super !== null && _super.apply(this, arguments) || this;
}
ResourceViewMixin.mixInto = function (destClass) {
var _this = this;
fullcalendar_1.Mixin.mixInto.call(this, destClass);
[
'bindBaseRenderHandlers',
'queryScroll',
'applyScroll',
'triggerDayClick',
'triggerSelect',
'triggerExternalDrop',
'handleResourceAdd',
'handleResourceRemove'
].forEach(function (methodName) {
destClass.prototype[methodName] = _this.prototype[methodName];
});
};
ResourceViewMixin.prototype.initResourceView = function () {
var _this = this;
// new task
var resourceDeps = ['hasResources'];
if (!this.canHandleSpecificResources) {
resourceDeps.push('displayingDates');
}
this.watch('displayingResources', resourceDeps, function () {
_this.requestResourcesRender(_this.get('currentResources'));
}, function () {
_this.requestResourcesUnrender();
});
// start relying on displayingResources
this.watch('displayingBusinessHours', [
'businessHourGenerator',
'displayingResources',
'displayingDates'
], function (deps) {
_this.requestBusinessHoursRender(deps.businessHourGenerator);
}, function () {
_this.requestBusinessHoursUnrender();
});
// start relying on resource displaying rather than just current resources
this.watch('displayingEvents', ['displayingResources', 'hasEvents'], function () {
_this.requestEventsRender(_this.get('currentEvents'));
}, function () {
_this.requestEventsUnrender();
});
};
// Logic: base render trigger should fire when BOTH the resources and dates have rendered,
// but the unrender trigger should fire after ONLY the dates are about to be unrendered.
ResourceViewMixin.prototype.bindBaseRenderHandlers = function () {
var isResourcesRendered = false;
var isDatesRendered = false;
this.on('resourcesRendered', function () {
if (!isResourcesRendered) {
isResourcesRendered = true;
if (isDatesRendered) {
this.whenSizeUpdated(this.triggerViewRender);
}
}
});
this.on('datesRendered', function () {
if (!isDatesRendered) {
isDatesRendered = true;
if (isResourcesRendered) {
this.whenSizeUpdated(this.triggerViewRender);
}
}
});
this.on('before:resourcesUnrendered', function () {
if (isResourcesRendered) {
isResourcesRendered = false;
}
});
this.on('before:datesUnrendered', function () {
if (isDatesRendered) {
isDatesRendered = false;
this.triggerViewDestroy();
}
});
};
// Scroll
// ----------------------------------------------------------------------------------------------
ResourceViewMixin.prototype.queryScroll = function () {
var scroll = fullcalendar_1.View.prototype.queryScroll.apply(this, arguments);
if (this.isResourcesRendered) {
$.extend(scroll, this.queryResourceScroll());
}
return scroll;
};
ResourceViewMixin.prototype.applyScroll = function (scroll) {
fullcalendar_1.View.prototype.applyScroll.apply(this, arguments);
if (this.isResourcesRendered) {
this.applyResourceScroll(scroll);
}
};
ResourceViewMixin.prototype.queryResourceScroll = function () {
return {}; // subclasses must implement
};
ResourceViewMixin.prototype.applyResourceScroll = function () {
// subclasses must implement
};
// Rendering Utils
// ----------------------------------------------------------------------------------------------
ResourceViewMixin.prototype.getResourceText = function (resource) {
return this.getResourceTextFunc()(resource);
};
ResourceViewMixin.prototype.getResourceTextFunc = function () {
if (this.resourceTextFunc) {
return this.resourceTextFunc;
}
else {
var func = this.opt('resourceText');
if (typeof func !== 'function') {
func = function (resource) { return resource.title || resource.id; };
}
this.resourceTextFunc = func;
return func;
}
};
// Resource Change Handling
// ----------------------------------------------------------------------------------------------
ResourceViewMixin.prototype.handleResourceAdd = function (resource) {
this.requestResourceRender(resource);
};
ResourceViewMixin.prototype.handleResourceRemove = function (resource) {
this.requestResourceUnrender(resource);
};
// Resource Rendering
// ----------------------------------------------------------------------------------------------
ResourceViewMixin.prototype.requestResourcesRender = function (resources) {
var _this = this;
this.requestRender(function () {
_this.executeResourcesRender(resources);
}, 'resource', 'init');
};
ResourceViewMixin.prototype.requestResourcesUnrender = function () {
var _this = this;
this.requestRender(function () {
_this.executeResourcesUnrender();
}, 'resource', 'destroy');
};
ResourceViewMixin.prototype.requestResourceRender = function (resource) {
var _this = this;
this.requestRender(function () {
_this.executeResourceRender(resource);
}, 'resource', 'add');
};
ResourceViewMixin.prototype.requestResourceUnrender = function (resource) {
var _this = this;
this.requestRender(function () {
_this.executeResourceUnrender(resource);
}, 'resource', 'remove');
};
// Resource High-level Rendering/Unrendering
// ----------------------------------------------------------------------------------------------
ResourceViewMixin.prototype.executeResourcesRender = function (resources) {
this.renderResources(resources);
this.isResourcesRendered = true;
this.trigger('resourcesRendered');
};
ResourceViewMixin.prototype.executeResourcesUnrender = function () {
this.trigger('before:resourcesUnrendered');
this.unrenderResources();
this.isResourcesRendered = false;
};
ResourceViewMixin.prototype.executeResourceRender = function (resource) {
this.renderResource(resource);
};
ResourceViewMixin.prototype.executeResourceUnrender = function (resource) {
this.unrenderResource(resource);
};
// Triggering
// ----------------------------------------------------------------------------------------------
/*
footprint is a ResourceComponentFootprint
*/
ResourceViewMixin.prototype.triggerDayClick = function (footprint, dayEl, ev) {
var dateProfile = this.calendar.footprintToDateProfile(footprint);
this.publiclyTrigger('dayClick', {
context: dayEl,
args: [
dateProfile.start,
ev,
this,
footprint.resourceId ?
this.calendar.resourceManager.getResourceById(footprint.resourceId) :
null
]
});
};
/*
footprint is a ResourceComponentFootprint
*/
ResourceViewMixin.prototype.triggerSelect = function (footprint, ev) {
var dateProfile = this.calendar.footprintToDateProfile(footprint);
this.publiclyTrigger('select', {
context: this,
args: [
dateProfile.start,
dateProfile.end,
ev,
this,
footprint.resourceId ?
this.calendar.resourceManager.getResourceById(footprint.resourceId) :
null
]
});
};
// override the view's default trigger in order to provide a resourceId to the `drop` event
// TODO: make more DRY with core
ResourceViewMixin.prototype.triggerExternalDrop = function (singleEventDef, isEvent, el, ev, ui) {
// trigger 'drop' regardless of whether element represents an event
this.publiclyTrigger('drop', {
context: el[0],
args: [
singleEventDef.dateProfile.start.clone(),
ev,
ui,
singleEventDef.getResourceIds()[0],
this
]
});
if (isEvent) {
// signal an external event landed
this.publiclyTrigger('eventReceive', {
context: this,
args: [
singleEventDef.buildInstance().toLegacy(),
this
]
});
}
};
return ResourceViewMixin;
}(fullcalendar_1.Mixin));
exports.default = ResourceViewMixin;
ResourceViewMixin.prototype.isResourcesRendered = false;
/***/ }),
/* 10 */,
/* 11 */,
/* 12 */,
/* 13 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(1);
var $ = __webpack_require__(2);
var fullcalendar_1 = __webpack_require__(0);
var ResourceDayTableMixin_1 = __webpack_require__(21);
var ResourceComponentFootprint_1 = __webpack_require__(6);
var ResourceDayGrid = /** @class */ (function (_super) {
tslib_1.__extends(ResourceDayGrid, _super);
function ResourceDayGrid(view) {
var _this = _super.call(this, view) || this;
_this.isResourceFootprintsEnabled = true;
return _this;
}
ResourceDayGrid.prototype.renderDates = function (dateProfile) {
this.dateProfile = dateProfile;
};
ResourceDayGrid.prototype.renderResources = function (resources) {
this.registerResources(resources);
this.renderGrid();
if (this.headContainerEl) {
this.processHeadResourceEls(this.headContainerEl);
}
};
// TODO: make DRY with ResourceTimeGrid
ResourceDayGrid.prototype.getHitFootprint = function (hit) {
var plainFootprint = _super.prototype.getHitFootprint.call(this, hit);
return new ResourceComponentFootprint_1.default(plainFootprint.unzonedRange, plainFootprint.isAllDay, this.getColResource(hit.col).id);
};
ResourceDayGrid.prototype.componentFootprintToSegs = function (componentFootprint) {
var resourceCnt = this.resourceCnt;
var genericSegs = this.datesAboveResources ?
this.sliceRangeByDay(componentFootprint.unzonedRange) : // each day-per-resource will need its own column
this.sliceRangeByRow(componentFootprint.unzonedRange);
var resourceSegs = [];
for (var _i = 0, genericSegs_1 = genericSegs; _i < genericSegs_1.length; _i++) {
var seg = genericSegs_1[_i];
for (var resourceIndex = 0; resourceIndex < resourceCnt; resourceIndex++) {
var resourceObj = this.flattenedResources[resourceIndex];
if (!(componentFootprint instanceof ResourceComponentFootprint_1.default) ||
(componentFootprint.resourceId === resourceObj.id)) {
var copy = $.extend({}, seg);
copy.resource = resourceObj;
if (this.isRTL) {
copy.leftCol = this.indicesToCol(resourceIndex, seg.lastRowDayIndex);
copy.rightCol = this.indicesToCol(resourceIndex, seg.firstRowDayIndex);
}
else {
copy.leftCol = this.indicesToCol(resourceIndex, seg.firstRowDayIndex);
copy.rightCol = this.indicesToCol(resourceIndex, seg.lastRowDayIndex);
}
resourceSegs.push(copy);
}
}
}
return resourceSegs;
};
return ResourceDayGrid;
}(fullcalendar_1.DayGrid));
exports.default = ResourceDayGrid;
ResourceDayTableMixin_1.default.mixInto(ResourceDayGrid);
/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(1);
var $ = __webpack_require__(2);
var moment = __webpack_require__(15);
var fullcalendar_1 = __webpack_require__(0);
var ClippedScroller_1 = __webpack_require__(24);
var ScrollerCanvas_1 = __webpack_require__(25);
var ScrollJoiner_1 = __webpack_require__(16);
var ScrollFollower_1 = __webpack_require__(26);
var TimelineEventRenderer_1 = __webpack_require__(17);
var TimelineFillRenderer_1 = __webpack_require__(28);
var TimelineHelperRenderer_1 = __webpack_require__(29);
var TimelineEventDragging_1 = __webpack_require__(40);
var TimelineEventResizing_1 = __webpack_require__(41);
var TimelineView_defaults_1 = __webpack_require__(42);
var TimelineView = /** @class */ (function (_super) {
tslib_1.__extends(TimelineView, _super);
function TimelineView(calendar, viewSpec) {
var _this = _super.call(this, calendar, viewSpec) || this;
_this.emphasizeWeeks = false;
_this.isTimeBodyScrolled = false;
_this.slotWidth = _this.opt('slotWidth');
return _this;
}
// Footprints
// ------------------------------------------------------------------------------------------------------------------
/*
TODO: avoid using Moments. use slat system somehow
THEN, can have componentFootprintToSegs handle this on its own
*/
TimelineView.prototype.normalizeComponentFootprint = function (componentFootprint) {
var adjustedEnd;
var adjustedStart;
var unzonedRange = componentFootprint.unzonedRange;
if (this.isTimeScale) {
adjustedStart = this.normalizeGridDate(unzonedRange.getStart());
adjustedEnd = this.normalizeGridDate(unzonedRange.getEnd());
}
else {
var dayRange = this.computeDayRange(unzonedRange);
if (this.largeUnit) {
adjustedStart = dayRange.start.clone().startOf(this.largeUnit);
adjustedEnd = dayRange.end.clone().startOf(this.largeUnit);
// if date is partially through the interval, or is in the same interval as the start,
// make the exclusive end be the *next* interval
if (!adjustedEnd.isSame(dayRange.end) || !adjustedEnd.isAfter(adjustedStart)) {
adjustedEnd.add(this.slotDuration);
}
}
else {
adjustedStart = dayRange.start;
adjustedEnd = dayRange.end;
}
}
return new fullcalendar_1.ComponentFootprint(new fullcalendar_1.UnzonedRange(adjustedStart, adjustedEnd), !this.isTimeScale // isAllDay
);
};
TimelineView.prototype.componentFootprintToSegs = function (footprint) {
var footprintStart = footprint.unzonedRange.getStart();
var footprintEnd = footprint.unzonedRange.getEnd();
var normalFootprint = this.normalizeComponentFootprint(footprint);
var segs = [];
// protect against when the span is entirely in an invalid date region
if (this.computeDateSnapCoverage(footprintStart) < this.computeDateSnapCoverage(footprintEnd)) {
// intersect the footprint's range with the grid'd range
var segRange = normalFootprint.unzonedRange.intersect(this.normalizedUnzonedRange);
if (segRange) {
var segStart = segRange.getStart();
var segEnd = segRange.getEnd();
segs.push({
start: segStart,
end: segEnd,
isStart: segRange.isStart && this.isValidDate(segStart),
isEnd: segRange.isEnd && this.isValidDate(segEnd.clone().subtract(1))
});
}
}
// TODO: what if month slots? should round it to nearest month
// TODO: dragging/resizing in this situation? deltas for dragging/resizing breaks down
return segs;
};
// Date Computation
// ------------------------------------------------------------------------------------------------------------------
/*
Makes the given date consistent with isTimeScale/largeUnit,
so, either removes the times, ensures a time, or makes it the startOf largeUnit.
Strips all timezones. Returns new copy.
TODO: should maybe be called "normalizeRangeDate".
*/
TimelineView.prototype.normalizeGridDate = function (date) {
var normalDate;
if (this.isTimeScale) {
normalDate = date.clone();
if (!normalDate.hasTime()) {
normalDate.time(0);
}
}
else {
normalDate = date.clone().stripTime();
if (this.largeUnit) {
normalDate.startOf(this.largeUnit);
}
}
return normalDate;
};
TimelineView.prototype.isValidDate = function (date) {
if (this.isHiddenDay(date)) {
return false;
}
else if (this.isTimeScale) {
// determine if the time is within minTime/maxTime, which may have wacky values
var ms = date.time() - this.dateProfile.minTime; // milliseconds since minTime
ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock
return ms < this.timeWindowMs; // before the maxTime?
}
else {
return true;
}
};
TimelineView.prototype.updateGridDates = function () {
var snapIndex = -1;
var snapDiff = 0; // index of the diff :(
var snapDiffToIndex = [];
var snapIndexToDiff = [];
var date = this.normalizedUnzonedStart.clone();
while (date < this.normalizedUnzonedEnd) {
if (this.isValidDate(date)) {
snapIndex++;
snapDiffToIndex.push(snapIndex);
snapIndexToDiff.push(snapDiff);
}
else {
snapDiffToIndex.push(snapIndex + 0.5);
}
date.add(this.snapDuration);
snapDiff++;
}
this.snapDiffToIndex = snapDiffToIndex;
this.snapIndexToDiff = snapIndexToDiff;
this.snapCnt = snapIndex + 1; // is always one behind
this.slotCnt = this.snapCnt / this.snapsPerSlot;
};
// Skeleton Rendering
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.renderSkeleton = function () {
this.el.addClass('fc-timeline');
if (this.opt('eventOverlap') === false) {
this.el.addClass('fc-no-overlap');
}
this.el.html(this.renderSkeletonHtml());
this.timeHeadEl = this.el.find('thead .fc-time-area');
this.timeBodyEl = this.el.find('tbody .fc-time-area');
this.timeHeadScroller = new ClippedScroller_1.default({
overflowX: 'clipped-scroll',
overflowY: 'hidden'
});
this.timeHeadScroller.canvas = new ScrollerCanvas_1.default();
this.timeHeadScroller.render();
this.timeHeadScroller.el.appendTo(this.timeHeadEl);
this.timeBodyScroller = new ClippedScroller_1.default();
this.timeBodyScroller.canvas = new ScrollerCanvas_1.default();
this.timeBodyScroller.render();
this.timeBodyScroller.el.appendTo(this.timeBodyEl);
this.isTimeBodyScrolled = false; // because if the grid has been rerendered, it will get a zero scroll
this.timeBodyScroller.on('scroll', fullcalendar_1.proxy(this, 'handleTimeBodyScrolled'));
this.slatContainerEl = $('<div class="fc-slats"/>').appendTo(this.timeBodyScroller.canvas.bgEl);
this.segContainerEl = $('<div class="fc-event-container"/>').appendTo(this.timeBodyScroller.canvas.contentEl);
this.bgSegContainerEl = this.timeBodyScroller.canvas.bgEl;
this.timeBodyBoundCache = new fullcalendar_1.CoordCache({
els: this.timeBodyScroller.canvas.el,
isHorizontal: true,
isVertical: true
});
this.timeScrollJoiner = new ScrollJoiner_1.default('horizontal', [this.timeHeadScroller, this.timeBodyScroller]);
// the date/time text on the top axis that stays put while scrolling happens
this.headDateFollower = new ScrollFollower_1.default(this.timeHeadScroller, true); // allowPointerEvents=true
// the event titles that stay put while scrolling happens
this.eventTitleFollower = new ScrollFollower_1.default(this.timeBodyScroller);
this.eventTitleFollower.minTravel = 50;
//
if (this.isRTL) {
this.eventTitleFollower.containOnNaturalRight = true;
}
else {
this.eventTitleFollower.containOnNaturalLeft = true;
}
_super.prototype.renderSkeleton.call(this);
};
TimelineView.prototype.renderSkeletonHtml = function () {
var theme = this.calendar.theme;
return "<table class=\"" + theme.getClass('tableGrid') + "\"> <thead class=\"fc-head\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetHeader') + "\"></td> </tr> </thead> <tbody class=\"fc-body\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetContent') + "\"></td> </tr> </tbody> </table>";
};
TimelineView.prototype.unrenderSkeleton = function () {
this.handleTimeBodyScrolled(0);
_super.prototype.unrenderSkeleton.call(this);
};
// Date Rendering
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.renderDates = function (dateProfile) {
TimelineView_defaults_1.initScaleProps(this);
this.timeWindowMs = dateProfile.maxTime - dateProfile.minTime;
// makes sure zone is stripped
this.normalizedUnzonedStart = this.normalizeGridDate(dateProfile.renderUnzonedRange.getStart());
this.normalizedUnzonedEnd = this.normalizeGridDate(dateProfile.renderUnzonedRange.getEnd());
// apply minTime/maxTime
// TODO: move towards .time(), but didn't play well with negatives.
// TODO: View should be responsible.
if (this.isTimeScale) {
this.normalizedUnzonedStart.add(dateProfile.minTime);
this.normalizedUnzonedEnd.subtract(1, 'day').add(dateProfile.maxTime);
}
this.normalizedUnzonedRange = new fullcalendar_1.UnzonedRange(this.normalizedUnzonedStart, this.normalizedUnzonedEnd);
var slotDates = [];
var date = this.normalizedUnzonedStart.clone();
this.calendar.localizeMoment(date);
while (date < this.normalizedUnzonedEnd) {
if (this.isValidDate(date)) {
slotDates.push(date.clone());
}
date.add(this.slotDuration);
}
this.slotDates = slotDates;
this.updateGridDates();
var slatHtmlRes = this.renderSlatHtml();
this.timeHeadScroller.canvas.contentEl.html(slatHtmlRes.headHtml);
this.timeHeadColEls = this.timeHeadScroller.canvas.contentEl.find('col');
this.slatContainerEl.html(slatHtmlRes.bodyHtml);
this.slatColEls = this.slatContainerEl.find('col');
this.slatEls = this.slatContainerEl.find('td');
this.slatCoordCache = new fullcalendar_1.CoordCache({
els: this.slatEls,
isHorizontal: true
});
// for the inner divs within the slats
// used for event rendering and scrollTime, to disregard slat border
this.slatInnerCoordCache = new fullcalendar_1.CoordCache({
els: this.slatEls.find('> div'),
isHorizontal: true,
// we use this coord cache for getPosition* for event rendering.
// workaround for .fc-content's negative margins.
offsetParent: this.timeBodyScroller.canvas.el
});
for (var i = 0; i < this.slotDates.length; i++) {
date = this.slotDates[i];
this.publiclyTrigger('dayRender', {
context: this,
args: [date, this.slatEls.eq(i), this]
});
}
if (this.headDateFollower) {
this.headDateFollower.setSpriteEls(this.timeHeadEl.find('tr:not(:last-child) .fc-cell-text'));
}
};
TimelineView.prototype.unrenderDates = function () {
if (this.headDateFollower) {
this.headDateFollower.clearSprites();
}
this.timeHeadScroller.canvas.contentEl.empty();
this.slatContainerEl.empty();
// clear the widths,
// for no jupiness when navigating
this.timeHeadScroller.canvas.clearWidth();
this.timeBodyScroller.canvas.clearWidth();
};
TimelineView.prototype.renderSlatHtml = function () {
var cell;
var date;
var rowCells;
var format;
var theme = this.calendar.theme;
var labelInterval = this.labelInterval;
var formats = this.headerFormats;
var cellRows = formats.map(function (format) { return []; }); // indexed by row,col
var leadingCell = null;
var prevWeekNumber = null;
var slotDates = this.slotDates;
var slotCells = []; // meta
var rowUnits = formats.map(function (format) { return (fullcalendar_1.queryMostGranularFormatUnit(format)); });
for (var _i = 0, slotDates_1 = slotDates; _i < slotDates_1.length; _i++) {
date = slotDates_1[_i];
var weekNumber = date.week();
var isWeekStart = this.emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber);
for (var row = 0; row < formats.length; row++) {
format = formats[row];
rowCells = cellRows[row];
leadingCell = rowCells[rowCells.length - 1];
var isSuperRow = (formats.length > 1) && (row < (formats.length - 1)); // more than one row and not the last
var newCell = null;
if (isSuperRow) {
var text = date.format(format);
if (!leadingCell || (leadingCell.text !== text)) {
newCell = this.buildCellObject(date, text, rowUnits[row]);
}
else {
leadingCell.colspan += 1;
}
}
else {
if (!leadingCell || fullcalendar_1.isInt(fullcalendar_1.divideRangeByDuration(this.normalizedUnzonedStart, date, labelInterval))) {
var text = date.format(format);
newCell = this.buildCellObject(date, text, rowUnits[row]);
}
else {
leadingCell.colspan += 1;
}
}
if (newCell) {
newCell.weekStart = isWeekStart;
rowCells.push(newCell);
}
}
slotCells.push({ weekStart: isWeekStart });
prevWeekNumber = weekNumber;
}
var isChrono = labelInterval > this.slotDuration;
var isSingleDay = this.slotDuration.as('days') === 1;
var html = '<table class="' + theme.getClass('tableGrid') + '">';
html += '<colgroup>';
for (var _a = 0, slotDates_2 = slotDates; _a < slotDates_2.length; _a++) {
date = slotDates_2[_a];
html += '<col/>';
}
html += '</colgroup>';
html += '<tbody>';
for (var i = 0; i < cellRows.length; i++) {
rowCells = cellRows[i];
var isLast = i === (cellRows.length - 1);
html += '<tr' + (isChrono && isLast ? ' class="fc-chrono"' : '') + '>';
for (var _b = 0, rowCells_1 = rowCells; _b < rowCells_1.length; _b++) {
cell = rowCells_1[_b];
var headerCellClassNames = [theme.getClass('widgetHeader')];
if (cell.weekStart) {
headerCellClassNames.push('fc-em-cell');
}
if (isSingleDay) {
headerCellClassNames = headerCellClassNames.concat(this.getDayClasses(cell.date, true) // adds "today" class and other day-based classes
);
}
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>';
}
html += '</tr>';
}
html += '</tbody></table>';
var slatHtml = '<table class="' + theme.getClass('tableGrid') + '">';
slatHtml += '<colgroup>';
for (var _c = 0, slotCells_1 = slotCells; _c < slotCells_1.length; _c++) {
cell = slotCells_1[_c];
slatHtml += '<col/>';
}
slatHtml += '</colgroup>';
slatHtml += '<tbody><tr>';
for (var i = 0; i < slotCells.length; i++) {
cell = slotCells[i];
date = slotDates[i];
slatHtml += this.slatCellHtml(date, cell.weekStart);
}
slatHtml += '</tr></tbody></table>';
return { headHtml: html, bodyHtml: slatHtml };
};
TimelineView.prototype.buildCellObject = function (date, text, rowUnit) {
date = date.clone(); // ensure our own reference
var spanHtml = this.buildGotoAnchorHtml({
date: date,
type: rowUnit,
forceOff: !rowUnit
}, {
'class': 'fc-cell-text'
}, fullcalendar_1.htmlEscape(text));
return { text: text, spanHtml: spanHtml, date: date, colspan: 1 };
};
TimelineView.prototype.slatCellHtml = function (date, isEm) {
var classes;
var theme = this.calendar.theme;
if (this.isTimeScale) {
classes = [];
classes.push(fullcalendar_1.isInt(fullcalendar_1.divideRangeByDuration(this.normalizedUnzonedStart, date, this.labelInterval)) ?
'fc-major' :
'fc-minor');
}
else {
classes = this.getDayClasses(date);
classes.push('fc-day');
}
classes.unshift(theme.getClass('widgetContent'));
if (isEm) {
classes.push('fc-em-cell');
}
return '<td class="' + classes.join(' ') + '"' +
' data-date="' + date.format() + '"' +
'><div /></td>';
};
// Business Hours
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.renderBusinessHours = function (businessHourPayload) {
if (!this.largeUnit) {
return _super.prototype.renderBusinessHours.call(this, businessHourPayload);
}
};
// Now Indicator
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.getNowIndicatorUnit = function () {
// TODO: converge with largeUnit. precompute
if (this.isTimeScale) {
return fullcalendar_1.computeGreatestUnit(this.slotDuration);
}
};
// will only execute if isTimeScale
TimelineView.prototype.renderNowIndicator = function (date) {
var nodes = [];
date = this.normalizeGridDate(date);
if (this.normalizedUnzonedRange.containsDate(date)) {
var coord = this.dateToCoord(date);
var css = this.isRTL ?
{ right: -coord } :
{ left: coord };
nodes.push($("<div class='fc-now-indicator fc-now-indicator-arrow'></div>")
.css(css)
.appendTo(this.timeHeadScroller.canvas.el)[0]);
nodes.push($("<div class='fc-now-indicator fc-now-indicator-line'></div>")
.css(css)
.appendTo(this.timeBodyScroller.canvas.el)[0]);
}
this.nowIndicatorEls = $(nodes);
};
// will only execute if isTimeScale
TimelineView.prototype.unrenderNowIndicator = function () {
if (this.nowIndicatorEls) {
this.nowIndicatorEls.remove();
this.nowIndicatorEls = null;
}
};
// Sizing
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.updateSize = function (totalHeight, isAuto, isResize) {
var bodyHeight;
var containerMinWidth;
var containerWidth;
var nonLastSlotWidth;
if (isAuto) {
bodyHeight = 'auto';
}
else {
bodyHeight = totalHeight - this.headHeight() - this.queryMiscHeight();
}
this.timeBodyScroller.setHeight(bodyHeight);
// reason for this complicated method is that things went wrong when:
// slots/headers didn't fill content area and needed to be stretched
// cells wouldn't align (rounding issues with available width calculated
// differently because of padding VS scrollbar trick)
var isDatesRendered = this.timeHeadColEls; // TODO: refactor use of this
if (isDatesRendered) {
var slotWidth = Math.round(this.slotWidth || (this.slotWidth = this.computeSlotWidth()));
containerWidth = slotWidth * this.slotDates.length;
containerMinWidth = '';
nonLastSlotWidth = slotWidth;
var availableWidth = this.timeBodyScroller.getClientWidth();
if (availableWidth > containerWidth) {
containerMinWidth = availableWidth;
containerWidth = '';
nonLastSlotWidth = Math.floor(availableWidth / this.slotDates.length);
}
}
else {
containerWidth = '';
containerMinWidth = '';
}
this.timeHeadScroller.canvas.setWidth(containerWidth);
this.timeHeadScroller.canvas.setMinWidth(containerMinWidth);
this.timeBodyScroller.canvas.setWidth(containerWidth);
this.timeBodyScroller.canvas.setMinWidth(containerMinWidth);
if (isDatesRendered) {
this.timeHeadColEls.slice(0, -1).add(this.slatColEls.slice(0, -1))
.css('width', nonLastSlotWidth);
}
this.timeHeadScroller.updateSize();
this.timeBodyScroller.updateSize();
this.timeScrollJoiner.update();
if (isDatesRendered) {
this.buildCoords();
// TODO: left/right CSS assignment also happens earlier in renderFgSegs
this.updateSegPositions();
// this updateSize method is triggered by callers who don't always subsequently call updateNowIndicator,
// and updateSize always has the risk of changing horizontal spacing which will affect nowIndicator positioning,
// so always call it here too. will often rerender twice unfortunately.
// TODO: more closely integrate updateSize with updateNowIndicator
this.updateNowIndicator();
}
if (this.headDateFollower) {
this.headDateFollower.update();
}
if (this.eventTitleFollower) {
this.eventTitleFollower.update();
}
};
TimelineView.prototype.queryMiscHeight = function () {
return this.el.outerHeight() -
this.timeHeadScroller.el.outerHeight() -
this.timeBodyScroller.el.outerHeight();
};
TimelineView.prototype.computeSlotWidth = function () {
var maxInnerWidth = 0; // TODO: harness core's `matchCellWidths` for this
var innerEls = this.timeHeadEl.find('tr:last-child th .fc-cell-text'); // TODO: cache
innerEls.each(function (i, node) {
var innerWidth = $(node).outerWidth();
return maxInnerWidth = Math.max(maxInnerWidth, innerWidth);
});
var headerWidth = maxInnerWidth + 1; // assume no padding, and one pixel border
var slotsPerLabel = fullcalendar_1.divideDurationByDuration(this.labelInterval, this.slotDuration); // TODO: rename labelDuration?
var slotWidth = Math.ceil(headerWidth / slotsPerLabel);
var minWidth = this.timeHeadColEls.eq(0).css('min-width');
if (minWidth) {
minWidth = parseInt(minWidth, 10);
if (minWidth) {
slotWidth = Math.max(slotWidth, minWidth);
}
}
return slotWidth;
};
// Coordinates
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.buildCoords = function () {
this.timeBodyBoundCache.build();
this.slatCoordCache.build();
this.slatInnerCoordCache.build();
};
// returned value is between 0 and the number of snaps
TimelineView.prototype.computeDateSnapCoverage = function (date) {
var snapDiff = fullcalendar_1.divideRangeByDuration(this.normalizedUnzonedStart, date, this.snapDuration);
if (snapDiff < 0) {
return 0;
}
else if (snapDiff >= this.snapDiffToIndex.length) {
return this.snapCnt;
}
else {
var snapDiffInt = Math.floor(snapDiff);
var snapCoverage = this.snapDiffToIndex[snapDiffInt];
if (fullcalendar_1.isInt(snapCoverage)) {
snapCoverage += snapDiff - snapDiffInt; // add the remainder
}
else {
// a fractional value, meaning the date is not visible
// always round up in this case. works for start AND end dates in a range.
snapCoverage = Math.ceil(snapCoverage);
}
return snapCoverage;
}
};
// for LTR, results range from 0 to width of area
// for RTL, results range from negative width of area to 0
TimelineView.prototype.dateToCoord = function (date) {
var snapCoverage = this.computeDateSnapCoverage(date);
var slotCoverage = snapCoverage / this.snapsPerSlot;
var slotIndex = Math.floor(slotCoverage);
slotIndex = Math.min(slotIndex, this.slotCnt - 1);
var partial = slotCoverage - slotIndex;
var coordCache = this.slatInnerCoordCache;
if (this.isRTL) {
return (coordCache.getRightPosition(slotIndex) -
(coordCache.getWidth(slotIndex) * partial)) - this.timeBodyBoundCache.getWidth(0);
}
else {
return (coordCache.getLeftPosition(slotIndex) +
(coordCache.getWidth(slotIndex) * partial));
}
};
TimelineView.prototype.rangeToCoords = function (range) {
if (this.isRTL) {
return { right: this.dateToCoord(range.start), left: this.dateToCoord(range.end) };
}
else {
return { left: this.dateToCoord(range.start), right: this.dateToCoord(range.end) };
}
};
// a getter / setter
TimelineView.prototype.headHeight = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var table = this.timeHeadScroller.canvas.contentEl.find('table');
return table.height.apply(table, args);
};
// this needs to be called if v scrollbars appear on body container. or zooming
TimelineView.prototype.updateSegPositions = function () {
var segs = [].concat(this.getEventSegs(), this.getBusinessHourSegs());
for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
var seg = segs_1[_i];
var coords = this.rangeToCoords(seg);
seg.el.css({
left: (seg.left = coords.left),
right: -(seg.right = coords.right)
});
}
};
// Scrolling
// ---------------------------------------------------------------------------------
TimelineView.prototype.handleTimeBodyScrolled = function (top) {
if (top) {
if (!this.isTimeBodyScrolled) {
this.isTimeBodyScrolled = true;
this.el.addClass('fc-scrolled');
}
}
else {
if (this.isTimeBodyScrolled) {
this.isTimeBodyScrolled = false;
this.el.removeClass('fc-scrolled');
}
}
};
TimelineView.prototype.computeInitialDateScroll = function () {
var unzonedRange = this.get('dateProfile').activeUnzonedRange;
var left = 0;
if (this.isTimeScale) {
var scrollTime = this.opt('scrollTime');
if (scrollTime) {
scrollTime = moment.duration(scrollTime);
left = this.dateToCoord(unzonedRange.getStart().time(scrollTime)); // TODO: fix this for RTL
}
}
return { left: left };
};
TimelineView.prototype.queryDateScroll = function () {
return { left: this.timeBodyScroller.getScrollLeft() };
};
TimelineView.prototype.applyDateScroll = function (scroll) {
if (scroll.left != null) {
// TODO: workaround for FF. the ScrollJoiner sibling won't react fast enough
// to override the native initial crappy scroll that FF applies.
// TODO: have the ScrollJoiner handle this
// Similar code in ResourceTimelineView::setScroll
this.timeHeadScroller.setScrollLeft(scroll.left);
this.timeBodyScroller.setScrollLeft(scroll.left);
}
};
// Hit System
// ------------------------------------------------------------------------------------------------------------------
TimelineView.prototype.prepareHits = function () {
this.buildCoords();
};
// FYI: we don't want to clear the slatCoordCache in releaseHits()
// because those coordinates are needed for dateToCoord()
TimelineView.prototype.queryHit = function (leftOffset, topOffset) {
var snapsPerSlot = this.snapsPerSlot;
var slatCoordCache = this.slatCoordCache;
var timeBodyBoundCache = this.timeBodyBoundCache;
// within scroll container's content rectangle?
if (timeBodyBoundCache.isPointInBounds(leftOffset, topOffset)) {
var slatIndex = slatCoordCache.getHorizontalIndex(leftOffset);
if (slatIndex != null) {
var localSnapIndex = void 0;
var partial = void 0;
var snapIndex = void 0;
var snapLeft = void 0;
var snapRight = void 0;
var slatWidth = slatCoordCache.getWidth(slatIndex);
if (this.isRTL) {