Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
main.js 49.85 KiB
/*!
FullCalendar Resource Timeline Plugin v4.3.0
Docs & License: https://fullcalendar.io/scheduler
(c) 2019 Adam Shaw
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core'), require('@fullcalendar/timeline'), require('@fullcalendar/resource-common')) :
typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core', '@fullcalendar/timeline', '@fullcalendar/resource-common'], factory) :
(global = global || self, factory(global.FullCalendarResourceTimeline = {}, global.FullCalendar, global.FullCalendarTimeline, global.FullCalendarResourceCommon));
}(this, function (exports, core, TimelinePlugin, ResourceCommonPlugin) { 'use strict';
var TimelinePlugin__default = 'default' in TimelinePlugin ? TimelinePlugin['default'] : TimelinePlugin;
var ResourceCommonPlugin__default = 'default' in ResourceCommonPlugin ? ResourceCommonPlugin['default'] : ResourceCommonPlugin;
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
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]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var Row = /** @class */ (function (_super) {
__extends(Row, _super);
function Row(context, spreadsheetParent, spreadsheetNextSibling, timeAxisParent, timeAxisNextSibling) {
var _this = _super.call(this, context) || this;
_this.isSizeDirty = false;
spreadsheetParent.insertBefore(_this.spreadsheetTr = document.createElement('tr'), spreadsheetNextSibling);
timeAxisParent.insertBefore(_this.timeAxisTr = document.createElement('tr'), timeAxisNextSibling);
return _this;
}
Row.prototype.destroy = function () {
core.removeElement(this.spreadsheetTr);
core.removeElement(this.timeAxisTr);
_super.prototype.destroy.call(this);
};
Row.prototype.updateSize = function (isResize) {
this.isSizeDirty = false;
};
return Row;
}(core.Component));
function updateExpanderIcon(el, isExpanded) {
var classList = el.classList;
if (isExpanded) {
classList.remove('fc-icon-plus-square');
classList.add('fc-icon-minus-square');
}
else {
classList.remove('fc-icon-minus-square');
classList.add('fc-icon-plus-square');
}
}
function clearExpanderIcon(el) {
var classList = el.classList;
classList.remove('fc-icon-minus-square');
classList.remove('fc-icon-plus-square');
}
function updateTrResourceId(tr, resourceId) {
tr.setAttribute('data-resource-id', resourceId);
}
var GroupRow = /** @class */ (function (_super) {
__extends(GroupRow, _super);
function GroupRow() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._renderCells = core.memoizeRendering(_this.renderCells, _this.unrenderCells);
_this._updateExpanderIcon = core.memoizeRendering(_this.updateExpanderIcon, null, [_this._renderCells]);
_this.onExpanderClick = function (ev) {
var props = _this.props;
_this.calendar.dispatch({
type: 'SET_RESOURCE_ENTITY_EXPANDED',
id: props.id,
isExpanded: !props.isExpanded
});
};
return _this;
}
GroupRow.prototype.render = function (props) {
this._renderCells(props.group, props.spreadsheetColCnt);
this._updateExpanderIcon(props.isExpanded);
this.isSizeDirty = true;
};
GroupRow.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._renderCells.unrender(); // should unrender everything else
};
GroupRow.prototype.renderCells = function (group, spreadsheetColCnt) {
var spreadsheetContentEl = this.renderSpreadsheetContent(group);
this.spreadsheetTr.appendChild(core.createElement('td', {
className: 'fc-divider',
colSpan: spreadsheetColCnt // span across all columns
}, this.spreadsheetHeightEl = core.createElement('div', null, spreadsheetContentEl)) // needed by setTrInnerHeight
);
this.expanderIconEl = spreadsheetContentEl.querySelector('.fc-icon');
this.expanderIconEl.parentElement.addEventListener('click', this.onExpanderClick);
// insert a single cell, with a single empty <div>.
// there will be no content
this.timeAxisTr.appendChild(core.createElement('td', { className: 'fc-divider' }, this.timeAxisHeightEl = document.createElement('div')));
};
GroupRow.prototype.unrenderCells = function () {
this.spreadsheetTr.innerHTML = '';
this.timeAxisTr.innerHTML = '';
};
/*
Renders the content wrapper element that will be inserted into this row's TD cell.
*/
GroupRow.prototype.renderSpreadsheetContent = function (group) {
var text = this.renderCellText(group);
var contentEl = core.htmlToElement('<div class="fc-cell-content">' +
'<span class="fc-expander">' +
'<span class="fc-icon"></span>' +
'</span>' +
'<span class="fc-cell-text">' +
(text ? core.htmlEscape(text) : ' ') +
'</span>' +
'</div>');
var filter = group.spec.render;
if (typeof filter === 'function') {
contentEl = filter(contentEl, group.value) || contentEl;
}
return contentEl;
};
GroupRow.prototype.renderCellText = function (group) {
var text = group.value || ''; // might be null/undefined if an ad-hoc grouping
var filter = group.spec.text;
if (typeof filter === 'function') {
text = filter(text) || text;
}
return text;
};
GroupRow.prototype.getHeightEls = function () {
return [this.spreadsheetHeightEl, this.timeAxisHeightEl];
};
GroupRow.prototype.updateExpanderIcon = function (isExpanded) {
updateExpanderIcon(this.expanderIconEl, isExpanded);
};
return GroupRow;
}(Row));
GroupRow.addEqualityFuncs({
group: ResourceCommonPlugin.isGroupsEqual // HACK for ResourceTimelineView::renderRows
});
var SpreadsheetRow = /** @class */ (function (_super) {
__extends(SpreadsheetRow, _super);
function SpreadsheetRow(context, tr) {
var _this = _super.call(this, context) || this;
_this._renderRow = core.memoizeRendering(_this.renderRow, _this.unrenderRow);
_this._updateTrResourceId = core.memoizeRendering(updateTrResourceId, null, [_this._renderRow]);
_this._updateExpanderIcon = core.memoizeRendering(_this.updateExpanderIcon, null, [_this._renderRow]);
_this.onExpanderClick = function (ev) {
var props = _this.props;
_this.calendar.dispatch({
type: 'SET_RESOURCE_ENTITY_EXPANDED',
id: props.id,
isExpanded: !props.isExpanded
});
};
_this.tr = tr;
return _this;
}
SpreadsheetRow.prototype.render = function (props) {
this._renderRow(props.resource, props.rowSpans, props.depth, props.colSpecs);
this._updateTrResourceId(this.tr, props.resource.id); // TODO: only use public ID?
this._updateExpanderIcon(props.hasChildren, props.isExpanded);
};
SpreadsheetRow.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._renderRow.unrender(); // should unrender everything else
};
SpreadsheetRow.prototype.renderRow = function (resource, rowSpans, depth, colSpecs) {
var _a = this, tr = _a.tr, theme = _a.theme, calendar = _a.calendar, view = _a.view;
var resourceFields = ResourceCommonPlugin.buildResourceFields(resource); // slightly inefficient. already done up the call stack
var mainTd;
for (var i = 0; i < colSpecs.length; i++) {
var colSpec = colSpecs[i];
var rowSpan = rowSpans[i];
if (rowSpan === 0) { // not responsible for group-based rows. VRowGroup is
continue;
}
else if (rowSpan == null) {
rowSpan = 1;
}
var text = void 0;
if (colSpec.field) {
text = resourceFields[colSpec.field];
}
else {
text = ResourceCommonPlugin.buildResourceTextFunc(colSpec.text, calendar)(resource);
}
var contentEl = core.htmlToElement('<div class="fc-cell-content">' +
(colSpec.isMain ? renderIconHtml(depth) : '') +
'<span class="fc-cell-text">' +
(text ? core.htmlEscape(text) : ' ') +
'</span>' +
'</div>');
if (typeof colSpec.render === 'function') { // a filter function for the element
contentEl = colSpec.render(new ResourceCommonPlugin.ResourceApi(calendar, resource), contentEl) || contentEl;
}
if (rowSpan > 1) {
contentEl.classList.add('fc-sticky');
}
var td = core.createElement('td', {
className: theme.getClass('widgetContent'),
rowspan: rowSpan
}, contentEl);
// the first cell of the row needs to have an inner div for setTrInnerHeight
if (colSpec.isMain) {
td.appendChild(this.heightEl = core.createElement('div', null, td.childNodes) // inner wrap
);
mainTd = td;
}
tr.appendChild(td);
}
this.expanderIconEl = tr.querySelector('.fc-expander-space .fc-icon');
// wait until very end
view.publiclyTrigger('resourceRender', [
{
resource: new ResourceCommonPlugin.ResourceApi(calendar, resource),
el: mainTd,
view: view
}
]);
};
SpreadsheetRow.prototype.unrenderRow = function () {
this.tr.innerHTML = '';
};
SpreadsheetRow.prototype.updateExpanderIcon = function (hasChildren, isExpanded) {
var expanderIconEl = this.expanderIconEl;
var expanderEl = expanderIconEl.parentElement;
if (expanderIconEl &&
expanderEl // why would this be null?? was the case in IE11
) {
if (hasChildren) {
expanderEl.addEventListener('click', this.onExpanderClick);
expanderEl.classList.add('fc-expander');
updateExpanderIcon(expanderIconEl, isExpanded);
}
else {
expanderEl.removeEventListener('click', this.onExpanderClick);
expanderEl.classList.remove('fc-expander');
clearExpanderIcon(expanderIconEl);
}
}
};
return SpreadsheetRow;
}(core.Component));
/*
Renders the HTML responsible for the subrow expander area,
as well as the space before it (used to align expanders of similar depths)
*/
function renderIconHtml(depth) {
var html = '';
for (var i = 0; i < depth; i++) {
html += '<span class="fc-icon"></span>';
}
html +=
'<span class="fc-expander-space">' +
'<span class="fc-icon"></span>' +
'</span>';
return html;
}
var ResourceRow = /** @class */ (function (_super) {
__extends(ResourceRow, _super);
function ResourceRow(context, a, b, c, d, timeAxis) {
var _this = _super.call(this, context, a, b, c, d) || this;
_this._updateTrResourceId = core.memoizeRendering(updateTrResourceId);
_this.spreadsheetRow = new SpreadsheetRow(context, _this.spreadsheetTr);
_this.timeAxisTr.appendChild(core.createElement('td', { className: _this.theme.getClass('widgetContent') }, _this.innerContainerEl = document.createElement('div')));
_this.lane = new TimelinePlugin.TimelineLane(context, _this.innerContainerEl, _this.innerContainerEl, timeAxis);
return _this;
}
ResourceRow.prototype.destroy = function () {
this.spreadsheetRow.destroy();
this.lane.destroy();
_super.prototype.destroy.call(this);
};
ResourceRow.prototype.render = function (props) {
// spreadsheetRow handles calling updateTrResourceId for spreadsheetTr
this.spreadsheetRow.receiveProps({
colSpecs: props.colSpecs,
id: props.id,
rowSpans: props.rowSpans,
depth: props.depth,
isExpanded: props.isExpanded,
hasChildren: props.hasChildren,
resource: props.resource
});
this._updateTrResourceId(this.timeAxisTr, props.resource.id);
this.lane.receiveProps({
dateProfile: props.dateProfile,
nextDayThreshold: props.nextDayThreshold,
businessHours: props.businessHours,
eventStore: props.eventStore,
eventUiBases: props.eventUiBases,
dateSelection: props.dateSelection,
eventSelection: props.eventSelection,
eventDrag: props.eventDrag,
eventResize: props.eventResize
});
this.isSizeDirty = true;
};
ResourceRow.prototype.updateSize = function (isResize) {
_super.prototype.updateSize.call(this, isResize);
this.lane.updateSize(isResize);
};
ResourceRow.prototype.getHeightEls = function () {
return [this.spreadsheetRow.heightEl, this.innerContainerEl];
};
return ResourceRow;
}(Row));
ResourceRow.addEqualityFuncs({
rowSpans: core.isArraysEqual // HACK for isSizeDirty, ResourceTimelineView::renderRows
});
var COL_MIN_WIDTH = 30;
var SpreadsheetHeader = /** @class */ (function (_super) {
__extends(SpreadsheetHeader, _super);
function SpreadsheetHeader(context, parentEl) {
var _this = _super.call(this, context) || this;
_this.resizables = [];
_this.colWidths = [];
_this.emitter = new core.EmitterMixin();
parentEl.appendChild(_this.tableEl = core.createElement('table', {
className: _this.theme.getClass('tableGrid')
}));
return _this;
}
SpreadsheetHeader.prototype.destroy = function () {
for (var _i = 0, _a = this.resizables; _i < _a.length; _i++) {
var resizable = _a[_i];
resizable.destroy();
}
core.removeElement(this.tableEl);
_super.prototype.destroy.call(this);
};
SpreadsheetHeader.prototype.render = function (props) {
var theme = this.theme;
var colSpecs = props.colSpecs;
var html = '<colgroup>' + props.colTags + '</colgroup>' +
'<tbody>';
if (props.superHeaderText) {
html +=
'<tr class="fc-super">' +
'<th class="' + theme.getClass('widgetHeader') + '" colspan="' + colSpecs.length + '">' +
'<div class="fc-cell-content">' +
'<span class="fc-cell-text">' +
core.htmlEscape(props.superHeaderText) +
'</span>' +
'</div>' +
'</th>' +
'</tr>';
}
html += '<tr>';
for (var i = 0; i < colSpecs.length; i++) {
var o = colSpecs[i];
var isLast = i === (colSpecs.length - 1);
html +=
"<th class=\"" + theme.getClass('widgetHeader') + "\">" +
'<div>' +
'<div class="fc-cell-content">' +
(o.isMain ?
'<span class="fc-expander-space">' +
'<span class="fc-icon"></span>' +
'</span>' :
'') +
'<span class="fc-cell-text">' +
core.htmlEscape(o.labelText || '') + // what about normalizing this value ahead of time?
'</span>' +
'</div>' +
(!isLast ? '<div class="fc-col-resizer"></div>' : '') +
'</div>' +
'</th>';
}
html += '</tr>';
html += '</tbody>';
this.tableEl.innerHTML = html;
this.thEls = Array.prototype.slice.call(this.tableEl.querySelectorAll('th'));
this.colEls = Array.prototype.slice.call(this.tableEl.querySelectorAll('col'));
this.resizerEls = Array.prototype.slice.call(this.tableEl.querySelectorAll('.fc-col-resizer'));
this.initColResizing();
};
SpreadsheetHeader.prototype.initColResizing = function () {
var _this = this;
var ElementDraggingImpl = this.calendar.pluginSystem.hooks.elementDraggingImpl;
if (ElementDraggingImpl) {
this.resizables = this.resizerEls.map(function (handleEl, colIndex) {
var dragging = new ElementDraggingImpl(handleEl);
var startWidth;
dragging.emitter.on('dragstart', function () {
startWidth = _this.colWidths[colIndex];
if (typeof startWidth !== 'number') {
startWidth = _this.thEls[colIndex].getBoundingClientRect().width;
}
});
dragging.emitter.on('dragmove', function (pev) {
_this.colWidths[colIndex] = Math.max(startWidth + pev.deltaX * (_this.isRtl ? -1 : 1), COL_MIN_WIDTH);
_this.emitter.trigger('colwidthchange', _this.colWidths);
});
dragging.setAutoScrollEnabled(false); // because gets weird with auto-scrolling time area
return dragging;
});
}
};
return SpreadsheetHeader;
}(core.Component));
var Spreadsheet = /** @class */ (function (_super) {
__extends(Spreadsheet, _super);
function Spreadsheet(context, headParentEl, bodyParentEl) {
var _this = _super.call(this, context) || this;
_this._renderCells = core.memoizeRendering(_this.renderCells, _this.unrenderCells);
_this.layout = new TimelinePlugin.HeaderBodyLayout(headParentEl, bodyParentEl, 'clipped-scroll');
var headerEnhancedScroller = _this.layout.headerScroller.enhancedScroll;
var bodyEnhancedScroller = _this.layout.bodyScroller.enhancedScroll;
_this.header = new SpreadsheetHeader(context, headerEnhancedScroller.canvas.contentEl);
_this.header.emitter.on('colwidthchange', function (colWidths) {
_this.applyColWidths(colWidths);
});
bodyEnhancedScroller.canvas.contentEl
.appendChild(_this.bodyContainerEl = core.createElement('div', { className: 'fc-rows' }, '<table>' +
'<colgroup />' +
'<tbody />' +
'</table>'));
_this.bodyColGroup = _this.bodyContainerEl.querySelector('colgroup');
_this.bodyTbody = _this.bodyContainerEl.querySelector('tbody');
return _this;
}
Spreadsheet.prototype.destroy = function () {
this.header.destroy();
this.layout.destroy();
this._renderCells.unrender();
_super.prototype.destroy.call(this);
};
Spreadsheet.prototype.render = function (props) {
this._renderCells(props.superHeaderText, props.colSpecs);
};
Spreadsheet.prototype.renderCells = function (superHeaderText, colSpecs) {
var colTags = this.renderColTags(colSpecs);
this.header.receiveProps({
superHeaderText: superHeaderText,
colSpecs: colSpecs,
colTags: colTags
});
this.bodyColGroup.innerHTML = colTags;
this.bodyColEls = Array.prototype.slice.call(this.bodyColGroup.querySelectorAll('col'));
this.applyColWidths(colSpecs.map(function (colSpec) { return colSpec.width; }));
};
Spreadsheet.prototype.unrenderCells = function () {
this.bodyColGroup.innerHTML = '';
};
Spreadsheet.prototype.renderColTags = function (colSpecs) {
var html = '';
for (var _i = 0, colSpecs_1 = colSpecs; _i < colSpecs_1.length; _i++) {
var o = colSpecs_1[_i];
if (o.isMain) {
html += '<col class="fc-main-col"/>';
}
else {
html += '<col/>';
}
}
return html;
};
Spreadsheet.prototype.updateSize = function (isResize, totalHeight, isAuto) {
this.layout.setHeight(totalHeight, isAuto);
};
Spreadsheet.prototype.applyColWidths = function (colWidths) {
var _this = this;
colWidths.forEach(function (colWidth, colIndex) {
var headEl = _this.header.colEls[colIndex]; // bad to access child
var bodyEl = _this.bodyColEls[colIndex];
var styleVal;
if (typeof colWidth === 'number') {
styleVal = colWidth + 'px';
}
else if (typeof colWidth == null) {
styleVal = '';
}
headEl.style.width = bodyEl.style.width = styleVal;
});
};
return Spreadsheet;
}(core.Component));
var MIN_RESOURCE_AREA_WIDTH = 30; // definitely bigger than scrollbars
var ResourceTimelineView = /** @class */ (function (_super) {
__extends(ResourceTimelineView, _super);
function ResourceTimelineView(context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.isStickyScrollDirty = false;
_this.rowNodes = [];
_this.rowComponents = [];
_this.rowComponentsById = {};
_this.resourceAreaWidthDraggings = [];
_this.splitter = new ResourceCommonPlugin.ResourceSplitter(); // doesn't let it do businessHours tho
_this.hasResourceBusinessHours = core.memoize(hasResourceBusinessHours);
_this.buildRowNodes = core.memoize(ResourceCommonPlugin.buildRowNodes);
_this.hasNesting = core.memoize(hasNesting);
_this._updateHasNesting = core.memoizeRendering(_this.updateHasNesting);
var allColSpecs = _this.opt('resourceColumns') || [];
var labelText = _this.opt('resourceLabelText'); // TODO: view.override
var defaultLabelText = 'Resources'; // TODO: view.defaults
var superHeaderText = null;
if (!allColSpecs.length) {
allColSpecs.push({
labelText: labelText || defaultLabelText,
text: ResourceCommonPlugin.buildResourceTextFunc(_this.opt('resourceText'), _this.calendar)
});
}
else {
superHeaderText = labelText;
}
var plainColSpecs = [];
var groupColSpecs = [];
var groupSpecs = [];
var isVGrouping = false;
var isHGrouping = false;
for (var _i = 0, allColSpecs_1 = allColSpecs; _i < allColSpecs_1.length; _i++) {
var colSpec = allColSpecs_1[_i];
if (colSpec.group) {
groupColSpecs.push(colSpec);
}
else {
plainColSpecs.push(colSpec);
}
}
plainColSpecs[0].isMain = true;
if (groupColSpecs.length) {
groupSpecs = groupColSpecs;
isVGrouping = true;
}
else {
var hGroupField = _this.opt('resourceGroupField');
if (hGroupField) {
isHGrouping = true;
groupSpecs.push({
field: hGroupField,
text: _this.opt('resourceGroupText'),
render: _this.opt('resourceGroupRender')
});
}
}
var allOrderSpecs = core.parseFieldSpecs(_this.opt('resourceOrder'));
var plainOrderSpecs = [];
for (var _a = 0, allOrderSpecs_1 = allOrderSpecs; _a < allOrderSpecs_1.length; _a++) {
var orderSpec = allOrderSpecs_1[_a];
var isGroup = false;
for (var _b = 0, groupSpecs_1 = groupSpecs; _b < groupSpecs_1.length; _b++) {
var groupSpec = groupSpecs_1[_b];
if (groupSpec.field === orderSpec.field) {
groupSpec.order = orderSpec.order; // -1, 0, 1
isGroup = true;
break;
}
}
if (!isGroup) {
plainOrderSpecs.push(orderSpec);
}
}
_this.superHeaderText = superHeaderText;
_this.isVGrouping = isVGrouping;
_this.isHGrouping = isHGrouping;
_this.groupSpecs = groupSpecs;
_this.colSpecs = groupColSpecs.concat(plainColSpecs);
_this.orderSpecs = plainOrderSpecs;
// START RENDERING...
_this.el.classList.add('fc-timeline');
if (_this.opt('eventOverlap') === false) {
_this.el.classList.add('fc-no-overlap');
}
_this.el.innerHTML = _this.renderSkeletonHtml();
_this.resourceAreaHeadEl = _this.el.querySelector('thead .fc-resource-area');
_this.setResourceAreaWidth(_this.opt('resourceAreaWidth'));
_this.initResourceAreaWidthDragging();
_this.miscHeight = _this.el.getBoundingClientRect().height;
_this.spreadsheet = new Spreadsheet(_this.context, _this.resourceAreaHeadEl, _this.el.querySelector('tbody .fc-resource-area'));
_this.timeAxis = new TimelinePlugin.TimeAxis(_this.context, _this.el.querySelector('thead .fc-time-area'), _this.el.querySelector('tbody .fc-time-area'));
var timeAxisRowContainer = core.createElement('div', { className: 'fc-rows' }, '<table><tbody /></table>');
_this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.contentEl.appendChild(timeAxisRowContainer);
_this.timeAxisTbody = timeAxisRowContainer.querySelector('tbody');
_this.lane = new TimelinePlugin.TimelineLane(_this.context, null, _this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.bgEl, _this.timeAxis);
_this.bodyScrollJoiner = new TimelinePlugin.ScrollJoiner('vertical', [
_this.spreadsheet.layout.bodyScroller,
_this.timeAxis.layout.bodyScroller
]);
// after scrolljoiner
_this.spreadsheetBodyStickyScroller = new TimelinePlugin.StickyScroller(_this.spreadsheet.layout.bodyScroller.enhancedScroll, _this.isRtl, true // isVertical
);
_this.spreadsheet.receiveProps({
superHeaderText: _this.superHeaderText,
colSpecs: _this.colSpecs
});
// Component...
context.calendar.registerInteractiveComponent(_this, {
el: _this.timeAxis.slats.el
});
return _this;
}
ResourceTimelineView.prototype.renderSkeletonHtml = function () {
var theme = this.theme;
return "<table class=\"" + theme.getClass('tableGrid') + "\"> <thead class=\"fc-head\"> <tr> <td class=\"fc-resource-area " + theme.getClass('widgetHeader') + "\"></td> <td class=\"fc-divider fc-col-resizer " + theme.getClass('widgetHeader') + "\"></td> <td class=\"fc-time-area " + theme.getClass('widgetHeader') + "\"></td> </tr> </thead> <tbody class=\"fc-body\"> <tr> <td class=\"fc-resource-area " + theme.getClass('widgetContent') + "\"></td> <td class=\"fc-divider fc-col-resizer " + theme.getClass('widgetHeader') + "\"></td> <td class=\"fc-time-area " + theme.getClass('widgetContent') + "\"></td> </tr> </tbody> </table>";
};
ResourceTimelineView.prototype.render = function (props) {
_super.prototype.render.call(this, props);
var splitProps = this.splitter.splitProps(props);
var hasResourceBusinessHours = this.hasResourceBusinessHours(props.resourceStore);
this.timeAxis.receiveProps({
dateProfile: props.dateProfile
});
// for all-resource bg events / selections / business-hours
this.lane.receiveProps(__assign({}, splitProps[''], { dateProfile: props.dateProfile, nextDayThreshold: this.nextDayThreshold, businessHours: hasResourceBusinessHours ? null : props.businessHours }));
var newRowNodes = this.buildRowNodes(props.resourceStore, this.groupSpecs, this.orderSpecs, this.isVGrouping, props.resourceEntityExpansions, this.opt('resourcesInitiallyExpanded'));
this._updateHasNesting(this.hasNesting(newRowNodes));
this.diffRows(newRowNodes);
this.renderRows(props.dateProfile, hasResourceBusinessHours ? props.businessHours : null, // CONFUSING, comment
splitProps);
};
ResourceTimelineView.prototype.updateHasNesting = function (isNesting) {
var classList = this.el.classList;
if (isNesting) {
classList.remove('fc-flat');
}
else {
classList.add('fc-flat');
}
};
ResourceTimelineView.prototype.diffRows = function (newNodes) {
var oldNodes = this.rowNodes;
var oldLen = oldNodes.length;
var oldIndexHash = {}; // id -> index
var oldI = 0;
var newI = 0;
for (oldI = 0; oldI < oldLen; oldI++) {
oldIndexHash[oldNodes[oldI].id] = oldI;
}
// iterate new nodes
for (oldI = 0, newI = 0; newI < newNodes.length; newI++) {
var newNode = newNodes[newI];
var oldIFound = oldIndexHash[newNode.id];
if (oldIFound != null && oldIFound >= oldI) {
this.removeRows(newI, oldIFound - oldI, oldNodes); // won't do anything if same index
oldI = oldIFound + 1;
}
else {
this.addRow(newI, newNode);
}
}
// old rows that weren't found need to be removed
this.removeRows(newI, oldLen - oldI, oldNodes); // won't do anything if same index
this.rowNodes = newNodes;
};
/*
rowComponents is the in-progress result
*/
ResourceTimelineView.prototype.addRow = function (index, rowNode) {
var _a = this, rowComponents = _a.rowComponents, rowComponentsById = _a.rowComponentsById;
var nextComponent = rowComponents[index];
var newComponent = this.buildChildComponent(rowNode, this.spreadsheet.bodyTbody, nextComponent ? nextComponent.spreadsheetTr : null, this.timeAxisTbody, nextComponent ? nextComponent.timeAxisTr : null);
rowComponents.splice(index, 0, newComponent);
rowComponentsById[rowNode.id] = newComponent;
};
ResourceTimelineView.prototype.removeRows = function (startIndex, len, oldRowNodes) {
if (len) {
var _a = this, rowComponents = _a.rowComponents, rowComponentsById = _a.rowComponentsById;
for (var i = 0; i < len; i++) {
var rowComponent = rowComponents[startIndex + i];
rowComponent.destroy();
delete rowComponentsById[oldRowNodes[i].id];
}
rowComponents.splice(startIndex, len);
}
};
ResourceTimelineView.prototype.buildChildComponent = function (node, spreadsheetTbody, spreadsheetNext, timeAxisTbody, timeAxisNext) {
if (node.group) {
return new GroupRow(this.context, spreadsheetTbody, spreadsheetNext, timeAxisTbody, timeAxisNext);
}
else if (node.resource) {
return new ResourceRow(this.context, spreadsheetTbody, spreadsheetNext, timeAxisTbody, timeAxisNext, this.timeAxis);
}
};
ResourceTimelineView.prototype.renderRows = function (dateProfile, fallbackBusinessHours, splitProps) {
var _a = this, rowNodes = _a.rowNodes, rowComponents = _a.rowComponents;
for (var i = 0; i < rowNodes.length; i++) {
var rowNode = rowNodes[i];
var rowComponent = rowComponents[i];
if (rowNode.group) {
rowComponent.receiveProps({
spreadsheetColCnt: this.colSpecs.length,
id: rowNode.id,
isExpanded: rowNode.isExpanded,
group: rowNode.group
});
}
else {
var resource = rowNode.resource;
rowComponent.receiveProps(__assign({}, splitProps[resource.id], { dateProfile: dateProfile, nextDayThreshold: this.nextDayThreshold, businessHours: resource.businessHours || fallbackBusinessHours, colSpecs: this.colSpecs, id: rowNode.id, rowSpans: rowNode.rowSpans, depth: rowNode.depth, isExpanded: rowNode.isExpanded, hasChildren: rowNode.hasChildren, resource: rowNode.resource }));
}
}
};
ResourceTimelineView.prototype.updateSize = function (isResize, viewHeight, isAuto) {
// FYI: this ordering is really important
var calendar = this.calendar;
var isBaseSizing = isResize || calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated;
if (isBaseSizing) {
this.syncHeadHeights();
this.timeAxis.updateSize(isResize, viewHeight - this.miscHeight, isAuto);
this.spreadsheet.updateSize(isResize, viewHeight - this.miscHeight, isAuto);
}
var rowSizingCnt = this.updateRowSizes(isResize);
this.lane.updateSize(isResize); // is efficient. uses flags
if (isBaseSizing || rowSizingCnt) {
this.bodyScrollJoiner.update();
this.timeAxis.layout.scrollJoiner.update(); // hack
this.rowPositions = new core.PositionCache(this.timeAxis.slats.el, this.rowComponents.map(function (rowComponent) {
return rowComponent.timeAxisTr;
}), false, // isHorizontal
true // isVertical
);
this.rowPositions.build();
this.isStickyScrollDirty = true;
}
};
ResourceTimelineView.prototype.syncHeadHeights = function () {
var spreadsheetHeadEl = this.spreadsheet.header.tableEl;
var timeAxisHeadEl = this.timeAxis.header.tableEl;
spreadsheetHeadEl.style.height = '';
timeAxisHeadEl.style.height = '';
var max = Math.max(spreadsheetHeadEl.getBoundingClientRect().height, timeAxisHeadEl.getBoundingClientRect().height);
spreadsheetHeadEl.style.height =
timeAxisHeadEl.style.height = max + 'px';
};
ResourceTimelineView.prototype.updateRowSizes = function (isResize) {
var dirtyRowComponents = this.rowComponents;
if (!isResize) {
dirtyRowComponents = dirtyRowComponents.filter(function (rowComponent) {
return rowComponent.isSizeDirty;
});
}
var elArrays = dirtyRowComponents.map(function (rowComponent) {
return rowComponent.getHeightEls();
});
// reset to natural heights
for (var _i = 0, elArrays_1 = elArrays; _i < elArrays_1.length; _i++) {
var elArray = elArrays_1[_i];
for (var _a = 0, elArray_1 = elArray; _a < elArray_1.length; _a++) {
var el = elArray_1[_a];
el.style.height = '';
}
}
// let rows update their contents' heights
for (var _b = 0, dirtyRowComponents_1 = dirtyRowComponents; _b < dirtyRowComponents_1.length; _b++) {
var rowComponent = dirtyRowComponents_1[_b];
rowComponent.updateSize(isResize); // will reset isSizeDirty
}
var maxHeights = elArrays.map(function (elArray) {
var maxHeight = null;
for (var _i = 0, elArray_2 = elArray; _i < elArray_2.length; _i++) {
var el = elArray_2[_i];
var height = el.getBoundingClientRect().height;
if (maxHeight === null || height > maxHeight) {
maxHeight = height;
}
}
return maxHeight;
});
for (var i = 0; i < elArrays.length; i++) {
for (var _c = 0, _d = elArrays[i]; _c < _d.length; _c++) {
var el = _d[_c];
el.style.height = maxHeights[i] + 'px';
}
}
return dirtyRowComponents.length;
};
ResourceTimelineView.prototype.destroy = function () {
for (var _i = 0, _a = this.rowComponents; _i < _a.length; _i++) {
var rowComponent = _a[_i];
rowComponent.destroy();
}
this.rowNodes = [];
this.rowComponents = [];
this.spreadsheet.destroy();
this.timeAxis.destroy();
for (var _b = 0, _c = this.resourceAreaWidthDraggings; _b < _c.length; _b++) {
var resourceAreaWidthDragging = _c[_b];
resourceAreaWidthDragging.destroy();
}
this.spreadsheetBodyStickyScroller.destroy();
_super.prototype.destroy.call(this);
this.calendar.unregisterInteractiveComponent(this);
};
// Now Indicator
// ------------------------------------------------------------------------------------------
ResourceTimelineView.prototype.getNowIndicatorUnit = function (dateProfile) {
return this.timeAxis.getNowIndicatorUnit(dateProfile);
};
ResourceTimelineView.prototype.renderNowIndicator = function (date) {
this.timeAxis.renderNowIndicator(date);
};
ResourceTimelineView.prototype.unrenderNowIndicator = function () {
this.timeAxis.unrenderNowIndicator();
};
// Scrolling
// ------------------------------------------------------------------------------------------------------------------
// this is useful for scrolling prev/next dates while resource is scrolled down
ResourceTimelineView.prototype.queryScroll = function () {
var scroll = _super.prototype.queryScroll.call(this);
if (this.props.resourceStore) {
__assign(scroll, this.queryResourceScroll());
}
return scroll;
};
ResourceTimelineView.prototype.applyScroll = function (scroll, isResize) {
_super.prototype.applyScroll.call(this, scroll, isResize);
if (this.props.resourceStore) {
this.applyResourceScroll(scroll);
}
// avoid updating stickyscroll too often
if (isResize || this.isStickyScrollDirty) {
this.isStickyScrollDirty = false;
this.spreadsheetBodyStickyScroller.updateSize();
this.timeAxis.updateStickyScrollers();
}
};
ResourceTimelineView.prototype.computeDateScroll = function (duration) {
return this.timeAxis.computeDateScroll(duration);
};
ResourceTimelineView.prototype.queryDateScroll = function () {
return this.timeAxis.queryDateScroll();
};
ResourceTimelineView.prototype.applyDateScroll = function (scroll) {
this.timeAxis.applyDateScroll(scroll);
};
ResourceTimelineView.prototype.queryResourceScroll = function () {
var _a = this, rowComponents = _a.rowComponents, rowNodes = _a.rowNodes;
var scroll = {};
var scrollerTop = this.timeAxis.layout.bodyScroller.el.getBoundingClientRect().top; // fixed position
for (var i = 0; i < rowComponents.length; i++) {
var rowComponent = rowComponents[i];
var rowNode = rowNodes[i];
var el = rowComponent.timeAxisTr;
var elBottom = el.getBoundingClientRect().bottom; // fixed position
if (elBottom > scrollerTop) {
scroll.rowId = rowNode.id;
scroll.bottom = elBottom - scrollerTop;
break;
}
}
// TODO: what about left scroll state for spreadsheet area?
return scroll;
};
ResourceTimelineView.prototype.applyResourceScroll = function (scroll) {
var rowId = scroll.forcedRowId || scroll.rowId;
if (rowId) {
var rowComponent = this.rowComponentsById[rowId];
if (rowComponent) {
var el = rowComponent.timeAxisTr;
if (el) {
var innerTop = this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.el.getBoundingClientRect().top;
var rowRect = el.getBoundingClientRect();
var scrollTop = (scroll.forcedRowId ?
rowRect.top : // just use top edge
rowRect.bottom - scroll.bottom) - // pixels from bottom edge
innerTop;
this.timeAxis.layout.bodyScroller.enhancedScroll.setScrollTop(scrollTop);
this.spreadsheet.layout.bodyScroller.enhancedScroll.setScrollTop(scrollTop);
}
}
}
};
// TODO: scrollToResource
// Hit System
// ------------------------------------------------------------------------------------------
ResourceTimelineView.prototype.buildPositionCaches = function () {
this.timeAxis.slats.updateSize();
this.rowPositions.build();
};
ResourceTimelineView.prototype.queryHit = function (positionLeft, positionTop) {
var rowPositions = this.rowPositions;
var slats = this.timeAxis.slats;
var rowIndex = rowPositions.topToIndex(positionTop);
if (rowIndex != null) {
var resource = this.rowNodes[rowIndex].resource;
if (resource) { // not a group
var slatHit = slats.positionToHit(positionLeft);
if (slatHit) {
return {
component: this,
dateSpan: {
range: slatHit.dateSpan.range,
allDay: slatHit.dateSpan.allDay,
resourceId: resource.id
},
rect: {
left: slatHit.left,
right: slatHit.right,
top: rowPositions.tops[rowIndex],
bottom: rowPositions.bottoms[rowIndex]
},
dayEl: slatHit.dayEl,
layer: 0
};
}
}
}
};
// Resource Area
// ------------------------------------------------------------------------------------------------------------------
ResourceTimelineView.prototype.setResourceAreaWidth = function (widthVal) {
this.resourceAreaWidth = widthVal;
core.applyStyleProp(this.resourceAreaHeadEl, 'width', widthVal || '');
};
ResourceTimelineView.prototype.initResourceAreaWidthDragging = function () {
var _this = this;
var resourceAreaDividerEls = Array.prototype.slice.call(this.el.querySelectorAll('.fc-col-resizer'));
var ElementDraggingImpl = this.calendar.pluginSystem.hooks.elementDraggingImpl;
if (ElementDraggingImpl) {
this.resourceAreaWidthDraggings = resourceAreaDividerEls.map(function (el) {
var dragging = new ElementDraggingImpl(el);
var dragStartWidth;
var viewWidth;
dragging.emitter.on('dragstart', function () {
dragStartWidth = _this.resourceAreaWidth;
if (typeof dragStartWidth !== 'number') {
dragStartWidth = _this.resourceAreaHeadEl.getBoundingClientRect().width;
}
viewWidth = _this.el.getBoundingClientRect().width;
});
dragging.emitter.on('dragmove', function (pev) {
var newWidth = dragStartWidth + pev.deltaX * (_this.isRtl ? -1 : 1);
newWidth = Math.max(newWidth, MIN_RESOURCE_AREA_WIDTH);
newWidth = Math.min(newWidth, viewWidth - MIN_RESOURCE_AREA_WIDTH);
_this.setResourceAreaWidth(newWidth);
});
dragging.setAutoScrollEnabled(false); // because gets weird with auto-scrolling time area
return dragging;
});
}
};
ResourceTimelineView.needsResourceData = true; // for ResourceViewProps
return ResourceTimelineView;
}(core.View));
function hasResourceBusinessHours(resourceStore) {
for (var resourceId in resourceStore) {
var resource = resourceStore[resourceId];
if (resource.businessHours) {
return true;
}
}
return false;
}
function hasNesting(nodes) {
for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
var node = nodes_1[_i];
if (node.group) {
return true;
}
else if (node.resource) {
if (node.hasChildren) {
return true;
}
}
}
return false;
}
var main = core.createPlugin({
deps: [ResourceCommonPlugin__default, TimelinePlugin__default],
defaultView: 'resourceTimelineDay',
views: {
resourceTimeline: {
class: ResourceTimelineView,
resourceAreaWidth: '30%',
resourcesInitiallyExpanded: true,
eventResizableFromStart: true // TODO: not DRY with this same setting in the main timeline config
},
resourceTimelineDay: {
type: 'resourceTimeline',
duration: { days: 1 }
},
resourceTimelineWeek: {
type: 'resourceTimeline',
duration: { weeks: 1 }
},
resourceTimelineMonth: {
type: 'resourceTimeline',
duration: { months: 1 }
},
resourceTimelineYear: {
type: 'resourceTimeline',
duration: { years: 1 }
}
}
});
exports.ResourceTimelineView = ResourceTimelineView;
exports.default = main;
Object.defineProperty(exports, '__esModule', { value: true });
}));