12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132 |
- /*!
- FullCalendar Interaction Plugin v4.3.0
- Docs & License: https://fullcalendar.io/
- (c) 2019 Adam Shaw
- */
-
- import { config, elementClosest, EmitterMixin, applyStyle, whenTransitionDone, removeElement, ScrollController, ElementScrollController, computeInnerRect, WindowScrollController, preventSelection, preventContextMenu, allowSelection, allowContextMenu, ElementDragging, computeRect, getClippingParents, pointInsideRect, isDateSpansEqual, constrainPoint, intersectRects, getRectCenter, diffPoints, mapHash, rangeContainsRange, interactionSettingsToStore, Interaction, enableCursor, disableCursor, compareNumbers, getElSeg, getRelevantEvents, EventApi, createEmptyEventStore, applyMutationToEventStore, interactionSettingsStore, startOfDay, diffDates, createDuration, eventTupleToStore, isInteractionValid, parseDragMeta, elementMatches, parseEventDef, createEventInstance, globalDefaults, createPlugin } from '@fullcalendar/core';
-
- /*! *****************************************************************************
- 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);
- };
-
- config.touchMouseIgnoreWait = 500;
- var ignoreMouseDepth = 0;
- var listenerCnt = 0;
- var isWindowTouchMoveCancelled = false;
- /*
- Uses a "pointer" abstraction, which monitors UI events for both mouse and touch.
- Tracks when the pointer "drags" on a certain element, meaning down+move+up.
-
- Also, tracks if there was touch-scrolling.
- Also, can prevent touch-scrolling from happening.
- Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement.
-
- emits:
- - pointerdown
- - pointermove
- - pointerup
- */
- var PointerDragging = /** @class */ (function () {
- function PointerDragging(containerEl) {
- var _this = this;
- this.subjectEl = null;
- this.downEl = null;
- // options that can be directly assigned by caller
- this.selector = ''; // will cause subjectEl in all emitted events to be this element
- this.handleSelector = '';
- this.shouldIgnoreMove = false;
- this.shouldWatchScroll = true; // for simulating pointermove on scroll
- // internal states
- this.isDragging = false;
- this.isTouchDragging = false;
- this.wasTouchScroll = false;
- // Mouse
- // ----------------------------------------------------------------------------------------------------
- this.handleMouseDown = function (ev) {
- if (!_this.shouldIgnoreMouse() &&
- isPrimaryMouseButton(ev) &&
- _this.tryStart(ev)) {
- var pev = _this.createEventFromMouse(ev, true);
- _this.emitter.trigger('pointerdown', pev);
- _this.initScrollWatch(pev);
- if (!_this.shouldIgnoreMove) {
- document.addEventListener('mousemove', _this.handleMouseMove);
- }
- document.addEventListener('mouseup', _this.handleMouseUp);
- }
- };
- this.handleMouseMove = function (ev) {
- var pev = _this.createEventFromMouse(ev);
- _this.recordCoords(pev);
- _this.emitter.trigger('pointermove', pev);
- };
- this.handleMouseUp = function (ev) {
- document.removeEventListener('mousemove', _this.handleMouseMove);
- document.removeEventListener('mouseup', _this.handleMouseUp);
- _this.emitter.trigger('pointerup', _this.createEventFromMouse(ev));
- _this.cleanup(); // call last so that pointerup has access to props
- };
- // Touch
- // ----------------------------------------------------------------------------------------------------
- this.handleTouchStart = function (ev) {
- if (_this.tryStart(ev)) {
- _this.isTouchDragging = true;
- var pev = _this.createEventFromTouch(ev, true);
- _this.emitter.trigger('pointerdown', pev);
- _this.initScrollWatch(pev);
- // unlike mouse, need to attach to target, not document
- // https://stackoverflow.com/a/45760014
- var target = ev.target;
- if (!_this.shouldIgnoreMove) {
- target.addEventListener('touchmove', _this.handleTouchMove);
- }
- target.addEventListener('touchend', _this.handleTouchEnd);
- target.addEventListener('touchcancel', _this.handleTouchEnd); // treat it as a touch end
- // attach a handler to get called when ANY scroll action happens on the page.
- // this was impossible to do with normal on/off because 'scroll' doesn't bubble.
- // http://stackoverflow.com/a/32954565/96342
- window.addEventListener('scroll', _this.handleTouchScroll, true // useCapture
- );
- }
- };
- this.handleTouchMove = function (ev) {
- var pev = _this.createEventFromTouch(ev);
- _this.recordCoords(pev);
- _this.emitter.trigger('pointermove', pev);
- };
- this.handleTouchEnd = function (ev) {
- if (_this.isDragging) { // done to guard against touchend followed by touchcancel
- var target = ev.target;
- target.removeEventListener('touchmove', _this.handleTouchMove);
- target.removeEventListener('touchend', _this.handleTouchEnd);
- target.removeEventListener('touchcancel', _this.handleTouchEnd);
- window.removeEventListener('scroll', _this.handleTouchScroll, true); // useCaptured=true
- _this.emitter.trigger('pointerup', _this.createEventFromTouch(ev));
- _this.cleanup(); // call last so that pointerup has access to props
- _this.isTouchDragging = false;
- startIgnoringMouse();
- }
- };
- this.handleTouchScroll = function () {
- _this.wasTouchScroll = true;
- };
- this.handleScroll = function (ev) {
- if (!_this.shouldIgnoreMove) {
- var pageX = (window.pageXOffset - _this.prevScrollX) + _this.prevPageX;
- var pageY = (window.pageYOffset - _this.prevScrollY) + _this.prevPageY;
- _this.emitter.trigger('pointermove', {
- origEvent: ev,
- isTouch: _this.isTouchDragging,
- subjectEl: _this.subjectEl,
- pageX: pageX,
- pageY: pageY,
- deltaX: pageX - _this.origPageX,
- deltaY: pageY - _this.origPageY
- });
- }
- };
- this.containerEl = containerEl;
- this.emitter = new EmitterMixin();
- containerEl.addEventListener('mousedown', this.handleMouseDown);
- containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true });
- listenerCreated();
- }
- PointerDragging.prototype.destroy = function () {
- this.containerEl.removeEventListener('mousedown', this.handleMouseDown);
- this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
- listenerDestroyed();
- };
- PointerDragging.prototype.tryStart = function (ev) {
- var subjectEl = this.querySubjectEl(ev);
- var downEl = ev.target;
- if (subjectEl &&
- (!this.handleSelector || elementClosest(downEl, this.handleSelector))) {
- this.subjectEl = subjectEl;
- this.downEl = downEl;
- this.isDragging = true; // do this first so cancelTouchScroll will work
- this.wasTouchScroll = false;
- return true;
- }
- return false;
- };
- PointerDragging.prototype.cleanup = function () {
- isWindowTouchMoveCancelled = false;
- this.isDragging = false;
- this.subjectEl = null;
- this.downEl = null;
- // keep wasTouchScroll around for later access
- this.destroyScrollWatch();
- };
- PointerDragging.prototype.querySubjectEl = function (ev) {
- if (this.selector) {
- return elementClosest(ev.target, this.selector);
- }
- else {
- return this.containerEl;
- }
- };
- PointerDragging.prototype.shouldIgnoreMouse = function () {
- return ignoreMouseDepth || this.isTouchDragging;
- };
- // can be called by user of this class, to cancel touch-based scrolling for the current drag
- PointerDragging.prototype.cancelTouchScroll = function () {
- if (this.isDragging) {
- isWindowTouchMoveCancelled = true;
- }
- };
- // Scrolling that simulates pointermoves
- // ----------------------------------------------------------------------------------------------------
- PointerDragging.prototype.initScrollWatch = function (ev) {
- if (this.shouldWatchScroll) {
- this.recordCoords(ev);
- window.addEventListener('scroll', this.handleScroll, true); // useCapture=true
- }
- };
- PointerDragging.prototype.recordCoords = function (ev) {
- if (this.shouldWatchScroll) {
- this.prevPageX = ev.pageX;
- this.prevPageY = ev.pageY;
- this.prevScrollX = window.pageXOffset;
- this.prevScrollY = window.pageYOffset;
- }
- };
- PointerDragging.prototype.destroyScrollWatch = function () {
- if (this.shouldWatchScroll) {
- window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true
- }
- };
- // Event Normalization
- // ----------------------------------------------------------------------------------------------------
- PointerDragging.prototype.createEventFromMouse = function (ev, isFirst) {
- var deltaX = 0;
- var deltaY = 0;
- // TODO: repeat code
- if (isFirst) {
- this.origPageX = ev.pageX;
- this.origPageY = ev.pageY;
- }
- else {
- deltaX = ev.pageX - this.origPageX;
- deltaY = ev.pageY - this.origPageY;
- }
- return {
- origEvent: ev,
- isTouch: false,
- subjectEl: this.subjectEl,
- pageX: ev.pageX,
- pageY: ev.pageY,
- deltaX: deltaX,
- deltaY: deltaY
- };
- };
- PointerDragging.prototype.createEventFromTouch = function (ev, isFirst) {
- var touches = ev.touches;
- var pageX;
- var pageY;
- var deltaX = 0;
- var deltaY = 0;
- // if touch coords available, prefer,
- // because FF would give bad ev.pageX ev.pageY
- if (touches && touches.length) {
- pageX = touches[0].pageX;
- pageY = touches[0].pageY;
- }
- else {
- pageX = ev.pageX;
- pageY = ev.pageY;
- }
- // TODO: repeat code
- if (isFirst) {
- this.origPageX = pageX;
- this.origPageY = pageY;
- }
- else {
- deltaX = pageX - this.origPageX;
- deltaY = pageY - this.origPageY;
- }
- return {
- origEvent: ev,
- isTouch: true,
- subjectEl: this.subjectEl,
- pageX: pageX,
- pageY: pageY,
- deltaX: deltaX,
- deltaY: deltaY
- };
- };
- return PointerDragging;
- }());
- // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
- function isPrimaryMouseButton(ev) {
- return ev.button === 0 && !ev.ctrlKey;
- }
- // Ignoring fake mouse events generated by touch
- // ----------------------------------------------------------------------------------------------------
- function startIgnoringMouse() {
- ignoreMouseDepth++;
- setTimeout(function () {
- ignoreMouseDepth--;
- }, config.touchMouseIgnoreWait);
- }
- // We want to attach touchmove as early as possible for Safari
- // ----------------------------------------------------------------------------------------------------
- function listenerCreated() {
- if (!(listenerCnt++)) {
- window.addEventListener('touchmove', onWindowTouchMove, { passive: false });
- }
- }
- function listenerDestroyed() {
- if (!(--listenerCnt)) {
- window.removeEventListener('touchmove', onWindowTouchMove, { passive: false });
- }
- }
- function onWindowTouchMove(ev) {
- if (isWindowTouchMoveCancelled) {
- ev.preventDefault();
- }
- }
-
- /*
- An effect in which an element follows the movement of a pointer across the screen.
- The moving element is a clone of some other element.
- Must call start + handleMove + stop.
- */
- var ElementMirror = /** @class */ (function () {
- function ElementMirror() {
- this.isVisible = false; // must be explicitly enabled
- this.sourceEl = null;
- this.mirrorEl = null;
- this.sourceElRect = null; // screen coords relative to viewport
- // options that can be set directly by caller
- this.parentNode = document.body;
- this.zIndex = 9999;
- this.revertDuration = 0;
- }
- ElementMirror.prototype.start = function (sourceEl, pageX, pageY) {
- this.sourceEl = sourceEl;
- this.sourceElRect = this.sourceEl.getBoundingClientRect();
- this.origScreenX = pageX - window.pageXOffset;
- this.origScreenY = pageY - window.pageYOffset;
- this.deltaX = 0;
- this.deltaY = 0;
- this.updateElPosition();
- };
- ElementMirror.prototype.handleMove = function (pageX, pageY) {
- this.deltaX = (pageX - window.pageXOffset) - this.origScreenX;
- this.deltaY = (pageY - window.pageYOffset) - this.origScreenY;
- this.updateElPosition();
- };
- // can be called before start
- ElementMirror.prototype.setIsVisible = function (bool) {
- if (bool) {
- if (!this.isVisible) {
- if (this.mirrorEl) {
- this.mirrorEl.style.display = '';
- }
- this.isVisible = bool; // needs to happen before updateElPosition
- this.updateElPosition(); // because was not updating the position while invisible
- }
- }
- else {
- if (this.isVisible) {
- if (this.mirrorEl) {
- this.mirrorEl.style.display = 'none';
- }
- this.isVisible = bool;
- }
- }
- };
- // always async
- ElementMirror.prototype.stop = function (needsRevertAnimation, callback) {
- var _this = this;
- var done = function () {
- _this.cleanup();
- callback();
- };
- if (needsRevertAnimation &&
- this.mirrorEl &&
- this.isVisible &&
- this.revertDuration && // if 0, transition won't work
- (this.deltaX || this.deltaY) // if same coords, transition won't work
- ) {
- this.doRevertAnimation(done, this.revertDuration);
- }
- else {
- setTimeout(done, 0);
- }
- };
- ElementMirror.prototype.doRevertAnimation = function (callback, revertDuration) {
- var mirrorEl = this.mirrorEl;
- var finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened
- mirrorEl.style.transition =
- 'top ' + revertDuration + 'ms,' +
- 'left ' + revertDuration + 'ms';
- applyStyle(mirrorEl, {
- left: finalSourceElRect.left,
- top: finalSourceElRect.top
- });
- whenTransitionDone(mirrorEl, function () {
- mirrorEl.style.transition = '';
- callback();
- });
- };
- ElementMirror.prototype.cleanup = function () {
- if (this.mirrorEl) {
- removeElement(this.mirrorEl);
- this.mirrorEl = null;
- }
- this.sourceEl = null;
- };
- ElementMirror.prototype.updateElPosition = function () {
- if (this.sourceEl && this.isVisible) {
- applyStyle(this.getMirrorEl(), {
- left: this.sourceElRect.left + this.deltaX,
- top: this.sourceElRect.top + this.deltaY
- });
- }
- };
- ElementMirror.prototype.getMirrorEl = function () {
- var sourceElRect = this.sourceElRect;
- var mirrorEl = this.mirrorEl;
- if (!mirrorEl) {
- mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true
- // we don't want long taps or any mouse interaction causing selection/menus.
- // would use preventSelection(), but that prevents selectstart, causing problems.
- mirrorEl.classList.add('fc-unselectable');
- mirrorEl.classList.add('fc-dragging');
- applyStyle(mirrorEl, {
- position: 'fixed',
- zIndex: this.zIndex,
- visibility: '',
- boxSizing: 'border-box',
- width: sourceElRect.right - sourceElRect.left,
- height: sourceElRect.bottom - sourceElRect.top,
- right: 'auto',
- bottom: 'auto',
- margin: 0
- });
- this.parentNode.appendChild(mirrorEl);
- }
- return mirrorEl;
- };
- return ElementMirror;
- }());
-
- /*
- Is a cache for a given element's scroll information (all the info that ScrollController stores)
- in addition the "client rectangle" of the element.. the area within the scrollbars.
-
- The cache can be in one of two modes:
- - doesListening:false - ignores when the container is scrolled by someone else
- - doesListening:true - watch for scrolling and update the cache
- */
- var ScrollGeomCache = /** @class */ (function (_super) {
- __extends(ScrollGeomCache, _super);
- function ScrollGeomCache(scrollController, doesListening) {
- var _this = _super.call(this) || this;
- _this.handleScroll = function () {
- _this.scrollTop = _this.scrollController.getScrollTop();
- _this.scrollLeft = _this.scrollController.getScrollLeft();
- _this.handleScrollChange();
- };
- _this.scrollController = scrollController;
- _this.doesListening = doesListening;
- _this.scrollTop = _this.origScrollTop = scrollController.getScrollTop();
- _this.scrollLeft = _this.origScrollLeft = scrollController.getScrollLeft();
- _this.scrollWidth = scrollController.getScrollWidth();
- _this.scrollHeight = scrollController.getScrollHeight();
- _this.clientWidth = scrollController.getClientWidth();
- _this.clientHeight = scrollController.getClientHeight();
- _this.clientRect = _this.computeClientRect(); // do last in case it needs cached values
- if (_this.doesListening) {
- _this.getEventTarget().addEventListener('scroll', _this.handleScroll);
- }
- return _this;
- }
- ScrollGeomCache.prototype.destroy = function () {
- if (this.doesListening) {
- this.getEventTarget().removeEventListener('scroll', this.handleScroll);
- }
- };
- ScrollGeomCache.prototype.getScrollTop = function () {
- return this.scrollTop;
- };
- ScrollGeomCache.prototype.getScrollLeft = function () {
- return this.scrollLeft;
- };
- ScrollGeomCache.prototype.setScrollTop = function (top) {
- this.scrollController.setScrollTop(top);
- if (!this.doesListening) {
- // we are not relying on the element to normalize out-of-bounds scroll values
- // so we need to sanitize ourselves
- this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0);
- this.handleScrollChange();
- }
- };
- ScrollGeomCache.prototype.setScrollLeft = function (top) {
- this.scrollController.setScrollLeft(top);
- if (!this.doesListening) {
- // we are not relying on the element to normalize out-of-bounds scroll values
- // so we need to sanitize ourselves
- this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0);
- this.handleScrollChange();
- }
- };
- ScrollGeomCache.prototype.getClientWidth = function () {
- return this.clientWidth;
- };
- ScrollGeomCache.prototype.getClientHeight = function () {
- return this.clientHeight;
- };
- ScrollGeomCache.prototype.getScrollWidth = function () {
- return this.scrollWidth;
- };
- ScrollGeomCache.prototype.getScrollHeight = function () {
- return this.scrollHeight;
- };
- ScrollGeomCache.prototype.handleScrollChange = function () {
- };
- return ScrollGeomCache;
- }(ScrollController));
- var ElementScrollGeomCache = /** @class */ (function (_super) {
- __extends(ElementScrollGeomCache, _super);
- function ElementScrollGeomCache(el, doesListening) {
- return _super.call(this, new ElementScrollController(el), doesListening) || this;
- }
- ElementScrollGeomCache.prototype.getEventTarget = function () {
- return this.scrollController.el;
- };
- ElementScrollGeomCache.prototype.computeClientRect = function () {
- return computeInnerRect(this.scrollController.el);
- };
- return ElementScrollGeomCache;
- }(ScrollGeomCache));
- var WindowScrollGeomCache = /** @class */ (function (_super) {
- __extends(WindowScrollGeomCache, _super);
- function WindowScrollGeomCache(doesListening) {
- return _super.call(this, new WindowScrollController(), doesListening) || this;
- }
- WindowScrollGeomCache.prototype.getEventTarget = function () {
- return window;
- };
- WindowScrollGeomCache.prototype.computeClientRect = function () {
- return {
- left: this.scrollLeft,
- right: this.scrollLeft + this.clientWidth,
- top: this.scrollTop,
- bottom: this.scrollTop + this.clientHeight
- };
- };
- // the window is the only scroll object that changes it's rectangle relative
- // to the document's topleft as it scrolls
- WindowScrollGeomCache.prototype.handleScrollChange = function () {
- this.clientRect = this.computeClientRect();
- };
- return WindowScrollGeomCache;
- }(ScrollGeomCache));
-
- // If available we are using native "performance" API instead of "Date"
- // Read more about it on MDN:
- // https://developer.mozilla.org/en-US/docs/Web/API/Performance
- var getTime = typeof performance === 'function' ? performance.now : Date.now;
- /*
- For a pointer interaction, automatically scrolls certain scroll containers when the pointer
- approaches the edge.
-
- The caller must call start + handleMove + stop.
- */
- var AutoScroller = /** @class */ (function () {
- function AutoScroller() {
- var _this = this;
- // options that can be set by caller
- this.isEnabled = true;
- this.scrollQuery = [window, '.fc-scroller'];
- this.edgeThreshold = 50; // pixels
- this.maxVelocity = 300; // pixels per second
- // internal state
- this.pointerScreenX = null;
- this.pointerScreenY = null;
- this.isAnimating = false;
- this.scrollCaches = null;
- // protect against the initial pointerdown being too close to an edge and starting the scroll
- this.everMovedUp = false;
- this.everMovedDown = false;
- this.everMovedLeft = false;
- this.everMovedRight = false;
- this.animate = function () {
- if (_this.isAnimating) { // wasn't cancelled between animation calls
- var edge = _this.computeBestEdge(_this.pointerScreenX + window.pageXOffset, _this.pointerScreenY + window.pageYOffset);
- if (edge) {
- var now = getTime();
- _this.handleSide(edge, (now - _this.msSinceRequest) / 1000);
- _this.requestAnimation(now);
- }
- else {
- _this.isAnimating = false; // will stop animation
- }
- }
- };
- }
- AutoScroller.prototype.start = function (pageX, pageY) {
- if (this.isEnabled) {
- this.scrollCaches = this.buildCaches();
- this.pointerScreenX = null;
- this.pointerScreenY = null;
- this.everMovedUp = false;
- this.everMovedDown = false;
- this.everMovedLeft = false;
- this.everMovedRight = false;
- this.handleMove(pageX, pageY);
- }
- };
- AutoScroller.prototype.handleMove = function (pageX, pageY) {
- if (this.isEnabled) {
- var pointerScreenX = pageX - window.pageXOffset;
- var pointerScreenY = pageY - window.pageYOffset;
- var yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY;
- var xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX;
- if (yDelta < 0) {
- this.everMovedUp = true;
- }
- else if (yDelta > 0) {
- this.everMovedDown = true;
- }
- if (xDelta < 0) {
- this.everMovedLeft = true;
- }
- else if (xDelta > 0) {
- this.everMovedRight = true;
- }
- this.pointerScreenX = pointerScreenX;
- this.pointerScreenY = pointerScreenY;
- if (!this.isAnimating) {
- this.isAnimating = true;
- this.requestAnimation(getTime());
- }
- }
- };
- AutoScroller.prototype.stop = function () {
- if (this.isEnabled) {
- this.isAnimating = false; // will stop animation
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- scrollCache.destroy();
- }
- this.scrollCaches = null;
- }
- };
- AutoScroller.prototype.requestAnimation = function (now) {
- this.msSinceRequest = now;
- requestAnimationFrame(this.animate);
- };
- AutoScroller.prototype.handleSide = function (edge, seconds) {
- var scrollCache = edge.scrollCache;
- var edgeThreshold = this.edgeThreshold;
- var invDistance = edgeThreshold - edge.distance;
- var velocity = // the closer to the edge, the faster we scroll
- (invDistance * invDistance) / (edgeThreshold * edgeThreshold) * // quadratic
- this.maxVelocity * seconds;
- var sign = 1;
- switch (edge.name) {
- case 'left':
- sign = -1;
- // falls through
- case 'right':
- scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign);
- break;
- case 'top':
- sign = -1;
- // falls through
- case 'bottom':
- scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign);
- break;
- }
- };
- // left/top are relative to document topleft
- AutoScroller.prototype.computeBestEdge = function (left, top) {
- var edgeThreshold = this.edgeThreshold;
- var bestSide = null;
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- var rect = scrollCache.clientRect;
- var leftDist = left - rect.left;
- var rightDist = rect.right - left;
- var topDist = top - rect.top;
- var bottomDist = rect.bottom - top;
- // completely within the rect?
- if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) {
- if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() &&
- (!bestSide || bestSide.distance > topDist)) {
- bestSide = { scrollCache: scrollCache, name: 'top', distance: topDist };
- }
- if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() &&
- (!bestSide || bestSide.distance > bottomDist)) {
- bestSide = { scrollCache: scrollCache, name: 'bottom', distance: bottomDist };
- }
- if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() &&
- (!bestSide || bestSide.distance > leftDist)) {
- bestSide = { scrollCache: scrollCache, name: 'left', distance: leftDist };
- }
- if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() &&
- (!bestSide || bestSide.distance > rightDist)) {
- bestSide = { scrollCache: scrollCache, name: 'right', distance: rightDist };
- }
- }
- }
- return bestSide;
- };
- AutoScroller.prototype.buildCaches = function () {
- return this.queryScrollEls().map(function (el) {
- if (el === window) {
- return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls
- }
- else {
- return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls
- }
- });
- };
- AutoScroller.prototype.queryScrollEls = function () {
- var els = [];
- for (var _i = 0, _a = this.scrollQuery; _i < _a.length; _i++) {
- var query = _a[_i];
- if (typeof query === 'object') {
- els.push(query);
- }
- else {
- els.push.apply(els, Array.prototype.slice.call(document.querySelectorAll(query)));
- }
- }
- return els;
- };
- return AutoScroller;
- }());
-
- /*
- Monitors dragging on an element. Has a number of high-level features:
- - minimum distance required before dragging
- - minimum wait time ("delay") before dragging
- - a mirror element that follows the pointer
- */
- var FeaturefulElementDragging = /** @class */ (function (_super) {
- __extends(FeaturefulElementDragging, _super);
- function FeaturefulElementDragging(containerEl) {
- var _this = _super.call(this, containerEl) || this;
- // options that can be directly set by caller
- // the caller can also set the PointerDragging's options as well
- _this.delay = null;
- _this.minDistance = 0;
- _this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag
- _this.mirrorNeedsRevert = false;
- _this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup
- _this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation
- _this.isDelayEnded = false;
- _this.isDistanceSurpassed = false;
- _this.delayTimeoutId = null;
- _this.onPointerDown = function (ev) {
- if (!_this.isDragging) { // so new drag doesn't happen while revert animation is going
- _this.isInteracting = true;
- _this.isDelayEnded = false;
- _this.isDistanceSurpassed = false;
- preventSelection(document.body);
- preventContextMenu(document.body);
- // prevent links from being visited if there's an eventual drag.
- // also prevents selection in older browsers (maybe?).
- // not necessary for touch, besides, browser would complain about passiveness.
- if (!ev.isTouch) {
- ev.origEvent.preventDefault();
- }
- _this.emitter.trigger('pointerdown', ev);
- if (!_this.pointer.shouldIgnoreMove) {
- // actions related to initiating dragstart+dragmove+dragend...
- _this.mirror.setIsVisible(false); // reset. caller must set-visible
- _this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down
- _this.startDelay(ev);
- if (!_this.minDistance) {
- _this.handleDistanceSurpassed(ev);
- }
- }
- }
- };
- _this.onPointerMove = function (ev) {
- if (_this.isInteracting) { // if false, still waiting for previous drag's revert
- _this.emitter.trigger('pointermove', ev);
- if (!_this.isDistanceSurpassed) {
- var minDistance = _this.minDistance;
- var distanceSq = void 0; // current distance from the origin, squared
- var deltaX = ev.deltaX, deltaY = ev.deltaY;
- distanceSq = deltaX * deltaX + deltaY * deltaY;
- if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem
- _this.handleDistanceSurpassed(ev);
- }
- }
- if (_this.isDragging) {
- // a real pointer move? (not one simulated by scrolling)
- if (ev.origEvent.type !== 'scroll') {
- _this.mirror.handleMove(ev.pageX, ev.pageY);
- _this.autoScroller.handleMove(ev.pageX, ev.pageY);
- }
- _this.emitter.trigger('dragmove', ev);
- }
- }
- };
- _this.onPointerUp = function (ev) {
- if (_this.isInteracting) { // if false, still waiting for previous drag's revert
- _this.isInteracting = false;
- allowSelection(document.body);
- allowContextMenu(document.body);
- _this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert
- if (_this.isDragging) {
- _this.autoScroller.stop();
- _this.tryStopDrag(ev); // which will stop the mirror
- }
- if (_this.delayTimeoutId) {
- clearTimeout(_this.delayTimeoutId);
- _this.delayTimeoutId = null;
- }
- }
- };
- var pointer = _this.pointer = new PointerDragging(containerEl);
- pointer.emitter.on('pointerdown', _this.onPointerDown);
- pointer.emitter.on('pointermove', _this.onPointerMove);
- pointer.emitter.on('pointerup', _this.onPointerUp);
- _this.mirror = new ElementMirror();
- _this.autoScroller = new AutoScroller();
- return _this;
- }
- FeaturefulElementDragging.prototype.destroy = function () {
- this.pointer.destroy();
- };
- FeaturefulElementDragging.prototype.startDelay = function (ev) {
- var _this = this;
- if (typeof this.delay === 'number') {
- this.delayTimeoutId = setTimeout(function () {
- _this.delayTimeoutId = null;
- _this.handleDelayEnd(ev);
- }, this.delay); // not assignable to number!
- }
- else {
- this.handleDelayEnd(ev);
- }
- };
- FeaturefulElementDragging.prototype.handleDelayEnd = function (ev) {
- this.isDelayEnded = true;
- this.tryStartDrag(ev);
- };
- FeaturefulElementDragging.prototype.handleDistanceSurpassed = function (ev) {
- this.isDistanceSurpassed = true;
- this.tryStartDrag(ev);
- };
- FeaturefulElementDragging.prototype.tryStartDrag = function (ev) {
- if (this.isDelayEnded && this.isDistanceSurpassed) {
- if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) {
- this.isDragging = true;
- this.mirrorNeedsRevert = false;
- this.autoScroller.start(ev.pageX, ev.pageY);
- this.emitter.trigger('dragstart', ev);
- if (this.touchScrollAllowed === false) {
- this.pointer.cancelTouchScroll();
- }
- }
- }
- };
- FeaturefulElementDragging.prototype.tryStopDrag = function (ev) {
- // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events
- // that come from the document to fire beforehand. much more convenient this way.
- this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev) // bound with args
- );
- };
- FeaturefulElementDragging.prototype.stopDrag = function (ev) {
- this.isDragging = false;
- this.emitter.trigger('dragend', ev);
- };
- // fill in the implementations...
- FeaturefulElementDragging.prototype.setIgnoreMove = function (bool) {
- this.pointer.shouldIgnoreMove = bool;
- };
- FeaturefulElementDragging.prototype.setMirrorIsVisible = function (bool) {
- this.mirror.setIsVisible(bool);
- };
- FeaturefulElementDragging.prototype.setMirrorNeedsRevert = function (bool) {
- this.mirrorNeedsRevert = bool;
- };
- FeaturefulElementDragging.prototype.setAutoScrollEnabled = function (bool) {
- this.autoScroller.isEnabled = bool;
- };
- return FeaturefulElementDragging;
- }(ElementDragging));
-
- /*
- When this class is instantiated, it records the offset of an element (relative to the document topleft),
- and continues to monitor scrolling, updating the cached coordinates if it needs to.
- Does not access the DOM after instantiation, so highly performant.
-
- Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element
- and an determine if a given point is inside the combined clipping rectangle.
- */
- var OffsetTracker = /** @class */ (function () {
- function OffsetTracker(el) {
- this.origRect = computeRect(el);
- // will work fine for divs that have overflow:hidden
- this.scrollCaches = getClippingParents(el).map(function (el) {
- return new ElementScrollGeomCache(el, true); // listen=true
- });
- }
- OffsetTracker.prototype.destroy = function () {
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- scrollCache.destroy();
- }
- };
- OffsetTracker.prototype.computeLeft = function () {
- var left = this.origRect.left;
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- left += scrollCache.origScrollLeft - scrollCache.getScrollLeft();
- }
- return left;
- };
- OffsetTracker.prototype.computeTop = function () {
- var top = this.origRect.top;
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- top += scrollCache.origScrollTop - scrollCache.getScrollTop();
- }
- return top;
- };
- OffsetTracker.prototype.isWithinClipping = function (pageX, pageY) {
- var point = { left: pageX, top: pageY };
- for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) {
- var scrollCache = _a[_i];
- if (!isIgnoredClipping(scrollCache.getEventTarget()) &&
- !pointInsideRect(point, scrollCache.clientRect)) {
- return false;
- }
- }
- return true;
- };
- return OffsetTracker;
- }());
- // certain clipping containers should never constrain interactions, like <html> and <body>
- // https://github.com/fullcalendar/fullcalendar/issues/3615
- function isIgnoredClipping(node) {
- var tagName = node.tagName;
- return tagName === 'HTML' || tagName === 'BODY';
- }
-
- /*
- Tracks movement over multiple droppable areas (aka "hits")
- that exist in one or more DateComponents.
- Relies on an existing draggable.
-
- emits:
- - pointerdown
- - dragstart
- - hitchange - fires initially, even if not over a hit
- - pointerup
- - (hitchange - again, to null, if ended over a hit)
- - dragend
- */
- var HitDragging = /** @class */ (function () {
- function HitDragging(dragging, droppableStore) {
- var _this = this;
- // options that can be set by caller
- this.useSubjectCenter = false;
- this.requireInitial = true; // if doesn't start out on a hit, won't emit any events
- this.initialHit = null;
- this.movingHit = null;
- this.finalHit = null; // won't ever be populated if shouldIgnoreMove
- this.handlePointerDown = function (ev) {
- var dragging = _this.dragging;
- _this.initialHit = null;
- _this.movingHit = null;
- _this.finalHit = null;
- _this.prepareHits();
- _this.processFirstCoord(ev);
- if (_this.initialHit || !_this.requireInitial) {
- dragging.setIgnoreMove(false);
- _this.emitter.trigger('pointerdown', ev); // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :(
- }
- else {
- dragging.setIgnoreMove(true);
- }
- };
- this.handleDragStart = function (ev) {
- _this.emitter.trigger('dragstart', ev);
- _this.handleMove(ev, true); // force = fire even if initially null
- };
- this.handleDragMove = function (ev) {
- _this.emitter.trigger('dragmove', ev);
- _this.handleMove(ev);
- };
- this.handlePointerUp = function (ev) {
- _this.releaseHits();
- _this.emitter.trigger('pointerup', ev);
- };
- this.handleDragEnd = function (ev) {
- if (_this.movingHit) {
- _this.emitter.trigger('hitupdate', null, true, ev);
- }
- _this.finalHit = _this.movingHit;
- _this.movingHit = null;
- _this.emitter.trigger('dragend', ev);
- };
- this.droppableStore = droppableStore;
- dragging.emitter.on('pointerdown', this.handlePointerDown);
- dragging.emitter.on('dragstart', this.handleDragStart);
- dragging.emitter.on('dragmove', this.handleDragMove);
- dragging.emitter.on('pointerup', this.handlePointerUp);
- dragging.emitter.on('dragend', this.handleDragEnd);
- this.dragging = dragging;
- this.emitter = new EmitterMixin();
- }
- // sets initialHit
- // sets coordAdjust
- HitDragging.prototype.processFirstCoord = function (ev) {
- var origPoint = { left: ev.pageX, top: ev.pageY };
- var adjustedPoint = origPoint;
- var subjectEl = ev.subjectEl;
- var subjectRect;
- if (subjectEl !== document) {
- subjectRect = computeRect(subjectEl);
- adjustedPoint = constrainPoint(adjustedPoint, subjectRect);
- }
- var initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top);
- if (initialHit) {
- if (this.useSubjectCenter && subjectRect) {
- var slicedSubjectRect = intersectRects(subjectRect, initialHit.rect);
- if (slicedSubjectRect) {
- adjustedPoint = getRectCenter(slicedSubjectRect);
- }
- }
- this.coordAdjust = diffPoints(adjustedPoint, origPoint);
- }
- else {
- this.coordAdjust = { left: 0, top: 0 };
- }
- };
- HitDragging.prototype.handleMove = function (ev, forceHandle) {
- var hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top);
- if (forceHandle || !isHitsEqual(this.movingHit, hit)) {
- this.movingHit = hit;
- this.emitter.trigger('hitupdate', hit, false, ev);
- }
- };
- HitDragging.prototype.prepareHits = function () {
- this.offsetTrackers = mapHash(this.droppableStore, function (interactionSettings) {
- interactionSettings.component.buildPositionCaches();
- return new OffsetTracker(interactionSettings.el);
- });
- };
- HitDragging.prototype.releaseHits = function () {
- var offsetTrackers = this.offsetTrackers;
- for (var id in offsetTrackers) {
- offsetTrackers[id].destroy();
- }
- this.offsetTrackers = {};
- };
- HitDragging.prototype.queryHitForOffset = function (offsetLeft, offsetTop) {
- var _a = this, droppableStore = _a.droppableStore, offsetTrackers = _a.offsetTrackers;
- var bestHit = null;
- for (var id in droppableStore) {
- var component = droppableStore[id].component;
- var offsetTracker = offsetTrackers[id];
- if (offsetTracker.isWithinClipping(offsetLeft, offsetTop)) {
- var originLeft = offsetTracker.computeLeft();
- var originTop = offsetTracker.computeTop();
- var positionLeft = offsetLeft - originLeft;
- var positionTop = offsetTop - originTop;
- var origRect = offsetTracker.origRect;
- var width = origRect.right - origRect.left;
- var height = origRect.bottom - origRect.top;
- if (
- // must be within the element's bounds
- positionLeft >= 0 && positionLeft < width &&
- positionTop >= 0 && positionTop < height) {
- var hit = component.queryHit(positionLeft, positionTop, width, height);
- if (hit &&
- (
- // make sure the hit is within activeRange, meaning it's not a deal cell
- !component.props.dateProfile || // hack for DayTile
- rangeContainsRange(component.props.dateProfile.activeRange, hit.dateSpan.range)) &&
- (!bestHit || hit.layer > bestHit.layer)) {
- // TODO: better way to re-orient rectangle
- hit.rect.left += originLeft;
- hit.rect.right += originLeft;
- hit.rect.top += originTop;
- hit.rect.bottom += originTop;
- bestHit = hit;
- }
- }
- }
- }
- return bestHit;
- };
- return HitDragging;
- }());
- function isHitsEqual(hit0, hit1) {
- if (!hit0 && !hit1) {
- return true;
- }
- if (Boolean(hit0) !== Boolean(hit1)) {
- return false;
- }
- return isDateSpansEqual(hit0.dateSpan, hit1.dateSpan);
- }
-
- /*
- Monitors when the user clicks on a specific date/time of a component.
- A pointerdown+pointerup on the same "hit" constitutes a click.
- */
- var DateClicking = /** @class */ (function (_super) {
- __extends(DateClicking, _super);
- function DateClicking(settings) {
- var _this = _super.call(this, settings) || this;
- _this.handlePointerDown = function (ev) {
- var dragging = _this.dragging;
- // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired
- dragging.setIgnoreMove(!_this.component.isValidDateDownEl(dragging.pointer.downEl));
- };
- // won't even fire if moving was ignored
- _this.handleDragEnd = function (ev) {
- var component = _this.component;
- var pointer = _this.dragging.pointer;
- if (!pointer.wasTouchScroll) {
- var _a = _this.hitDragging, initialHit = _a.initialHit, finalHit = _a.finalHit;
- if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) {
- component.calendar.triggerDateClick(initialHit.dateSpan, initialHit.dayEl, component.view, ev.origEvent);
- }
- }
- };
- var component = settings.component;
- // we DO want to watch pointer moves because otherwise finalHit won't get populated
- _this.dragging = new FeaturefulElementDragging(component.el);
- _this.dragging.autoScroller.isEnabled = false;
- var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings));
- hitDragging.emitter.on('pointerdown', _this.handlePointerDown);
- hitDragging.emitter.on('dragend', _this.handleDragEnd);
- return _this;
- }
- DateClicking.prototype.destroy = function () {
- this.dragging.destroy();
- };
- return DateClicking;
- }(Interaction));
-
- /*
- Tracks when the user selects a portion of time of a component,
- constituted by a drag over date cells, with a possible delay at the beginning of the drag.
- */
- var DateSelecting = /** @class */ (function (_super) {
- __extends(DateSelecting, _super);
- function DateSelecting(settings) {
- var _this = _super.call(this, settings) || this;
- _this.dragSelection = null;
- _this.handlePointerDown = function (ev) {
- var _a = _this, component = _a.component, dragging = _a.dragging;
- var canSelect = component.opt('selectable') &&
- component.isValidDateDownEl(ev.origEvent.target);
- // don't bother to watch expensive moves if component won't do selection
- dragging.setIgnoreMove(!canSelect);
- // if touch, require user to hold down
- dragging.delay = ev.isTouch ? getComponentTouchDelay(component) : null;
- };
- _this.handleDragStart = function (ev) {
- _this.component.calendar.unselect(ev); // unselect previous selections
- };
- _this.handleHitUpdate = function (hit, isFinal) {
- var calendar = _this.component.calendar;
- var dragSelection = null;
- var isInvalid = false;
- if (hit) {
- dragSelection = joinHitsIntoSelection(_this.hitDragging.initialHit, hit, calendar.pluginSystem.hooks.dateSelectionTransformers);
- if (!dragSelection || !_this.component.isDateSelectionValid(dragSelection)) {
- isInvalid = true;
- dragSelection = null;
- }
- }
- if (dragSelection) {
- calendar.dispatch({ type: 'SELECT_DATES', selection: dragSelection });
- }
- else if (!isFinal) { // only unselect if moved away while dragging
- calendar.dispatch({ type: 'UNSELECT_DATES' });
- }
- if (!isInvalid) {
- enableCursor();
- }
- else {
- disableCursor();
- }
- if (!isFinal) {
- _this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging
- }
- };
- _this.handlePointerUp = function (pev) {
- if (_this.dragSelection) {
- // selection is already rendered, so just need to report selection
- _this.component.calendar.triggerDateSelect(_this.dragSelection, pev);
- _this.dragSelection = null;
- }
- };
- var component = settings.component;
- var dragging = _this.dragging = new FeaturefulElementDragging(component.el);
- dragging.touchScrollAllowed = false;
- dragging.minDistance = component.opt('selectMinDistance') || 0;
- dragging.autoScroller.isEnabled = component.opt('dragScroll');
- var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings));
- hitDragging.emitter.on('pointerdown', _this.handlePointerDown);
- hitDragging.emitter.on('dragstart', _this.handleDragStart);
- hitDragging.emitter.on('hitupdate', _this.handleHitUpdate);
- hitDragging.emitter.on('pointerup', _this.handlePointerUp);
- return _this;
- }
- DateSelecting.prototype.destroy = function () {
- this.dragging.destroy();
- };
- return DateSelecting;
- }(Interaction));
- function getComponentTouchDelay(component) {
- var delay = component.opt('selectLongPressDelay');
- if (delay == null) {
- delay = component.opt('longPressDelay');
- }
- return delay;
- }
- function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) {
- var dateSpan0 = hit0.dateSpan;
- var dateSpan1 = hit1.dateSpan;
- var ms = [
- dateSpan0.range.start,
- dateSpan0.range.end,
- dateSpan1.range.start,
- dateSpan1.range.end
- ];
- ms.sort(compareNumbers);
- var props = {};
- for (var _i = 0, dateSelectionTransformers_1 = dateSelectionTransformers; _i < dateSelectionTransformers_1.length; _i++) {
- var transformer = dateSelectionTransformers_1[_i];
- var res = transformer(hit0, hit1);
- if (res === false) {
- return null;
- }
- else if (res) {
- __assign(props, res);
- }
- }
- props.range = { start: ms[0], end: ms[3] };
- props.allDay = dateSpan0.allDay;
- return props;
- }
-
- var EventDragging = /** @class */ (function (_super) {
- __extends(EventDragging, _super);
- function EventDragging(settings) {
- var _this = _super.call(this, settings) || this;
- // internal state
- _this.subjectSeg = null; // the seg being selected/dragged
- _this.isDragging = false;
- _this.eventRange = null;
- _this.relevantEvents = null; // the events being dragged
- _this.receivingCalendar = null;
- _this.validMutation = null;
- _this.mutatedRelevantEvents = null;
- _this.handlePointerDown = function (ev) {
- var origTarget = ev.origEvent.target;
- var _a = _this, component = _a.component, dragging = _a.dragging;
- var mirror = dragging.mirror;
- var initialCalendar = component.calendar;
- var subjectSeg = _this.subjectSeg = getElSeg(ev.subjectEl);
- var eventRange = _this.eventRange = subjectSeg.eventRange;
- var eventInstanceId = eventRange.instance.instanceId;
- _this.relevantEvents = getRelevantEvents(initialCalendar.state.eventStore, eventInstanceId);
- dragging.minDistance = ev.isTouch ? 0 : component.opt('eventDragMinDistance');
- dragging.delay =
- // only do a touch delay if touch and this event hasn't been selected yet
- (ev.isTouch && eventInstanceId !== component.props.eventSelection) ?
- getComponentTouchDelay$1(component) :
- null;
- mirror.parentNode = initialCalendar.el;
- mirror.revertDuration = component.opt('dragRevertDuration');
- var isValid = component.isValidSegDownEl(origTarget) &&
- !elementClosest(origTarget, '.fc-resizer'); // NOT on a resizer
- dragging.setIgnoreMove(!isValid);
- // disable dragging for elements that are resizable (ie, selectable)
- // but are not draggable
- _this.isDragging = isValid &&
- ev.subjectEl.classList.contains('fc-draggable');
- };
- _this.handleDragStart = function (ev) {
- var initialCalendar = _this.component.calendar;
- var eventRange = _this.eventRange;
- var eventInstanceId = eventRange.instance.instanceId;
- if (ev.isTouch) {
- // need to select a different event?
- if (eventInstanceId !== _this.component.props.eventSelection) {
- initialCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstanceId });
- }
- }
- else {
- // if now using mouse, but was previous touch interaction, clear selected event
- initialCalendar.dispatch({ type: 'UNSELECT_EVENT' });
- }
- if (_this.isDragging) {
- initialCalendar.unselect(ev); // unselect *date* selection
- initialCalendar.publiclyTrigger('eventDragStart', [
- {
- el: _this.subjectSeg.el,
- event: new EventApi(initialCalendar, eventRange.def, eventRange.instance),
- jsEvent: ev.origEvent,
- view: _this.component.view
- }
- ]);
- }
- };
- _this.handleHitUpdate = function (hit, isFinal) {
- if (!_this.isDragging) {
- return;
- }
- var relevantEvents = _this.relevantEvents;
- var initialHit = _this.hitDragging.initialHit;
- var initialCalendar = _this.component.calendar;
- // states based on new hit
- var receivingCalendar = null;
- var mutation = null;
- var mutatedRelevantEvents = null;
- var isInvalid = false;
- var interaction = {
- affectedEvents: relevantEvents,
- mutatedEvents: createEmptyEventStore(),
- isEvent: true,
- origSeg: _this.subjectSeg
- };
- if (hit) {
- var receivingComponent = hit.component;
- receivingCalendar = receivingComponent.calendar;
- if (initialCalendar === receivingCalendar ||
- receivingComponent.opt('editable') && receivingComponent.opt('droppable')) {
- mutation = computeEventMutation(initialHit, hit, receivingCalendar.pluginSystem.hooks.eventDragMutationMassagers);
- if (mutation) {
- mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, receivingCalendar.eventUiBases, mutation, receivingCalendar);
- interaction.mutatedEvents = mutatedRelevantEvents;
- if (!receivingComponent.isInteractionValid(interaction)) {
- isInvalid = true;
- mutation = null;
- mutatedRelevantEvents = null;
- interaction.mutatedEvents = createEmptyEventStore();
- }
- }
- }
- else {
- receivingCalendar = null;
- }
- }
- _this.displayDrag(receivingCalendar, interaction);
- if (!isInvalid) {
- enableCursor();
- }
- else {
- disableCursor();
- }
- if (!isFinal) {
- if (initialCalendar === receivingCalendar && // TODO: write test for this
- isHitsEqual(initialHit, hit)) {
- mutation = null;
- }
- _this.dragging.setMirrorNeedsRevert(!mutation);
- // render the mirror if no already-rendered mirror
- // TODO: wish we could somehow wait for dispatch to guarantee render
- _this.dragging.setMirrorIsVisible(!hit || !document.querySelector('.fc-mirror'));
- // assign states based on new hit
- _this.receivingCalendar = receivingCalendar;
- _this.validMutation = mutation;
- _this.mutatedRelevantEvents = mutatedRelevantEvents;
- }
- };
- _this.handlePointerUp = function () {
- if (!_this.isDragging) {
- _this.cleanup(); // because handleDragEnd won't fire
- }
- };
- _this.handleDragEnd = function (ev) {
- if (_this.isDragging) {
- var initialCalendar_1 = _this.component.calendar;
- var initialView = _this.component.view;
- var _a = _this, receivingCalendar = _a.receivingCalendar, validMutation = _a.validMutation;
- var eventDef = _this.eventRange.def;
- var eventInstance = _this.eventRange.instance;
- var eventApi = new EventApi(initialCalendar_1, eventDef, eventInstance);
- var relevantEvents_1 = _this.relevantEvents;
- var mutatedRelevantEvents = _this.mutatedRelevantEvents;
- var finalHit = _this.hitDragging.finalHit;
- _this.clearDrag(); // must happen after revert animation
- initialCalendar_1.publiclyTrigger('eventDragStop', [
- {
- el: _this.subjectSeg.el,
- event: eventApi,
- jsEvent: ev.origEvent,
- view: initialView
- }
- ]);
- if (validMutation) {
- // dropped within same calendar
- if (receivingCalendar === initialCalendar_1) {
- initialCalendar_1.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: mutatedRelevantEvents
- });
- var transformed = {};
- for (var _i = 0, _b = initialCalendar_1.pluginSystem.hooks.eventDropTransformers; _i < _b.length; _i++) {
- var transformer = _b[_i];
- __assign(transformed, transformer(validMutation, initialCalendar_1));
- }
- var eventDropArg = __assign({}, transformed, { el: ev.subjectEl, delta: validMutation.datesDelta, oldEvent: eventApi, event: new EventApi(// the data AFTER the mutation
- initialCalendar_1, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), revert: function () {
- initialCalendar_1.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: relevantEvents_1
- });
- }, jsEvent: ev.origEvent, view: initialView });
- initialCalendar_1.publiclyTrigger('eventDrop', [eventDropArg]);
- // dropped in different calendar
- }
- else if (receivingCalendar) {
- initialCalendar_1.publiclyTrigger('eventLeave', [
- {
- draggedEl: ev.subjectEl,
- event: eventApi,
- view: initialView
- }
- ]);
- initialCalendar_1.dispatch({
- type: 'REMOVE_EVENT_INSTANCES',
- instances: _this.mutatedRelevantEvents.instances
- });
- receivingCalendar.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: _this.mutatedRelevantEvents
- });
- if (ev.isTouch) {
- receivingCalendar.dispatch({
- type: 'SELECT_EVENT',
- eventInstanceId: eventInstance.instanceId
- });
- }
- var dropArg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.component // should this be finalHit.component.view? See #4644
- });
- receivingCalendar.publiclyTrigger('drop', [dropArg]);
- receivingCalendar.publiclyTrigger('eventReceive', [
- {
- draggedEl: ev.subjectEl,
- event: new EventApi(// the data AFTER the mutation
- receivingCalendar, mutatedRelevantEvents.defs[eventDef.defId], mutatedRelevantEvents.instances[eventInstance.instanceId]),
- view: finalHit.component // should this be finalHit.component.view? See #4644
- }
- ]);
- }
- }
- else {
- initialCalendar_1.publiclyTrigger('_noEventDrop');
- }
- }
- _this.cleanup();
- };
- var component = _this.component;
- var dragging = _this.dragging = new FeaturefulElementDragging(component.el);
- dragging.pointer.selector = EventDragging.SELECTOR;
- dragging.touchScrollAllowed = false;
- dragging.autoScroller.isEnabled = component.opt('dragScroll');
- var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsStore);
- hitDragging.useSubjectCenter = settings.useEventCenter;
- hitDragging.emitter.on('pointerdown', _this.handlePointerDown);
- hitDragging.emitter.on('dragstart', _this.handleDragStart);
- hitDragging.emitter.on('hitupdate', _this.handleHitUpdate);
- hitDragging.emitter.on('pointerup', _this.handlePointerUp);
- hitDragging.emitter.on('dragend', _this.handleDragEnd);
- return _this;
- }
- EventDragging.prototype.destroy = function () {
- this.dragging.destroy();
- };
- // render a drag state on the next receivingCalendar
- EventDragging.prototype.displayDrag = function (nextCalendar, state) {
- var initialCalendar = this.component.calendar;
- var prevCalendar = this.receivingCalendar;
- // does the previous calendar need to be cleared?
- if (prevCalendar && prevCalendar !== nextCalendar) {
- // does the initial calendar need to be cleared?
- // if so, don't clear all the way. we still need to to hide the affectedEvents
- if (prevCalendar === initialCalendar) {
- prevCalendar.dispatch({
- type: 'SET_EVENT_DRAG',
- state: {
- affectedEvents: state.affectedEvents,
- mutatedEvents: createEmptyEventStore(),
- isEvent: true,
- origSeg: state.origSeg
- }
- });
- // completely clear the old calendar if it wasn't the initial
- }
- else {
- prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
- }
- }
- if (nextCalendar) {
- nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state });
- }
- };
- EventDragging.prototype.clearDrag = function () {
- var initialCalendar = this.component.calendar;
- var receivingCalendar = this.receivingCalendar;
- if (receivingCalendar) {
- receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
- }
- // the initial calendar might have an dummy drag state from displayDrag
- if (initialCalendar !== receivingCalendar) {
- initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
- }
- };
- EventDragging.prototype.cleanup = function () {
- this.subjectSeg = null;
- this.isDragging = false;
- this.eventRange = null;
- this.relevantEvents = null;
- this.receivingCalendar = null;
- this.validMutation = null;
- this.mutatedRelevantEvents = null;
- };
- EventDragging.SELECTOR = '.fc-draggable, .fc-resizable'; // TODO: test this in IE11
- return EventDragging;
- }(Interaction));
- function computeEventMutation(hit0, hit1, massagers) {
- var dateSpan0 = hit0.dateSpan;
- var dateSpan1 = hit1.dateSpan;
- var date0 = dateSpan0.range.start;
- var date1 = dateSpan1.range.start;
- var standardProps = {};
- if (dateSpan0.allDay !== dateSpan1.allDay) {
- standardProps.allDay = dateSpan1.allDay;
- standardProps.hasEnd = hit1.component.opt('allDayMaintainDuration');
- if (dateSpan1.allDay) {
- // means date1 is already start-of-day,
- // but date0 needs to be converted
- date0 = startOfDay(date0);
- }
- }
- var delta = diffDates(date0, date1, hit0.component.dateEnv, hit0.component === hit1.component ?
- hit0.component.largeUnit :
- null);
- if (delta.milliseconds) { // has hours/minutes/seconds
- standardProps.allDay = false;
- }
- var mutation = {
- datesDelta: delta,
- standardProps: standardProps
- };
- for (var _i = 0, massagers_1 = massagers; _i < massagers_1.length; _i++) {
- var massager = massagers_1[_i];
- massager(mutation, hit0, hit1);
- }
- return mutation;
- }
- function getComponentTouchDelay$1(component) {
- var delay = component.opt('eventLongPressDelay');
- if (delay == null) {
- delay = component.opt('longPressDelay');
- }
- return delay;
- }
-
- var EventDragging$1 = /** @class */ (function (_super) {
- __extends(EventDragging, _super);
- function EventDragging(settings) {
- var _this = _super.call(this, settings) || this;
- // internal state
- _this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg?
- _this.eventRange = null;
- _this.relevantEvents = null;
- _this.validMutation = null;
- _this.mutatedRelevantEvents = null;
- _this.handlePointerDown = function (ev) {
- var component = _this.component;
- var seg = _this.querySeg(ev);
- var eventRange = _this.eventRange = seg.eventRange;
- _this.dragging.minDistance = component.opt('eventDragMinDistance');
- // if touch, need to be working with a selected event
- _this.dragging.setIgnoreMove(!_this.component.isValidSegDownEl(ev.origEvent.target) ||
- (ev.isTouch && _this.component.props.eventSelection !== eventRange.instance.instanceId));
- };
- _this.handleDragStart = function (ev) {
- var calendar = _this.component.calendar;
- var eventRange = _this.eventRange;
- _this.relevantEvents = getRelevantEvents(calendar.state.eventStore, _this.eventRange.instance.instanceId);
- _this.draggingSeg = _this.querySeg(ev);
- calendar.unselect();
- calendar.publiclyTrigger('eventResizeStart', [
- {
- el: _this.draggingSeg.el,
- event: new EventApi(calendar, eventRange.def, eventRange.instance),
- jsEvent: ev.origEvent,
- view: _this.component.view
- }
- ]);
- };
- _this.handleHitUpdate = function (hit, isFinal, ev) {
- var calendar = _this.component.calendar;
- var relevantEvents = _this.relevantEvents;
- var initialHit = _this.hitDragging.initialHit;
- var eventInstance = _this.eventRange.instance;
- var mutation = null;
- var mutatedRelevantEvents = null;
- var isInvalid = false;
- var interaction = {
- affectedEvents: relevantEvents,
- mutatedEvents: createEmptyEventStore(),
- isEvent: true,
- origSeg: _this.draggingSeg
- };
- if (hit) {
- mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-start-resizer'), eventInstance.range, calendar.pluginSystem.hooks.eventResizeJoinTransforms);
- }
- if (mutation) {
- mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, calendar.eventUiBases, mutation, calendar);
- interaction.mutatedEvents = mutatedRelevantEvents;
- if (!_this.component.isInteractionValid(interaction)) {
- isInvalid = true;
- mutation = null;
- mutatedRelevantEvents = null;
- interaction.mutatedEvents = null;
- }
- }
- if (mutatedRelevantEvents) {
- calendar.dispatch({
- type: 'SET_EVENT_RESIZE',
- state: interaction
- });
- }
- else {
- calendar.dispatch({ type: 'UNSET_EVENT_RESIZE' });
- }
- if (!isInvalid) {
- enableCursor();
- }
- else {
- disableCursor();
- }
- if (!isFinal) {
- if (mutation && isHitsEqual(initialHit, hit)) {
- mutation = null;
- }
- _this.validMutation = mutation;
- _this.mutatedRelevantEvents = mutatedRelevantEvents;
- }
- };
- _this.handleDragEnd = function (ev) {
- var calendar = _this.component.calendar;
- var view = _this.component.view;
- var eventDef = _this.eventRange.def;
- var eventInstance = _this.eventRange.instance;
- var eventApi = new EventApi(calendar, eventDef, eventInstance);
- var relevantEvents = _this.relevantEvents;
- var mutatedRelevantEvents = _this.mutatedRelevantEvents;
- calendar.publiclyTrigger('eventResizeStop', [
- {
- el: _this.draggingSeg.el,
- event: eventApi,
- jsEvent: ev.origEvent,
- view: view
- }
- ]);
- if (_this.validMutation) {
- calendar.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: mutatedRelevantEvents
- });
- calendar.publiclyTrigger('eventResize', [
- {
- el: _this.draggingSeg.el,
- startDelta: _this.validMutation.startDelta || createDuration(0),
- endDelta: _this.validMutation.endDelta || createDuration(0),
- prevEvent: eventApi,
- event: new EventApi(// the data AFTER the mutation
- calendar, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null),
- revert: function () {
- calendar.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: relevantEvents
- });
- },
- jsEvent: ev.origEvent,
- view: view
- }
- ]);
- }
- else {
- calendar.publiclyTrigger('_noEventResize');
- }
- // reset all internal state
- _this.draggingSeg = null;
- _this.relevantEvents = null;
- _this.validMutation = null;
- // okay to keep eventInstance around. useful to set it in handlePointerDown
- };
- var component = settings.component;
- var dragging = _this.dragging = new FeaturefulElementDragging(component.el);
- dragging.pointer.selector = '.fc-resizer';
- dragging.touchScrollAllowed = false;
- dragging.autoScroller.isEnabled = component.opt('dragScroll');
- var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings));
- hitDragging.emitter.on('pointerdown', _this.handlePointerDown);
- hitDragging.emitter.on('dragstart', _this.handleDragStart);
- hitDragging.emitter.on('hitupdate', _this.handleHitUpdate);
- hitDragging.emitter.on('dragend', _this.handleDragEnd);
- return _this;
- }
- EventDragging.prototype.destroy = function () {
- this.dragging.destroy();
- };
- EventDragging.prototype.querySeg = function (ev) {
- return getElSeg(elementClosest(ev.subjectEl, this.component.fgSegSelector));
- };
- return EventDragging;
- }(Interaction));
- function computeMutation(hit0, hit1, isFromStart, instanceRange, transforms) {
- var dateEnv = hit0.component.dateEnv;
- var date0 = hit0.dateSpan.range.start;
- var date1 = hit1.dateSpan.range.start;
- var delta = diffDates(date0, date1, dateEnv, hit0.component.largeUnit);
- var props = {};
- for (var _i = 0, transforms_1 = transforms; _i < transforms_1.length; _i++) {
- var transform = transforms_1[_i];
- var res = transform(hit0, hit1);
- if (res === false) {
- return null;
- }
- else if (res) {
- __assign(props, res);
- }
- }
- if (isFromStart) {
- if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) {
- props.startDelta = delta;
- return props;
- }
- }
- else {
- if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) {
- props.endDelta = delta;
- return props;
- }
- }
- return null;
- }
-
- var UnselectAuto = /** @class */ (function () {
- function UnselectAuto(calendar) {
- var _this = this;
- this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system
- this.onSelect = function (selectInfo) {
- if (selectInfo.jsEvent) {
- _this.isRecentPointerDateSelect = true;
- }
- };
- this.onDocumentPointerUp = function (pev) {
- var _a = _this, calendar = _a.calendar, documentPointer = _a.documentPointer;
- var state = calendar.state;
- // touch-scrolling should never unfocus any type of selection
- if (!documentPointer.wasTouchScroll) {
- if (state.dateSelection && // an existing date selection?
- !_this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp?
- ) {
- var unselectAuto = calendar.viewOpt('unselectAuto');
- var unselectCancel = calendar.viewOpt('unselectCancel');
- if (unselectAuto && (!unselectAuto || !elementClosest(documentPointer.downEl, unselectCancel))) {
- calendar.unselect(pev);
- }
- }
- if (state.eventSelection && // an existing event selected?
- !elementClosest(documentPointer.downEl, EventDragging.SELECTOR) // interaction DIDN'T start on an event
- ) {
- calendar.dispatch({ type: 'UNSELECT_EVENT' });
- }
- }
- _this.isRecentPointerDateSelect = false;
- };
- this.calendar = calendar;
- var documentPointer = this.documentPointer = new PointerDragging(document);
- documentPointer.shouldIgnoreMove = true;
- documentPointer.shouldWatchScroll = false;
- documentPointer.emitter.on('pointerup', this.onDocumentPointerUp);
- /*
- TODO: better way to know about whether there was a selection with the pointer
- */
- calendar.on('select', this.onSelect);
- }
- UnselectAuto.prototype.destroy = function () {
- this.calendar.off('select', this.onSelect);
- this.documentPointer.destroy();
- };
- return UnselectAuto;
- }());
-
- /*
- Given an already instantiated draggable object for one-or-more elements,
- Interprets any dragging as an attempt to drag an events that lives outside
- of a calendar onto a calendar.
- */
- var ExternalElementDragging = /** @class */ (function () {
- function ExternalElementDragging(dragging, suppliedDragMeta) {
- var _this = this;
- this.receivingCalendar = null;
- this.droppableEvent = null; // will exist for all drags, even if create:false
- this.suppliedDragMeta = null;
- this.dragMeta = null;
- this.handleDragStart = function (ev) {
- _this.dragMeta = _this.buildDragMeta(ev.subjectEl);
- };
- this.handleHitUpdate = function (hit, isFinal, ev) {
- var dragging = _this.hitDragging.dragging;
- var receivingCalendar = null;
- var droppableEvent = null;
- var isInvalid = false;
- var interaction = {
- affectedEvents: createEmptyEventStore(),
- mutatedEvents: createEmptyEventStore(),
- isEvent: _this.dragMeta.create,
- origSeg: null
- };
- if (hit) {
- receivingCalendar = hit.component.calendar;
- if (_this.canDropElOnCalendar(ev.subjectEl, receivingCalendar)) {
- droppableEvent = computeEventForDateSpan(hit.dateSpan, _this.dragMeta, receivingCalendar);
- interaction.mutatedEvents = eventTupleToStore(droppableEvent);
- isInvalid = !isInteractionValid(interaction, receivingCalendar);
- if (isInvalid) {
- interaction.mutatedEvents = createEmptyEventStore();
- droppableEvent = null;
- }
- }
- }
- _this.displayDrag(receivingCalendar, interaction);
- // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?)
- // TODO: wish we could somehow wait for dispatch to guarantee render
- dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-mirror'));
- if (!isInvalid) {
- enableCursor();
- }
- else {
- disableCursor();
- }
- if (!isFinal) {
- dragging.setMirrorNeedsRevert(!droppableEvent);
- _this.receivingCalendar = receivingCalendar;
- _this.droppableEvent = droppableEvent;
- }
- };
- this.handleDragEnd = function (pev) {
- var _a = _this, receivingCalendar = _a.receivingCalendar, droppableEvent = _a.droppableEvent;
- _this.clearDrag();
- if (receivingCalendar && droppableEvent) {
- var finalHit = _this.hitDragging.finalHit;
- var finalView = finalHit.component.view;
- var dragMeta = _this.dragMeta;
- var arg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView });
- receivingCalendar.publiclyTrigger('drop', [arg]);
- if (dragMeta.create) {
- receivingCalendar.dispatch({
- type: 'MERGE_EVENTS',
- eventStore: eventTupleToStore(droppableEvent)
- });
- if (pev.isTouch) {
- receivingCalendar.dispatch({
- type: 'SELECT_EVENT',
- eventInstanceId: droppableEvent.instance.instanceId
- });
- }
- // signal that an external event landed
- receivingCalendar.publiclyTrigger('eventReceive', [
- {
- draggedEl: pev.subjectEl,
- event: new EventApi(receivingCalendar, droppableEvent.def, droppableEvent.instance),
- view: finalView
- }
- ]);
- }
- }
- _this.receivingCalendar = null;
- _this.droppableEvent = null;
- };
- var hitDragging = this.hitDragging = new HitDragging(dragging, interactionSettingsStore);
- hitDragging.requireInitial = false; // will start outside of a component
- hitDragging.emitter.on('dragstart', this.handleDragStart);
- hitDragging.emitter.on('hitupdate', this.handleHitUpdate);
- hitDragging.emitter.on('dragend', this.handleDragEnd);
- this.suppliedDragMeta = suppliedDragMeta;
- }
- ExternalElementDragging.prototype.buildDragMeta = function (subjectEl) {
- if (typeof this.suppliedDragMeta === 'object') {
- return parseDragMeta(this.suppliedDragMeta);
- }
- else if (typeof this.suppliedDragMeta === 'function') {
- return parseDragMeta(this.suppliedDragMeta(subjectEl));
- }
- else {
- return getDragMetaFromEl(subjectEl);
- }
- };
- ExternalElementDragging.prototype.displayDrag = function (nextCalendar, state) {
- var prevCalendar = this.receivingCalendar;
- if (prevCalendar && prevCalendar !== nextCalendar) {
- prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
- }
- if (nextCalendar) {
- nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state });
- }
- };
- ExternalElementDragging.prototype.clearDrag = function () {
- if (this.receivingCalendar) {
- this.receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
- }
- };
- ExternalElementDragging.prototype.canDropElOnCalendar = function (el, receivingCalendar) {
- var dropAccept = receivingCalendar.opt('dropAccept');
- if (typeof dropAccept === 'function') {
- return dropAccept(el);
- }
- else if (typeof dropAccept === 'string' && dropAccept) {
- return Boolean(elementMatches(el, dropAccept));
- }
- return true;
- };
- return ExternalElementDragging;
- }());
- // Utils for computing event store from the DragMeta
- // ----------------------------------------------------------------------------------------------------
- function computeEventForDateSpan(dateSpan, dragMeta, calendar) {
- var defProps = __assign({}, dragMeta.leftoverProps);
- for (var _i = 0, _a = calendar.pluginSystem.hooks.externalDefTransforms; _i < _a.length; _i++) {
- var transform = _a[_i];
- __assign(defProps, transform(dateSpan, dragMeta));
- }
- var def = parseEventDef(defProps, dragMeta.sourceId, dateSpan.allDay, calendar.opt('forceEventDuration') || Boolean(dragMeta.duration), // hasEnd
- calendar);
- var start = dateSpan.range.start;
- // only rely on time info if drop zone is all-day,
- // otherwise, we already know the time
- if (dateSpan.allDay && dragMeta.startTime) {
- start = calendar.dateEnv.add(start, dragMeta.startTime);
- }
- var end = dragMeta.duration ?
- calendar.dateEnv.add(start, dragMeta.duration) :
- calendar.getDefaultEventEnd(dateSpan.allDay, start);
- var instance = createEventInstance(def.defId, { start: start, end: end });
- return { def: def, instance: instance };
- }
- // Utils for extracting data from element
- // ----------------------------------------------------------------------------------------------------
- function getDragMetaFromEl(el) {
- var str = getEmbeddedElData(el, 'event');
- var obj = str ?
- JSON.parse(str) :
- { create: false }; // if no embedded data, assume no event creation
- return parseDragMeta(obj);
- }
- config.dataAttrPrefix = '';
- function getEmbeddedElData(el, name) {
- var prefix = config.dataAttrPrefix;
- var prefixedName = (prefix ? prefix + '-' : '') + name;
- return el.getAttribute('data-' + prefixedName) || '';
- }
-
- /*
- Makes an element (that is *external* to any calendar) draggable.
- Can pass in data that determines how an event will be created when dropped onto a calendar.
- Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system.
- */
- var ExternalDraggable = /** @class */ (function () {
- function ExternalDraggable(el, settings) {
- var _this = this;
- if (settings === void 0) { settings = {}; }
- this.handlePointerDown = function (ev) {
- var dragging = _this.dragging;
- var _a = _this.settings, minDistance = _a.minDistance, longPressDelay = _a.longPressDelay;
- dragging.minDistance =
- minDistance != null ?
- minDistance :
- (ev.isTouch ? 0 : globalDefaults.eventDragMinDistance);
- dragging.delay =
- ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv
- (longPressDelay != null ? longPressDelay : globalDefaults.longPressDelay) :
- 0;
- };
- this.handleDragStart = function (ev) {
- if (ev.isTouch &&
- _this.dragging.delay &&
- ev.subjectEl.classList.contains('fc-event')) {
- _this.dragging.mirror.getMirrorEl().classList.add('fc-selected');
- }
- };
- this.settings = settings;
- var dragging = this.dragging = new FeaturefulElementDragging(el);
- dragging.touchScrollAllowed = false;
- if (settings.itemSelector != null) {
- dragging.pointer.selector = settings.itemSelector;
- }
- if (settings.appendTo != null) {
- dragging.mirror.parentNode = settings.appendTo; // TODO: write tests
- }
- dragging.emitter.on('pointerdown', this.handlePointerDown);
- dragging.emitter.on('dragstart', this.handleDragStart);
- new ExternalElementDragging(dragging, settings.eventData);
- }
- ExternalDraggable.prototype.destroy = function () {
- this.dragging.destroy();
- };
- return ExternalDraggable;
- }());
-
- /*
- Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements.
- The third-party system is responsible for drawing the visuals effects of the drag.
- This class simply monitors for pointer movements and fires events.
- It also has the ability to hide the moving element (the "mirror") during the drag.
- */
- var InferredElementDragging = /** @class */ (function (_super) {
- __extends(InferredElementDragging, _super);
- function InferredElementDragging(containerEl) {
- var _this = _super.call(this, containerEl) || this;
- _this.shouldIgnoreMove = false;
- _this.mirrorSelector = '';
- _this.currentMirrorEl = null;
- _this.handlePointerDown = function (ev) {
- _this.emitter.trigger('pointerdown', ev);
- if (!_this.shouldIgnoreMove) {
- // fire dragstart right away. does not support delay or min-distance
- _this.emitter.trigger('dragstart', ev);
- }
- };
- _this.handlePointerMove = function (ev) {
- if (!_this.shouldIgnoreMove) {
- _this.emitter.trigger('dragmove', ev);
- }
- };
- _this.handlePointerUp = function (ev) {
- _this.emitter.trigger('pointerup', ev);
- if (!_this.shouldIgnoreMove) {
- // fire dragend right away. does not support a revert animation
- _this.emitter.trigger('dragend', ev);
- }
- };
- var pointer = _this.pointer = new PointerDragging(containerEl);
- pointer.emitter.on('pointerdown', _this.handlePointerDown);
- pointer.emitter.on('pointermove', _this.handlePointerMove);
- pointer.emitter.on('pointerup', _this.handlePointerUp);
- return _this;
- }
- InferredElementDragging.prototype.destroy = function () {
- this.pointer.destroy();
- };
- InferredElementDragging.prototype.setIgnoreMove = function (bool) {
- this.shouldIgnoreMove = bool;
- };
- InferredElementDragging.prototype.setMirrorIsVisible = function (bool) {
- if (bool) {
- // restore a previously hidden element.
- // use the reference in case the selector class has already been removed.
- if (this.currentMirrorEl) {
- this.currentMirrorEl.style.visibility = '';
- this.currentMirrorEl = null;
- }
- }
- else {
- var mirrorEl = this.mirrorSelector ?
- document.querySelector(this.mirrorSelector) :
- null;
- if (mirrorEl) {
- this.currentMirrorEl = mirrorEl;
- mirrorEl.style.visibility = 'hidden';
- }
- }
- };
- return InferredElementDragging;
- }(ElementDragging));
-
- /*
- Bridges third-party drag-n-drop systems with FullCalendar.
- Must be instantiated and destroyed by caller.
- */
- var ThirdPartyDraggable = /** @class */ (function () {
- function ThirdPartyDraggable(containerOrSettings, settings) {
- var containerEl = document;
- if (
- // wish we could just test instanceof EventTarget, but doesn't work in IE11
- containerOrSettings === document ||
- containerOrSettings instanceof Element) {
- containerEl = containerOrSettings;
- settings = settings || {};
- }
- else {
- settings = (containerOrSettings || {});
- }
- var dragging = this.dragging = new InferredElementDragging(containerEl);
- if (typeof settings.itemSelector === 'string') {
- dragging.pointer.selector = settings.itemSelector;
- }
- else if (containerEl === document) {
- dragging.pointer.selector = '[data-event]';
- }
- if (typeof settings.mirrorSelector === 'string') {
- dragging.mirrorSelector = settings.mirrorSelector;
- }
- new ExternalElementDragging(dragging, settings.eventData);
- }
- ThirdPartyDraggable.prototype.destroy = function () {
- this.dragging.destroy();
- };
- return ThirdPartyDraggable;
- }());
-
- var main = createPlugin({
- componentInteractions: [DateClicking, DateSelecting, EventDragging, EventDragging$1],
- calendarInteractions: [UnselectAuto],
- elementDraggingImpl: FeaturefulElementDragging
- });
-
- export default main;
- export { ExternalDraggable as Draggable, FeaturefulElementDragging, PointerDragging, ThirdPartyDraggable };
|