1/*! 2FullCalendar Interaction Plugin v4.3.0 3Docs & License: https://fullcalendar.io/ 4(c) 2019 Adam Shaw 5*/ 6 7(function (global, factory) { 8 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) : 9 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 10 (global = global || self, factory(global.FullCalendarInteraction = {}, global.FullCalendar)); 11}(this, function (exports, core) { 'use strict'; 12 13 /*! ***************************************************************************** 14 Copyright (c) Microsoft Corporation. All rights reserved. 15 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 16 this file except in compliance with the License. You may obtain a copy of the 17 License at http://www.apache.org/licenses/LICENSE-2.0 18 19 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 21 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 22 MERCHANTABLITY OR NON-INFRINGEMENT. 23 24 See the Apache Version 2.0 License for specific language governing permissions 25 and limitations under the License. 26 ***************************************************************************** */ 27 /* global Reflect, Promise */ 28 29 var extendStatics = function(d, b) { 30 extendStatics = Object.setPrototypeOf || 31 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 32 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 33 return extendStatics(d, b); 34 }; 35 36 function __extends(d, b) { 37 extendStatics(d, b); 38 function __() { this.constructor = d; } 39 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 40 } 41 42 var __assign = function() { 43 __assign = Object.assign || function __assign(t) { 44 for (var s, i = 1, n = arguments.length; i < n; i++) { 45 s = arguments[i]; 46 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 47 } 48 return t; 49 }; 50 return __assign.apply(this, arguments); 51 }; 52 53 core.config.touchMouseIgnoreWait = 500; 54 var ignoreMouseDepth = 0; 55 var listenerCnt = 0; 56 var isWindowTouchMoveCancelled = false; 57 /* 58 Uses a "pointer" abstraction, which monitors UI events for both mouse and touch. 59 Tracks when the pointer "drags" on a certain element, meaning down+move+up. 60 61 Also, tracks if there was touch-scrolling. 62 Also, can prevent touch-scrolling from happening. 63 Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement. 64 65 emits: 66 - pointerdown 67 - pointermove 68 - pointerup 69 */ 70 var PointerDragging = /** @class */ (function () { 71 function PointerDragging(containerEl) { 72 var _this = this; 73 this.subjectEl = null; 74 this.downEl = null; 75 // options that can be directly assigned by caller 76 this.selector = ''; // will cause subjectEl in all emitted events to be this element 77 this.handleSelector = ''; 78 this.shouldIgnoreMove = false; 79 this.shouldWatchScroll = true; // for simulating pointermove on scroll 80 // internal states 81 this.isDragging = false; 82 this.isTouchDragging = false; 83 this.wasTouchScroll = false; 84 // Mouse 85 // ---------------------------------------------------------------------------------------------------- 86 this.handleMouseDown = function (ev) { 87 if (!_this.shouldIgnoreMouse() && 88 isPrimaryMouseButton(ev) && 89 _this.tryStart(ev)) { 90 var pev = _this.createEventFromMouse(ev, true); 91 _this.emitter.trigger('pointerdown', pev); 92 _this.initScrollWatch(pev); 93 if (!_this.shouldIgnoreMove) { 94 document.addEventListener('mousemove', _this.handleMouseMove); 95 } 96 document.addEventListener('mouseup', _this.handleMouseUp); 97 } 98 }; 99 this.handleMouseMove = function (ev) { 100 var pev = _this.createEventFromMouse(ev); 101 _this.recordCoords(pev); 102 _this.emitter.trigger('pointermove', pev); 103 }; 104 this.handleMouseUp = function (ev) { 105 document.removeEventListener('mousemove', _this.handleMouseMove); 106 document.removeEventListener('mouseup', _this.handleMouseUp); 107 _this.emitter.trigger('pointerup', _this.createEventFromMouse(ev)); 108 _this.cleanup(); // call last so that pointerup has access to props 109 }; 110 // Touch 111 // ---------------------------------------------------------------------------------------------------- 112 this.handleTouchStart = function (ev) { 113 if (_this.tryStart(ev)) { 114 _this.isTouchDragging = true; 115 var pev = _this.createEventFromTouch(ev, true); 116 _this.emitter.trigger('pointerdown', pev); 117 _this.initScrollWatch(pev); 118 // unlike mouse, need to attach to target, not document 119 // https://stackoverflow.com/a/45760014 120 var target = ev.target; 121 if (!_this.shouldIgnoreMove) { 122 target.addEventListener('touchmove', _this.handleTouchMove); 123 } 124 target.addEventListener('touchend', _this.handleTouchEnd); 125 target.addEventListener('touchcancel', _this.handleTouchEnd); // treat it as a touch end 126 // attach a handler to get called when ANY scroll action happens on the page. 127 // this was impossible to do with normal on/off because 'scroll' doesn't bubble. 128 // http://stackoverflow.com/a/32954565/96342 129 window.addEventListener('scroll', _this.handleTouchScroll, true // useCapture 130 ); 131 } 132 }; 133 this.handleTouchMove = function (ev) { 134 var pev = _this.createEventFromTouch(ev); 135 _this.recordCoords(pev); 136 _this.emitter.trigger('pointermove', pev); 137 }; 138 this.handleTouchEnd = function (ev) { 139 if (_this.isDragging) { // done to guard against touchend followed by touchcancel 140 var target = ev.target; 141 target.removeEventListener('touchmove', _this.handleTouchMove); 142 target.removeEventListener('touchend', _this.handleTouchEnd); 143 target.removeEventListener('touchcancel', _this.handleTouchEnd); 144 window.removeEventListener('scroll', _this.handleTouchScroll, true); // useCaptured=true 145 _this.emitter.trigger('pointerup', _this.createEventFromTouch(ev)); 146 _this.cleanup(); // call last so that pointerup has access to props 147 _this.isTouchDragging = false; 148 startIgnoringMouse(); 149 } 150 }; 151 this.handleTouchScroll = function () { 152 _this.wasTouchScroll = true; 153 }; 154 this.handleScroll = function (ev) { 155 if (!_this.shouldIgnoreMove) { 156 var pageX = (window.pageXOffset - _this.prevScrollX) + _this.prevPageX; 157 var pageY = (window.pageYOffset - _this.prevScrollY) + _this.prevPageY; 158 _this.emitter.trigger('pointermove', { 159 origEvent: ev, 160 isTouch: _this.isTouchDragging, 161 subjectEl: _this.subjectEl, 162 pageX: pageX, 163 pageY: pageY, 164 deltaX: pageX - _this.origPageX, 165 deltaY: pageY - _this.origPageY 166 }); 167 } 168 }; 169 this.containerEl = containerEl; 170 this.emitter = new core.EmitterMixin(); 171 containerEl.addEventListener('mousedown', this.handleMouseDown);
172 containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true }); 173 listenerCreated(); 174 } 175 PointerDragging.prototype.destroy = function () { 176 this.containerEl.removeEventListener('mousedown', this.handleMouseDown); 177 this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); 178 listenerDestroyed(); 179 }; 180 PointerDragging.prototype.tryStart = function (ev) { 181 var subjectEl = this.querySubjectEl(ev); 182 var downEl = ev.target; 183 if (subjectEl && 184 (!this.handleSelector || core.elementClosest(downEl, this.handleSelector))) { 185 this.subjectEl = subjectEl; 186 this.downEl = downEl; 187 this.isDragging = true; // do this first so cancelTouchScroll will work 188 this.wasTouchScroll = false; 189 return true; 190 } 191 return false; 192 }; 193 PointerDragging.prototype.cleanup = function () { 194 isWindowTouchMoveCancelled = false; 195 this.isDragging = false; 196 this.subjectEl = null; 197 this.downEl = null; 198 // keep wasTouchScroll around for later access 199 this.destroyScrollWatch(); 200 }; 201 PointerDragging.prototype.querySubjectEl = function (ev) { 202 if (this.selector) { 203 return core.elementClosest(ev.target, this.selector); 204 } 205 else { 206 return this.containerEl; 207 } 208 }; 209 PointerDragging.prototype.shouldIgnoreMouse = function () { 210 return ignoreMouseDepth || this.isTouchDragging; 211 }; 212 // can be called by user of this class, to cancel touch-based scrolling for the current drag 213 PointerDragging.prototype.cancelTouchScroll = function () { 214 if (this.isDragging) { 215 isWindowTouchMoveCancelled = true; 216 } 217 }; 218 // Scrolling that simulates pointermoves 219 // ---------------------------------------------------------------------------------------------------- 220 PointerDragging.prototype.initScrollWatch = function (ev) { 221 if (this.shouldWatchScroll) { 222 this.recordCoords(ev); 223 window.addEventListener('scroll', this.handleScroll, true); // useCapture=true 224 } 225 }; 226 PointerDragging.prototype.recordCoords = function (ev) { 227 if (this.shouldWatchScroll) { 228 this.prevPageX = ev.pageX; 229 this.prevPageY = ev.pageY; 230 this.prevScrollX = window.pageXOffset; 231 this.prevScrollY = window.pageYOffset; 232 } 233 }; 234 PointerDragging.prototype.destroyScrollWatch = function () { 235 if (this.shouldWatchScroll) { 236 window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true 237 } 238 }; 239 // Event Normalization 240 // ---------------------------------------------------------------------------------------------------- 241 PointerDragging.prototype.createEventFromMouse = function (ev, isFirst) { 242 var deltaX = 0; 243 var deltaY = 0; 244 // TODO: repeat code 245 if (isFirst) { 246 this.origPageX = ev.pageX; 247 this.origPageY = ev.pageY; 248 } 249 else { 250 deltaX = ev.pageX - this.origPageX; 251 deltaY = ev.pageY - this.origPageY; 252 } 253 return { 254 origEvent: ev, 255 isTouch: false, 256 subjectEl: this.subjectEl, 257 pageX: ev.pageX, 258 pageY: ev.pageY, 259 deltaX: deltaX, 260 deltaY: deltaY 261 }; 262 }; 263 PointerDragging.prototype.createEventFromTouch = function (ev, isFirst) { 264 var touches = ev.touches; 265 var pageX; 266 var pageY; 267 var deltaX = 0; 268 var deltaY = 0; 269 // if touch coords available, prefer, 270 // because FF would give bad ev.pageX ev.pageY 271 if (touches && touches.length) { 272 pageX = touches[0].pageX; 273 pageY = touches[0].pageY; 274 } 275 else { 276 pageX = ev.pageX; 277 pageY = ev.pageY; 278 } 279 // TODO: repeat code 280 if (isFirst) { 281 this.origPageX = pageX; 282 this.origPageY = pageY; 283 } 284 else { 285 deltaX = pageX - this.origPageX; 286 deltaY = pageY - this.origPageY; 287 } 288 return { 289 origEvent: ev, 290 isTouch: true, 291 subjectEl: this.subjectEl, 292 pageX: pageX, 293 pageY: pageY, 294 deltaX: deltaX, 295 deltaY: deltaY 296 }; 297 }; 298 return PointerDragging; 299 }());
300 // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac) 301 function isPrimaryMouseButton(ev) { 302 return ev.button === 0 && !ev.ctrlKey; 303 } 304 // Ignoring fake mouse events generated by touch 305 // ---------------------------------------------------------------------------------------------------- 306 function startIgnoringMouse() { 307 ignoreMouseDepth++; 308 setTimeout(function () { 309 ignoreMouseDepth--; 310 }, core.config.touchMouseIgnoreWait); 311 } 312 // We want to attach touchmove as early as possible for Safari 313 // ---------------------------------------------------------------------------------------------------- 314 function listenerCreated() { 315 if (!(listenerCnt++)) { 316 window.addEventListener('touchmove', onWindowTouchMove, { passive: false }); 317 } 318 } 319 function listenerDestroyed() { 320 if (!(--listenerCnt)) { 321 window.removeEventListener('touchmove', onWindowTouchMove, { passive: false }); 322 } 323 } 324 function onWindowTouchMove(ev) { 325 if (isWindowTouchMoveCancelled) { 326 ev.preventDefault(); 327 } 328 } 329 330 /* 331 An effect in which an element follows the movement of a pointer across the screen. 332 The moving element is a clone of some other element. 333 Must call start + handleMove + stop. 334 */ 335 var ElementMirror = /** @class */ (function () { 336 function ElementMirror() { 337 this.isVisible = false; // must be explicitly enabled 338 this.sourceEl = null; 339 this.mirrorEl = null; 340 this.sourceElRect = null; // screen coords relative to viewport 341 // options that can be set directly by caller 342 this.parentNode = document.body; 343 this.zIndex = 9999; 344 this.revertDuration = 0; 345 } 346 ElementMirror.prototype.start = function (sourceEl, pageX, pageY) { 347 this.sourceEl = sourceEl; 348 this.sourceElRect = this.sourceEl.getBoundingClientRect(); 349 this.origScreenX = pageX - window.pageXOffset; 350 this.origScreenY = pageY - window.pageYOffset; 351 this.deltaX = 0; 352 this.deltaY = 0; 353 this.updateElPosition(); 354 }; 355 ElementMirror.prototype.handleMove = function (pageX, pageY) { 356 this.deltaX = (pageX - window.pageXOffset) - this.origScreenX; 357 this.deltaY = (pageY - window.pageYOffset) - this.origScreenY; 358 this.updateElPosition(); 359 }; 360 // can be called before start 361 ElementMirror.prototype.setIsVisible = function (bool) { 362 if (bool) { 363 if (!this.isVisible) { 364 if (this.mirrorEl) { 365 this.mirrorEl.style.display = ''; 366 } 367 this.isVisible = bool; // needs to happen before updateElPosition 368 this.updateElPosition(); // because was not updating the position while invisible 369 } 370 } 371 else { 372 if (this.isVisible) { 373 if (this.mirrorEl) { 374 this.mirrorEl.style.display = 'none'; 375 } 376 this.isVisible = bool; 377 } 378 } 379 }; 380 // always async 381 ElementMirror.prototype.stop = function (needsRevertAnimation, callback) { 382 var _this = this; 383 var done = function () { 384 _this.cleanup(); 385 callback(); 386 }; 387 if (needsRevertAnimation && 388 this.mirrorEl && 389 this.isVisible && 390 this.revertDuration && // if 0, transition won't work 391 (this.deltaX || this.deltaY) // if same coords, transition won't work 392 ) { 393 this.doRevertAnimation(done, this.revertDuration); 394 } 395 else { 396 setTimeout(done, 0); 397 } 398 }; 399 ElementMirror.prototype.doRevertAnimation = function (callback, revertDuration) { 400 var mirrorEl = this.mirrorEl; 401 var finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened 402 mirrorEl.style.transition = 403 'top ' + revertDuration + 'ms,' + 404 'left ' + revertDuration + 'ms'; 405 core.applyStyle(mirrorEl, { 406 left: finalSourceElRect.left, 407 top: finalSourceElRect.top 408 }); 409 core.whenTransitionDone(mirrorEl, function () { 410 mirrorEl.style.transition = ''; 411 callback(); 412 }); 413 }; 414 ElementMirror.prototype.cleanup = function () { 415 if (this.mirrorEl) { 416 core.removeElement(this.mirrorEl); 417 this.mirrorEl = null; 418 } 419 this.sourceEl = null; 420 }; 421 ElementMirror.prototype.updateElPosition = function () { 422 if (this.sourceEl && this.isVisible) { 423 core.applyStyle(this.getMirrorEl(), { 424 left: this.sourceElRect.left + this.deltaX, 425 top: this.sourceElRect.top + this.deltaY 426 }); 427 } 428 }; 429 ElementMirror.prototype.getMirrorEl = function () { 430 var sourceElRect = this.sourceElRect; 431 var mirrorEl = this.mirrorEl; 432 if (!mirrorEl) { 433 mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true 434 // we don't want long taps or any mouse interaction causing selection/menus. 435 // would use preventSelection(), but that prevents selectstart, causing problems. 436 mirrorEl.classList.add('fc-unselectable'); 437 mirrorEl.classList.add('fc-dragging'); 438 core.applyStyle(mirrorEl, { 439 position: 'fixed', 440 zIndex: this.zIndex, 441 visibility: '', 442 boxSizing: 'border-box', 443 width: sourceElRect.right - sourceElRect.left, 444 height: sourceElRect.bottom - sourceElRect.top, 445 right: 'auto', 446 bottom: 'auto', 447 margin: 0 448 }); 449 this.parentNode.appendChild(mirrorEl); 450 } 451 return mirrorEl; 452 }; 453 return ElementMirror; 454 }()); 455 456 /* 457 Is a cache for a given element's scroll information (all the info that ScrollController stores) 458 in addition the "client rectangle" of the element.. the area within the scrollbars. 459 460 The cache can be in one of two modes: 461 - doesListening:false - ignores when the container is scrolled by someone else 462 - doesListening:true - watch for scrolling and update the cache 463 */ 464 var ScrollGeomCache = /** @class */ (function (_super) { 465 __extends(ScrollGeomCache, _super); 466 function ScrollGeomCache(scrollController, doesListening) { 467 var _this = _super.call(this) || this; 468 _this.handleScroll = function () { 469 _this.scrollTop = _this.scrollController.getScrollTop(); 470 _this.scrollLeft = _this.scrollController.getScrollLeft(); 471 _this.handleScrollChange(); 472 };
473 _this.scrollController = scrollController; 474 _this.doesListening = doesListening; 475 _this.scrollTop = _this.origScrollTop = scrollController.getScrollTop(); 476 _this.scrollLeft = _this.origScrollLeft = scrollController.getScrollLeft(); 477 _this.scrollWidth = scrollController.getScrollWidth(); 478 _this.scrollHeight = scrollController.getScrollHeight(); 479 _this.clientWidth = scrollController.getClientWidth(); 480 _this.clientHeight = scrollController.getClientHeight(); 481 _this.clientRect = _this.computeClientRect(); // do last in case it needs cached values 482 if (_this.doesListening) { 483 _this.getEventTarget().addEventListener('scroll', _this.handleScroll); 484 } 485 return _this; 486 } 487 ScrollGeomCache.prototype.destroy = function () { 488 if (this.doesListening) { 489 this.getEventTarget().removeEventListener('scroll', this.handleScroll); 490 } 491 }; 492 ScrollGeomCache.prototype.getScrollTop = function () { 493 return this.scrollTop; 494 }; 495 ScrollGeomCache.prototype.getScrollLeft = function () { 496 return this.scrollLeft; 497 }; 498 ScrollGeomCache.prototype.setScrollTop = function (top) { 499 this.scrollController.setScrollTop(top); 500 if (!this.doesListening) { 501 // we are not relying on the element to normalize out-of-bounds scroll values 502 // so we need to sanitize ourselves 503 this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0); 504 this.handleScrollChange(); 505 } 506 }; 507 ScrollGeomCache.prototype.setScrollLeft = function (top) { 508 this.scrollController.setScrollLeft(top); 509 if (!this.doesListening) { 510 // we are not relying on the element to normalize out-of-bounds scroll values 511 // so we need to sanitize ourselves 512 this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0); 513 this.handleScrollChange(); 514 } 515 }; 516 ScrollGeomCache.prototype.getClientWidth = function () { 517 return this.clientWidth; 518 }; 519 ScrollGeomCache.prototype.getClientHeight = function () { 520 return this.clientHeight; 521 }; 522 ScrollGeomCache.prototype.getScrollWidth = function () { 523 return this.scrollWidth; 524 }; 525 ScrollGeomCache.prototype.getScrollHeight = function () { 526 return this.scrollHeight; 527 }; 528 ScrollGeomCache.prototype.handleScrollChange = function () { 529 }; 530 return ScrollGeomCache; 531 }(core.ScrollController)); 532 var ElementScrollGeomCache = /** @class */ (function (_super) { 533 __extends(ElementScrollGeomCache, _super); 534 function ElementScrollGeomCache(el, doesListening) { 535 return _super.call(this, new core.ElementScrollController(el), doesListening) || this; 536 } 537 ElementScrollGeomCache.prototype.getEventTarget = function () { 538 return this.scrollController.el; 539 }; 540 ElementScrollGeomCache.prototype.computeClientRect = function () { 541 return core.computeInnerRect(this.scrollController.el); 542 }; 543 return ElementScrollGeomCache; 544 }(ScrollGeomCache)); 545 var WindowScrollGeomCache = /** @class */ (function (_super) { 546 __extends(WindowScrollGeomCache, _super); 547 function WindowScrollGeomCache(doesListening) { 548 return _super.call(this, new core.WindowScrollController(), doesListening) || this; 549 } 550 WindowScrollGeomCache.prototype.getEventTarget = function () { 551 return window; 552 }; 553 WindowScrollGeomCache.prototype.computeClientRect = function () { 554 return { 555 left: this.scrollLeft, 556 right: this.scrollLeft + this.clientWidth, 557 top: this.scrollTop, 558 bottom: this.scrollTop + this.clientHeight 559 }; 560 }; 561 // the window is the only scroll object that changes it's rectangle relative 562 // to the document's topleft as it scrolls 563 WindowScrollGeomCache.prototype.handleScrollChange = function () { 564 this.clientRect = this.computeClientRect(); 565 }; 566 return WindowScrollGeomCache; 567 }(ScrollGeomCache)); 568 569 // If available we are using native "performance" API instead of "Date" 570 // Read more about it on MDN: 571 // https://developer.mozilla.org/en-US/docs/Web/API/Performance 572 var getTime = typeof performance === 'function' ? performance.now : Date.now; 573 /* 574 For a pointer interaction, automatically scrolls certain scroll containers when the pointer 575 approaches the edge. 576 577 The caller must call start + handleMove + stop. 578 */ 579 var AutoScroller = /** @class */ (function () { 580 function AutoScroller() { 581 var _this = this; 582 // options that can be set by caller 583 this.isEnabled = true; 584 this.scrollQuery = [window, '.fc-scroller']; 585 this.edgeThreshold = 50; // pixels 586 this.maxVelocity = 300; // pixels per second 587 // internal state 588 this.pointerScreenX = null; 589 this.pointerScreenY = null; 590 this.isAnimating = false; 591 this.scrollCaches = null; 592 // protect against the initial pointerdown being too close to an edge and starting the scroll 593 this.everMovedUp = false; 594 this.everMovedDown = false; 595 this.everMovedLeft = false; 596 this.everMovedRight = false; 597 this.animate = function () { 598 if (_this.isAnimating) { // wasn't cancelled between animation calls 599 var edge = _this.computeBestEdge(_this.pointerScreenX + window.pageXOffset, _this.pointerScreenY + window.pageYOffset); 600 if (edge) { 601 var now = getTime(); 602 _this.handleSide(edge, (now - _this.msSinceRequest) / 1000); 603 _this.requestAnimation(now); 604 } 605 else { 606 _this.isAnimating = false; // will stop animation 607 } 608 } 609 }; 610 } 611 AutoScroller.prototype.start = function (pageX, pageY) { 612 if (this.isEnabled) { 613 this.scrollCaches = this.buildCaches(); 614 this.pointerScreenX = null; 615 this.pointerScreenY = null; 616 this.everMovedUp = false; 617 this.everMovedDown = false; 618 this.everMovedLeft = false; 619 this.everMovedRight = false; 620 this.handleMove(pageX, pageY); 621 } 622 }; 623 AutoScroller.prototype.handleMove = function (pageX, pageY) { 624 if (this.isEnabled) { 625 var pointerScreenX = pageX - window.pageXOffset; 626 var pointerScreenY = pageY - window.pageYOffset; 627 var yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY; 628 var xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX; 629 if (yDelta < 0) { 630 this.everMovedUp = true; 631 } 632 else if (yDelta > 0) { 633 this.everMovedDown = true; 634 } 635 if (xDelta < 0) { 636 this.everMovedLeft = true; 637 } 638 else if (xDelta > 0) { 639 this.everMovedRight = true; 640 } 641 this.pointerScreenX = pointerScreenX; 642 this.pointerScreenY = pointerScreenY; 643 if (!this.isAnimating) { 644 this.isAnimating = true; 645 this.requestAnimation(getTime()); 646 } 647 } 648 }; 649 AutoScroller.prototype.stop = function () { 650 if (this.isEnabled) { 651 this.isAnimating = false; // will stop animation 652 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 653 var scrollCache = _a[_i]; 654 scrollCache.destroy(); 655 } 656 this.scrollCaches = null; 657 } 658 }; 659 AutoScroller.prototype.requestAnimation = function (now) { 660 this.msSinceRequest = now; 661 requestAnimationFrame(this.animate); 662 }; 663 AutoScroller.prototype.handleSide = function (edge, seconds) { 664 var scrollCache = edge.scrollCache; 665 var edgeThreshold = this.edgeThreshold; 666 var invDistance = edgeThreshold - edge.distance; 667 var velocity = // the closer to the edge, the faster we scroll 668 (invDistance * invDistance) / (edgeThreshold * edgeThreshold) * // quadratic 669 this.maxVelocity * seconds; 670 var sign = 1; 671 switch (edge.name) { 672 case 'left': 673 sign = -1; 674 // falls through 675 case 'right': 676 scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign); 677 break; 678 case 'top': 679 sign = -1; 680 // falls through 681 case 'bottom': 682 scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign); 683 break; 684 } 685 }; 686 // left/top are relative to document topleft 687 AutoScroller.prototype.computeBestEdge = function (left, top) { 688 var edgeThreshold = this.edgeThreshold; 689 var bestSide = null; 690 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 691 var scrollCache = _a[_i]; 692 var rect = scrollCache.clientRect; 693 var leftDist = left - rect.left; 694 var rightDist = rect.right - left; 695 var topDist = top - rect.top; 696 var bottomDist = rect.bottom - top; 697 // completely within the rect? 698 if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) { 699 if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() && 700 (!bestSide || bestSide.distance > topDist)) { 701 bestSide = { scrollCache: scrollCache, name: 'top', distance: topDist }; 702 } 703 if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() && 704 (!bestSide || bestSide.distance > bottomDist)) { 705 bestSide = { scrollCache: scrollCache, name: 'bottom', distance: bottomDist }; 706 } 707 if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() && 708 (!bestSide || bestSide.distance > leftDist)) { 709 bestSide = { scrollCache: scrollCache, name: 'left', distance: leftDist }; 710 } 711 if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() && 712 (!bestSide || bestSide.distance > rightDist)) { 713 bestSide = { scrollCache: scrollCache, name: 'right', distance: rightDist }; 714 } 715 } 716 } 717 return bestSide; 718 }; 719 AutoScroller.prototype.buildCaches = function () { 720 return this.queryScrollEls().map(function (el) { 721 if (el === window) { 722 return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls 723 } 724 else { 725 return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls 726 } 727 }); 728 }; 729 AutoScroller.prototype.queryScrollEls = function () { 730 var els = []; 731 for (var _i = 0, _a = this.scrollQuery; _i < _a.length; _i++) { 732 var query = _a[_i]; 733 if (typeof query === 'object') { 734 els.push(query); 735 } 736 else { 737 els.push.apply(els, Array.prototype.slice.call(document.querySelectorAll(query))); 738 } 739 } 740 return els; 741 }; 742 return AutoScroller; 743 }()); 744 745 /* 746 Monitors dragging on an element. Has a number of high-level features: 747 - minimum distance required before dragging 748 - minimum wait time ("delay") before dragging 749 - a mirror element that follows the pointer 750 */ 751 var FeaturefulElementDragging = /** @class */ (function (_super) { 752 __extends(FeaturefulElementDragging, _super); 753 function FeaturefulElementDragging(containerEl) { 754 var _this = _super.call(this, containerEl) || this; 755 // options that can be directly set by caller 756 // the caller can also set the PointerDragging's options as well 757 _this.delay = null; 758 _this.minDistance = 0; 759 _this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag 760 _this.mirrorNeedsRevert = false; 761 _this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup 762 _this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation 763 _this.isDelayEnded = false; 764 _this.isDistanceSurpassed = false; 765 _this.delayTimeoutId = null; 766 _this.onPointerDown = function (ev) { 767 if (!_this.isDragging) { // so new drag doesn't happen while revert animation is going 768 _this.isInteracting = true; 769 _this.isDelayEnded = false; 770 _this.isDistanceSurpassed = false; 771 core.preventSelection(document.body); 772 core.preventContextMenu(document.body); 773 // prevent links from being visited if there's an eventual drag. 774 // also prevents selection in older browsers (maybe?). 775 // not necessary for touch, besides, browser would complain about passiveness. 776 if (!ev.isTouch) { 777 ev.origEvent.preventDefault(); 778 } 779 _this.emitter.trigger('pointerdown', ev); 780 if (!_this.pointer.shouldIgnoreMove) { 781 // actions related to initiating dragstart+dragmove+dragend... 782 _this.mirror.setIsVisible(false); // reset. caller must set-visible 783 _this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down 784 _this.startDelay(ev); 785 if (!_this.minDistance) { 786 _this.handleDistanceSurpassed(ev); 787 } 788 } 789 } 790 }; 791 _this.onPointerMove = function (ev) { 792 if (_this.isInteracting) { // if false, still waiting for previous drag's revert 793 _this.emitter.trigger('pointermove', ev); 794 if (!_this.isDistanceSurpassed) { 795 var minDistance = _this.minDistance; 796 var distanceSq = void 0; // current distance from the origin, squared 797 var deltaX = ev.deltaX, deltaY = ev.deltaY; 798 distanceSq = deltaX * deltaX + deltaY * deltaY; 799 if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem 800 _this.handleDistanceSurpassed(ev); 801 } 802 } 803 if (_this.isDragging) { 804 // a real po
804inter move? (not one simulated by scrolling) 805 if (ev.origEvent.type !== 'scroll') { 806 _this.mirror.handleMove(ev.pageX, ev.pageY); 807 _this.autoScroller.handleMove(ev.pageX, ev.pageY); 808 } 809 _this.emitter.trigger('dragmove', ev); 810 } 811 } 812 }; 813 _this.onPointerUp = function (ev) { 814 if (_this.isInteracting) { // if false, still waiting for previous drag's revert 815 _this.isInteracting = false; 816 core.allowSelection(document.body); 817 core.allowContextMenu(document.body); 818 _this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert 819 if (_this.isDragging) { 820 _this.autoScroller.stop(); 821 _this.tryStopDrag(ev); // which will stop the mirror 822 } 823 if (_this.delayTimeoutId) { 824 clearTimeout(_this.delayTimeoutId); 825 _this.delayTimeoutId = null; 826 } 827 } 828 }; 829 var pointer = _this.pointer = new PointerDragging(containerEl); 830 pointer.emitter.on('pointerdown', _this.onPointerDown); 831 pointer.emitter.on('pointermove', _this.onPointerMove); 832 pointer.emitter.on('pointerup', _this.onPointerUp); 833 _this.mirror = new ElementMirror(); 834 _this.autoScroller = new AutoScroller(); 835 return _this; 836 } 837 FeaturefulElementDragging.prototype.destroy = function () { 838 this.pointer.destroy(); 839 }; 840 FeaturefulElementDragging.prototype.startDelay = function (ev) { 841 var _this = this; 842 if (typeof this.delay === 'number') { 843 this.delayTimeoutId = setTimeout(function () { 844 _this.delayTimeoutId = null; 845 _this.handleDelayEnd(ev); 846 }, this.delay); // not assignable to number! 847 } 848 else { 849 this.handleDelayEnd(ev); 850 } 851 }; 852 FeaturefulElementDragging.prototype.handleDelayEnd = function (ev) { 853 this.isDelayEnded = true; 854 this.tryStartDrag(ev); 855 }; 856 FeaturefulElementDragging.prototype.handleDistanceSurpassed = function (ev) { 857 this.isDistanceSurpassed = true; 858 this.tryStartDrag(ev); 859 }; 860 FeaturefulElementDragging.prototype.tryStartDrag = function (ev) { 861 if (this.isDelayEnded && this.isDistanceSurpassed) { 862 if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) { 863 this.isDragging = true; 864 this.mirrorNeedsRevert = false; 865 this.autoScroller.start(ev.pageX, ev.pageY); 866 this.emitter.trigger('dragstart', ev); 867 if (this.touchScrollAllowed === false) { 868 this.pointer.cancelTouchScroll(); 869 } 870 } 871 } 872 }; 873 FeaturefulElementDragging.prototype.tryStopDrag = function (ev) { 874 // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events 875 // that come from the document to fire beforehand. much more convenient this way. 876 this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev) // bound with args 877 ); 878 }; 879 FeaturefulElementDragging.prototype.stopDrag = function (ev) { 880 this.isDragging = false; 881 this.emitter.trigger('dragend', ev); 882 }; 883 // fill in the implementations... 884 FeaturefulElementDragging.prototype.setIgnoreMove = function (bool) { 885 this.pointer.shouldIgnoreMove = bool; 886 }; 887 FeaturefulElementDragging.prototype.setMirrorIsVisible = function (bool) { 888 this.mirror.setIsVisible(bool); 889 }; 890 FeaturefulElementDragging.prototype.setMirrorNeedsRevert = function (bool) { 891 this.mirrorNeedsRevert = bool; 892 }; 893 FeaturefulElementDragging.prototype.setAutoScrollEnabled = function (bool) { 894 this.autoScroller.isEnabled = bool; 895 }; 896 return FeaturefulElementDragging; 897 }(core.ElementDragging)); 898 899 /* 900 When this class is instantiated, it records the offset of an element (relative to the document topleft), 901 and continues to monitor scrolling, updating the cached coordinates if it needs to. 902 Does not access the DOM after instantiation, so highly performant. 903 904 Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element 905 and an determine if a given point is inside the combined clipping rectangle. 906 */ 907 var OffsetTracker = /** @class */ (function () { 908 function OffsetTracker(el) { 909 this.origRect = core.computeRect(el); 910 // will work fine for divs that have overflow:hidden 911 this.scrollCaches = core.getClippingParents(el).map(function (el) { 912 return new ElementScrollGeomCache(el, true); // listen=true 913 }); 914 } 915 OffsetTracker.prototype.destroy = function () { 916 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 917 var scrollCache = _a[_i]; 918 scrollCache.destroy(); 919 } 920 }; 921 OffsetTracker.prototype.computeLeft = function () { 922 var left = this.origRect.left; 923 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 924 var scrollCache = _a[_i]; 925 left += scrollCache.origScrollLeft - scrollCache.getScrollLeft(); 926 } 927 return left; 928 }; 929 OffsetTracker.prototype.computeTop = function () { 930 var top = this.origRect.top; 931 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 932 var scrollCache = _a[_i]; 933 top += scrollCache.origScrollTop - scrollCache.getScrollTop(); 934 } 935 return top; 936 }; 937 OffsetTracker.prototype.isWithinClipping = function (pageX, pageY) { 938 var point = { left: pageX, top: pageY }; 939 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 940 var scrollCache = _a[_i];
941 if (!isIgnoredClipping(scrollCache.getEventTarget()) && 942 !core.pointInsideRect(point, scrollCache.clientRect)) { 943 return false; 944 } 945 } 946 return true; 947 }; 948 return OffsetTracker; 949 }()); 950 // certain clipping containers should never constrain interactions, like <html> and <body> 951 // https://github.com/fullcalendar/fullcalendar/issues/3615 952 function isIgnoredClipping(node) { 953 var tagName = node.tagName; 954 return tagName === 'HTML' || tagName === 'BODY'; 955 } 956 957 /* 958 Tracks movement over multiple droppable areas (aka "hits") 959 that exist in one or more DateComponents. 960 Relies on an existing draggable. 961 962 emits: 963 - pointerdown 964 - dragstart 965 - hitchange - fires initially, even if not over a hit 966 - pointerup 967 - (hitchange - again, to null, if ended over a hit) 968 - dragend 969 */ 970 var HitDragging = /** @class */ (function () { 971 function HitDragging(dragging, droppableStore) { 972 var _this = this; 973 // options that can be set by caller 974 this.useSubjectCenter = false; 975 this.requireInitial = true; // if doesn't start out on a hit, won't emit any events 976 this.initialHit = null; 977 this.movingHit = null; 978 this.finalHit = null; // won't ever be populated if shouldIgnoreMove 979 this.handlePointerDown = function (ev) { 980 var dragging = _this.dragging; 981 _this.initialHit = null; 982 _this.movingHit = null; 983 _this.finalHit = null; 984 _this.prepareHits(); 985 _this.processFirstCoord(ev); 986 if (_this.initialHit || !_this.requireInitial) { 987 dragging.setIgnoreMove(false); 988 _this.emitter.trigger('pointerdown', ev); // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :( 989 } 990 else { 991 dragging.setIgnoreMove(true); 992 } 993 }; 994 this.handleDragStart = function (ev) { 995 _this.emitter.trigger('dragstart', ev); 996 _this.handleMove(ev, true); // force = fire even if initially null 997 }; 998 this.handleDragMove = function (ev) { 999 _this.emitter.trigger('dragmove', ev); 1000 _this.handleMove(ev); 1001 }; 1002 this.handlePointerUp = function (ev) { 1003 _this.releaseHits(); 1004 _this.emitter.trigger('pointerup', ev); 1005 }; 1006 this.handleDragEnd = function (ev) { 1007 if (_this.movingHit) { 1008 _this.emitter.trigger('hitupdate', null, true, ev); 1009 } 1010 _this.finalHit = _this.movingHit; 1011 _this.movingHit = null; 1012 _this.emitter.trigger('dragend', ev); 1013 }; 1014 this.droppableStore = droppableStore; 1015 dragging.emitter.on('pointerdown', this.handlePointerDown); 1016 dragging.emitter.on('dragstart', this.handleDragStart); 1017 dragging.emitter.on('dragmove', this.handleDragMove); 1018 dragging.emitter.on('pointerup', this.handlePointerUp); 1019 dragging.emitter.on('dragend', this.handleDragEnd); 1020 this.dragging = dragging; 1021 this.emitter = new core.EmitterMixin(); 1022 } 1023 // sets initialHit 1024 // sets coordAdjust 1025 HitDragging.prototype.processFirstCoord = function (ev) { 1026 var origPoint = { left: ev.pageX, top: ev.pageY }; 1027 var adjustedPoint = origPoint; 1028 var subjectEl = ev.subjectEl; 1029 var subjectRect; 1030 if (subjectEl !== document) { 1031 subjectRect = core.computeRect(subjectEl); 1032 adjustedPoint = core.constrainPoint(adjustedPoint, subjectRect); 1033 } 1034 var initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top); 1035 if (initialHit) { 1036 if (this.useSubjectCenter && subjectRect) { 1037 var slicedSubjectRect = core.intersectRects(subjectRect, initialHit.rect); 1038 if (slicedSubjectRect) { 1039 adjustedPoint = core.getRectCenter(slicedSubjectRect); 1040 } 1041 } 1042 this.coordAdjust = core.diffPoints(adjustedPoint, origPoint); 1043 } 1044 else { 1045 this.coordAdjust = { left: 0, top: 0 }; 1046 } 1047 }; 1048 HitDragging.prototype.handleMove = function (ev, forceHandle) { 1049 var hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top); 1050 if (forceHandle || !isHitsEqual(this.movingHit, hit)) { 1051 this.movingHit = hit; 1052 this.emitter.trigger('hitupdate', hit, false, ev); 1053 } 1054 }; 1055 HitDragging.prototype.prepareHits = function () { 1056 this.offsetTrackers = core.mapHash(this.droppableStore, function (interactionSettings) { 1057 interactionSettings.component.buildPositionCaches(); 1058 return new OffsetTracker(interactionSettings.el); 1059 }); 1060 }; 1061 HitDragging.prototype.releaseHits = function () { 1062 var offsetTrackers = this.offsetTrackers; 1063 for (var id in offsetTrackers) { 1064 offsetTrackers[id].destroy(); 1065 } 1066 this.offsetTrackers = {}; 1067 }; 1068 HitDragging.prototype.queryHitForOffset = function (offsetLeft, offsetTop) { 1069 var _a = this, droppableStore = _a.droppableStore, offsetTrackers = _a.offsetTrackers; 1070 var bestHit = null; 1071 for (var id in droppableStore) { 1072 var component = droppableStore[id].component; 1073 var offsetTracker = offsetTrackers[id]; 1074 if (offsetTracker.isWithinClipping(offsetLeft, offsetTop)) { 1075 var originLeft = offsetTracker.computeLeft(); 1076 var originTop = offsetTracker.computeTop(); 1077 var positionLeft = offsetLeft - originLeft; 1078 var positionTop = offsetTop - originTop; 1079 var origRect = offsetTracker.origRect; 1080 var width = origRect.right - origRect.left; 1081 var height = origRect.bottom - origRect.top; 1082 if ( 1083 // must be within the element's bounds 1084 positionLeft >= 0 && positionLeft < width && 1085 positionTop >= 0 && positionTop < height) { 1086 var hit = component.queryHit(positionLeft, positionTop, width, height); 1087 if (hit && 1088 ( 1089 // make sure the hit is within activeRange, meaning it's not a deal cell 1090 !component.props.dateProfile || // hack for DayTile 1091 core.rangeContainsRange(component.props.dateProfile.activeRange, hit.dateSpan.range)) && 1092 (!bestHit || hit.layer > bestHit.layer)) { 1093 // TODO: better way to re-orient rectangle 1094 hit.rect.left += originLeft; 1095 hit.rect.right += originLeft; 1096 hit.rect.top += originTop; 1097 hit.rect.bottom += originTop; 1098 bestHit = hit; 1099 } 1100 } 1101 } 1102 } 1103 return bestHit; 1104 }; 1105 return HitDragging; 1106 }()); 1107 function isHitsEqual(hit0, hit1) { 1108 if (!hit0 && !hit1) { 1109 return true; 1110 } 1111 if (Boolean(hit0) !== Boolean(hit1)) { 1112 return false; 1113 } 1114 return core.isDateSpansEqual(hit0.dateSpan, hit1.dateSpan); 1115 } 1116 1117 /* 1118 Monitors when the user clicks on a specific date/time of a component. 1119 A pointerdown+pointerup on the same "hit" constitutes a click. 1120 */ 1121 var DateClicking = /** @class */ (function (_super) { 1122 __extends(DateClicking, _super);
1123 function DateClicking(settings) { 1124 var _this = _super.call(this, settings) || this; 1125 _this.handlePointerDown = function (ev) { 1126 var dragging = _this.dragging; 1127 // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired 1128 dragging.setIgnoreMove(!_this.component.isValidDateDownEl(dragging.pointer.downEl)); 1129 }; 1130 // won't even fire if moving was ignored 1131 _this.handleDragEnd = function (ev) { 1132 var component = _this.component; 1133 var pointer = _this.dragging.pointer; 1134 if (!pointer.wasTouchScroll) { 1135 var _a = _this.hitDragging, initialHit = _a.initialHit, finalHit = _a.finalHit; 1136 if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) { 1137 component.calendar.triggerDateClick(initialHit.dateSpan, initialHit.dayEl, component.view, ev.origEvent); 1138 } 1139 } 1140 }; 1141 var component = settings.component; 1142 // we DO want to watch pointer moves because otherwise finalHit won't get populated 1143 _this.dragging = new FeaturefulElementDragging(component.el); 1144 _this.dragging.autoScroller.isEnabled = false; 1145 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 1146 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 1147 hitDragging.emitter.on('dragend', _this.handleDragEnd); 1148 return _this; 1149 } 1150 DateClicking.prototype.destroy = function () { 1151 this.dragging.destroy(); 1152 }; 1153 return DateClicking; 1154 }(core.Interaction)); 1155 1156 /* 1157 Tracks when the user selects a portion of time of a component, 1158 constituted by a drag over date cells, with a possible delay at the beginning of the drag. 1159 */ 1160 var DateSelecting = /** @class */ (function (_super) { 1161 __extends(DateSelecting, _super); 1162 function DateSelecting(settings) { 1163 var _this = _super.call(this, settings) || this; 1164 _this.dragSelection = null; 1165 _this.handlePointerDown = function (ev) { 1166 var _a = _this, component = _a.component, dragging = _a.dragging; 1167 var canSelect = component.opt('selectable') && 1168 component.isValidDateDownEl(ev.origEvent.target); 1169 // don't bother to watch expensive moves if component won't do selection 1170 dragging.setIgnoreMove(!canSelect); 1171 // if touch, require user to hold down 1172 dragging.delay = ev.isTouch ? getComponentTouchDelay(component) : null; 1173 }; 1174 _this.handleDragStart = function (ev) { 1175 _this.component.calendar.unselect(ev); // unselect previous selections 1176 }; 1177 _this.handleHitUpdate = function (hit, isFinal) { 1178 var calendar = _this.component.calendar; 1179 var dragSelection = null; 1180 var isInvalid = false; 1181 if (hit) { 1182 dragSelection = joinHitsIntoSelection(_this.hitDragging.initialHit, hit, calendar.pluginSystem.hooks.dateSelectionTransformers); 1183 if (!dragSelection || !_this.component.isDateSelectionValid(dragSelection)) { 1184 isInvalid = true; 1185 dragSelection = null; 1186 } 1187 } 1188 if (dragSelection) { 1189 calendar.dispatch({ type: 'SELECT_DATES', selection: dragSelection }); 1190 } 1191 else if (!isFinal) { // only unselect if moved away while dragging 1192 calendar.dispatch({ type: 'UNSELECT_DATES' }); 1193 } 1194 if (!isInvalid) { 1195 core.enableCursor(); 1196 } 1197 else { 1198 core.disableCursor(); 1199 } 1200 if (!isFinal) { 1201 _this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging 1202 } 1203 }; 1204 _this.handlePointerUp = function (pev) { 1205 if (_this.dragSelection) { 1206 // selection is already rendered, so just need to report selection 1207 _this.component.calendar.triggerDateSelect(_this.dragSelection, pev); 1208 _this.dragSelection = null; 1209 } 1210 }; 1211 var component = settings.component; 1212 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 1213 dragging.touchScrollAllowed = false; 1214 dragging.minDistance = component.opt('selectMinDistance') || 0; 1215 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 1216 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 1217 hitDragging.emitter.on('pointerdown', _this.handlePointerDown);
1218 hitDragging.emitter.on('dragstart', _this.handleDragStart); 1219 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 1220 hitDragging.emitter.on('pointerup', _this.handlePointerUp); 1221 return _this; 1222 } 1223 DateSelecting.prototype.destroy = function () { 1224 this.dragging.destroy(); 1225 }; 1226 return DateSelecting; 1227 }(core.Interaction)); 1228 function getComponentTouchDelay(component) { 1229 var delay = component.opt('selectLongPressDelay'); 1230 if (delay == null) { 1231 delay = component.opt('longPressDelay'); 1232 } 1233 return delay; 1234 } 1235 function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) { 1236 var dateSpan0 = hit0.dateSpan; 1237 var dateSpan1 = hit1.dateSpan; 1238 var ms = [ 1239 dateSpan0.range.start, 1240 dateSpan0.range.end, 1241 dateSpan1.range.start, 1242 dateSpan1.range.end 1243 ]; 1244 ms.sort(core.compareNumbers); 1245 var props = {}; 1246 for (var _i = 0, dateSelectionTransformers_1 = dateSelectionTransformers; _i < dateSelectionTransformers_1.length; _i++) { 1247 var transformer = dateSelectionTransformers_1[_i]; 1248 var res = transformer(hit0, hit1); 1249 if (res === false) { 1250 return null; 1251 } 1252 else if (res) { 1253 __assign(props, res); 1254 } 1255 } 1256 props.range = { start: ms[0], end: ms[3] }; 1257 props.allDay = dateSpan0.allDay; 1258 return props; 1259 } 1260 1261 var EventDragging = /** @class */ (function (_super) { 1262 __extends(EventDragging, _super); 1263 function EventDragging(settings) { 1264 var _this = _super.call(this, settings) || this; 1265 // internal state 1266 _this.subjectSeg = null; // the seg being selected/dragged 1267 _this.isDragging = false; 1268 _this.eventRange = null; 1269 _this.relevantEvents = null; // the events being dragged 1270 _this.receivingCalendar = null; 1271 _this.validMutation = null; 1272 _this.mutatedRelevantEvents = null; 1273 _this.handlePointerDown = function (ev) { 1274 var origTarget = ev.origEvent.target; 1275 var _a = _this, component = _a.component, dragging = _a.dragging; 1276 var mirror = dragging.mirror; 1277 var initialCalendar = component.calendar; 1278 var subjectSeg = _this.subjectSeg = core.getElSeg(ev.subjectEl); 1279 var eventRange = _this.eventRange = subjectSeg.eventRange; 1280 var eventInstanceId = eventRange.instance.instanceId; 1281 _this.relevantEvents = core.getRelevantEvents(initialCalendar.state.eventStore, eventInstanceId); 1282 dragging.minDistance = ev.isTouch ? 0 : component.opt('eventDragMinDistance'); 1283 dragging.delay = 1284 // only do a touch delay if touch and this event hasn't been selected yet 1285 (ev.isTouch && eventInstanceId !== component.props.eventSelection) ? 1286 getComponentTouchDelay$1(component) : 1287 null; 1288 mirror.parentNode = initialCalendar.el; 1289 mirror.revertDuration = component.opt('dragRevertDuration'); 1290 var isValid = component.isValidSegDownEl(origTarget) && 1291 !core.elementClosest(origTarget, '.fc-resizer'); // NOT on a resizer 1292 dragging.setIgnoreMove(!isValid); 1293 // disable dragging for elements that are resizable (ie, selectable) 1294 // but are not draggable 1295 _this.isDragging = isValid && 1296 ev.subjectEl.classList.contains('fc-draggable'); 1297 }; 1298 _this.handleDragStart = function (ev) { 1299 var initialCalendar = _this.component.calendar; 1300 var eventRange = _this.eventRange; 1301 var eventInstanceId = eventRange.instance.instanceId; 1302 if (ev.isTouch) { 1303 // need to select a different event? 1304 if (eventInstanceId !== _this.component.props.eventSelection) { 1305 initialCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstanceId }); 1306 } 1307 } 1308 else { 1309 // if now using mouse, but was previous touch interaction, clear selected event 1310 initialCalendar.dispatch({ type: 'UNSELECT_EVENT' }); 1311 } 1312 if (_this.isDragging) { 1313 initialCalendar.unselect(ev); // unselect *date* selection 1314 initialCalendar.publiclyTrigger('eventDragStart', [ 1315 { 1316 el: _this.subjectSeg.el, 1317 event: new core.EventApi(initialCalendar, eventRange.def, eventRange.instance), 1318 jsEvent: ev.origEvent, 1319 view: _this.component.view 1320 } 1321 ]); 1322 } 1323 }; 1324 _this.handleHitUpdate = function (hit, isFinal) { 1325 if (!_this.isDragging) { 1326 return; 1327 } 1328 var relevantEvents = _this.relevantEvents; 1329 var initialHit = _this.hitDragging.initialHit; 1330 var initialCalendar = _this.component.calendar; 1331 // states based on new hit 1332 var receivingCalendar = null; 1333 var mutation = null; 1334 var mutatedRelevantEvents = null; 1335 var isInvalid = false; 1336 var interaction = { 1337 affectedEvents: relevantEvents, 1338 mutatedEvents: core.createEmptyEventStore(), 1339 isEvent: true, 1340 origSeg: _this.subjectSeg 1341 }; 1342 if (hit) { 1343 var receivingComponent = hit.component; 1344 receivingCalendar = receivingComponent.calendar; 1345 if (initialCalendar === receivingCalendar || 1346 receivingComponent.opt('editable') && receivingComponent.opt('droppable')) { 1347 mutation = computeEventMutation(initialHit, hit, receivingCalendar.pluginSystem.hooks.eventDragMutationMassagers); 1348 if (mutation) { 1349 mutatedRelevantEvents = core.applyMutationToEventStore(relevantEvents, receivingCalendar.eventUiBases, mutation, receivingCalendar); 1350 interaction.mutatedEvents = mutatedRelevantEvents; 1351 if (!receivingComponent.isInteractionValid(interaction)) { 1352 isInvalid = true; 1353 mutation = null; 1354 mutatedRelevantEvents = null; 1355 interaction.mutatedEvents = core.createEmptyEventStore(); 1356 } 1357 } 1358 } 1359 else { 1360 receivingCalendar = null; 1361 } 1362 } 1363 _this.displayDrag(receivingCalendar, interaction); 1364 if (!isInvalid) {
1365 core.enableCursor(); 1366 } 1367 else { 1368 core.disableCursor(); 1369 } 1370 if (!isFinal) { 1371 if (initialCalendar === receivingCalendar && // TODO: write test for this 1372 isHitsEqual(initialHit, hit)) { 1373 mutation = null; 1374 } 1375 _this.dragging.setMirrorNeedsRevert(!mutation); 1376 // render the mirror if no already-rendered mirror 1377 // TODO: wish we could somehow wait for dispatch to guarantee render 1378 _this.dragging.setMirrorIsVisible(!hit || !document.querySelector('.fc-mirror')); 1379 // assign states based on new hit 1380 _this.receivingCalendar = receivingCalendar; 1381 _this.validMutation = mutation; 1382 _this.mutatedRelevantEvents = mutatedRelevantEvents; 1383 } 1384 }; 1385 _this.handlePointerUp = function () { 1386 if (!_this.isDragging) { 1387 _this.cleanup(); // because handleDragEnd won't fire 1388 } 1389 }; 1390 _this.handleDragEnd = function (ev) { 1391 if (_this.isDragging) { 1392 var initialCalendar_1 = _this.component.calendar; 1393 var initialView = _this.component.view; 1394 var _a = _this, receivingCalendar = _a.receivingCalendar, validMutation = _a.validMutation; 1395 var eventDef = _this.eventRange.def; 1396 var eventInstance = _this.eventRange.instance; 1397 var eventApi = new core.EventApi(initialCalendar_1, eventDef, eventInstance); 1398 var relevantEvents_1 = _this.relevantEvents; 1399 var mutatedRelevantEvents = _this.mutatedRelevantEvents; 1400 var finalHit = _this.hitDragging.finalHit; 1401 _this.clearDrag(); // must happen after revert animation 1402 initialCalendar_1.publiclyTrigger('eventDragStop', [ 1403 { 1404 el: _this.subjectSeg.el, 1405 event: eventApi, 1406 jsEvent: ev.origEvent, 1407 view: initialView 1408 } 1409 ]); 1410 if (validMutation) { 1411 // dropped within same calendar 1412 if (receivingCalendar === initialCalendar_1) { 1413 initialCalendar_1.dispatch({ 1414 type: 'MERGE_EVENTS', 1415 eventStore: mutatedRelevantEvents 1416 }); 1417 var transformed = {}; 1418 for (var _i = 0, _b = initialCalendar_1.pluginSystem.hooks.eventDropTransformers; _i < _b.length; _i++) { 1419 var transformer = _b[_i]; 1420 __assign(transformed, transformer(validMutation, initialCalendar_1)); 1421 } 1422 var eventDropArg = __assign({}, transformed, { el: ev.subjectEl, delta: validMutation.datesDelta, oldEvent: eventApi, event: new core.EventApi(// the data AFTER the mutation 1423 initialCalendar_1, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), revert: function () { 1424 initialCalendar_1.dispatch({ 1425 type: 'MERGE_EVENTS', 1426 eventStore: relevantEvents_1 1427 }); 1428 }, jsEvent: ev.origEvent, view: initialView }); 1429 initialCalendar_1.publiclyTrigger('eventDrop', [eventDropArg]); 1430 // dropped in different calendar 1431 } 1432 else if (receivingCalendar) { 1433 initialCalendar_1.publiclyTrigger('eventLeave', [ 1434 { 1435 draggedEl: ev.subjectEl, 1436 event: eventApi, 1437 view: initialView 1438 } 1439 ]); 1440 initialCalendar_1.dispatch({
1441 type: 'REMOVE_EVENT_INSTANCES', 1442 instances: _this.mutatedRelevantEvents.instances 1443 }); 1444 receivingCalendar.dispatch({ 1445 type: 'MERGE_EVENTS', 1446 eventStore: _this.mutatedRelevantEvents 1447 }); 1448 if (ev.isTouch) { 1449 receivingCalendar.dispatch({ 1450 type: 'SELECT_EVENT', 1451 eventInstanceId: eventInstance.instanceId 1452 }); 1453 } 1454 var dropArg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.component // should this be finalHit.component.view? See #4644 1455 }); 1456 receivingCalendar.publiclyTrigger('drop', [dropArg]); 1457 receivingCalendar.publiclyTrigger('eventReceive', [ 1458 { 1459 draggedEl: ev.subjectEl, 1460 event: new core.EventApi(// the data AFTER the mutation 1461 receivingCalendar, mutatedRelevantEvents.defs[eventDef.defId], mutatedRelevantEvents.instances[eventInstance.instanceId]), 1462 view: finalHit.component // should this be finalHit.component.view? See #4644 1463 } 1464 ]); 1465 } 1466 } 1467 else { 1468 initialCalendar_1.publiclyTrigger('_noEventDrop'); 1469 } 1470 } 1471 _this.cleanup(); 1472 }; 1473 var component = _this.component; 1474 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 1475 dragging.pointer.selector = EventDragging.SELECTOR; 1476 dragging.touchScrollAllowed = false; 1477 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 1478 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsStore); 1479 hitDragging.useSubjectCenter = settings.useEventCenter; 1480 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 1481 hitDragging.emitter.on('dragstart', _this.handleDragStart); 1482 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 1483 hitDragging.emitter.on('pointerup', _this.handlePointerUp); 1484 hitDragging.emitter.on('dragend', _this.handleDragEnd); 1485 return _this; 1486 } 1487 EventDragging.prototype.destroy = function () { 1488 this.dragging.destroy(); 1489 }; 1490 // render a drag state on the next receivingCalendar 1491 EventDragging.prototype.displayDrag = function (nextCalendar, state) { 1492 var initialCalendar = this.component.calendar; 1493 var prevCalendar = this.receivingCalendar; 1494 // does the previous calendar need to be cleared? 1495 if (prevCalendar && prevCalendar !== nextCalendar) { 1496 // does the initial calendar need to be cleared? 1497 // if so, don't clear all the way. we still need to to hide the affectedEvents 1498 if (prevCalendar === initialCalendar) { 1499 prevCalendar.dispatch({ 1500 type: 'SET_EVENT_DRAG', 1501 state: { 1502 affectedEvents: state.affectedEvents, 1503 mutatedEvents: core.createEmptyEventStore(), 1504 isEvent: true, 1505 origSeg: state.origSeg 1506 } 1507 }); 1508 // completely clear the old calendar if it wasn't the initial 1509 } 1510 else { 1511 prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 1512 } 1513 } 1514 if (nextCalendar) { 1515 nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); 1516 } 1517 }; 1518 EventDragging.prototype.clearDrag = function () { 1519 var initialCalendar = this.component.calendar; 1520 var receivingCalendar = this.receivingCalendar; 1521 if (receivingCalendar) { 1522 receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 1523 } 1524 // the initial calendar might have an dummy drag state from displayDrag 1525 if (initialCalendar !== receivingCalendar) { 1526 initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 1527 } 1528 }; 1529 EventDragging.prototype.cleanup = function () { 1530 this.subjectSeg = null; 1531 this.isDragging = false; 1532 this.eventRange = null; 1533 this.relevantEvents = null; 1534 this.receivingCalendar = null; 1535 this.validMutation = null; 1536 this.mutatedRelevantEvents = null; 1537 }; 1538 EventDragging.SELECTOR = '.fc-draggable, .fc-resizable'; // TODO: test this in IE11 1539 return EventDragging; 1540 }(core.Interaction)); 1541 function computeEventMutation(hit0, hit1, massagers) { 1542 var dateSpan0 = hit0.dateSpan; 1543 var dateSpan1 = hit1.dateSpan; 1544 var date0 = dateSpan0.range.start; 1545 var date1 = dateSpan1.range.start; 1546 var standardProps = {}; 1547 if (dateSpan0.allDay !== dateSpan1.allDay) { 1548 standardProps.allDay = dateSpan1.allDay; 1549 standardProps.hasEnd = hit1.component.opt('allDayMaintainDuration'); 1550 if (dateSpan1.allDay) { 1551 // means date1 is already start-of-day, 1552 // but date0 needs to be converted 1553 date0 = core.startOfDay(date0); 1554 } 1555 } 1556 var delta = core.diffDates(date0, date1, hit0.component.dateEnv, hit0.component === hit1.component ? 1557 hit0.component.largeUnit : 1558 null); 1559 if (delta.milliseconds) { // has hours/minutes/seconds 1560 standardProps.allDay = false; 1561 } 1562 var mutation = { 1563 datesDelta: delta, 1564 standardProps: standardProps 1565 }; 1566 for (var _i = 0, massagers_1 = massagers; _i < massagers_1.length; _i++) { 1567 var massager = massagers_1[_i]; 1568 massager(mutation, hit0, hit1); 1569 } 1570 return mutation; 1571 } 1572 function getComponentTouchDelay$1(component) {
1573 var delay = component.opt('eventLongPressDelay'); 1574 if (delay == null) { 1575 delay = component.opt('longPressDelay'); 1576 } 1577 return delay; 1578 } 1579 1580 var EventDragging$1 = /** @class */ (function (_super) { 1581 __extends(EventDragging, _super); 1582 function EventDragging(settings) { 1583 var _this = _super.call(this, settings) || this; 1584 // internal state 1585 _this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg? 1586 _this.eventRange = null; 1587 _this.relevantEvents = null; 1588 _this.validMutation = null; 1589 _this.mutatedRelevantEvents = null; 1590 _this.handlePointerDown = function (ev) { 1591 var component = _this.component; 1592 var seg = _this.querySeg(ev); 1593 var eventRange = _this.eventRange = seg.eventRange; 1594 _this.dragging.minDistance = component.opt('eventDragMinDistance'); 1595 // if touch, need to be working with a selected event 1596 _this.dragging.setIgnoreMove(!_this.component.isValidSegDownEl(ev.origEvent.target) || 1597 (ev.isTouch && _this.component.props.eventSelection !== eventRange.instance.instanceId)); 1598 }; 1599 _this.handleDragStart = function (ev) { 1600 var calendar = _this.component.calendar; 1601 var eventRange = _this.eventRange; 1602 _this.relevantEvents = core.getRelevantEvents(calendar.state.eventStore, _this.eventRange.instance.instanceId); 1603 _this.draggingSeg = _this.querySeg(ev); 1604 calendar.unselect(); 1605 calendar.publiclyTrigger('eventResizeStart', [ 1606 { 1607 el: _this.draggingSeg.el, 1608 event: new core.EventApi(calendar, eventRange.def, eventRange.instance), 1609 jsEvent: ev.origEvent, 1610 view: _this.component.view 1611 } 1612 ]); 1613 }; 1614 _this.handleHitUpdate = function (hit, isFinal, ev) { 1615 var calendar = _this.component.calendar; 1616 var relevantEvents = _this.relevantEvents; 1617 var initialHit = _this.hitDragging.initialHit; 1618 var eventInstance = _this.eventRange.instance; 1619 var mutation = null; 1620 var mutatedRelevantEvents = null; 1621 var isInvalid = false; 1622 var interaction = { 1623 affectedEvents: relevantEvents, 1624 mutatedEvents: core.createEmptyEventStore(), 1625 isEvent: true, 1626 origSeg: _this.draggingSeg 1627 }; 1628 if (hit) { 1629 mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-start-resizer'), eventInstance.range, calendar.pluginSystem.hooks.eventResizeJoinTransforms); 1630 } 1631 if (mutation) { 1632 mutatedRelevantEvents = core.applyMutationToEventStore(relevantEvents, calendar.eventUiBases, mutation, calendar); 1633 interaction.mutatedEvents = mutatedRelevantEvents; 1634 if (!_this.component.isInteractionValid(interaction)) { 1635 isInvalid = true; 1636 mutation = null; 1637 mutatedRelevantEvents = null; 1638 interaction.mutatedEvents = null; 1639 } 1640 } 1641 if (mutatedRelevantEvents) { 1642 calendar.dispatch({ 1643 type: 'SET_EVENT_RESIZE', 1644 state: interaction 1645 }); 1646 } 1647 else { 1648 calendar.dispatch({ type: 'UNSET_EVENT_RESIZE' }); 1649 } 1650 if (!isInvalid) { 1651 core.enableCursor(); 1652 } 1653 else { 1654 core.disableCursor(); 1655 } 1656 if (!isFinal) { 1657 if (mutation && isHitsEqual(initialHit, hit)) { 1658 mutation = null; 1659 } 1660 _this.validMutation = mutation; 1661 _this.mutatedRelevantEvents = mutatedRelevantEvents; 1662 } 1663 }; 1664 _this.handleDragEnd = function (ev) { 1665 var calendar = _this.component.calendar; 1666 var view = _this.component.view; 1667 var eventDef = _this.eventRange.def; 1668 var eventInstance = _this.eventRange.instance; 1669 var eventApi = new core.EventApi(calendar, eventDef, eventInstance); 1670 var relevantEvents = _this.relevantEvents; 1671 var mutatedRelevantEvents = _this.mutatedRelevantEvents; 1672 calendar.publiclyTrigger('eventResizeStop', [ 1673 { 1674 el: _this.draggingSeg.el, 1675 event: eventApi, 1676 jsEvent: ev.origEvent, 1677 view: view 1678 } 1679 ]); 1680 if (_this.validMutation) { 1681 calendar.dispatch({ 1682 type: 'MERGE_EVENTS', 1683 eventStore: mutatedRelevantEvents 1684 }); 1685 calendar.publiclyTrigger('eventResize', [ 1686 { 1687 el: _this.draggingSeg.el, 1688 startDelta: _this.validMutation.startDelta || core.createDuration(0), 1689 endDelta: _this.validMutation.endDelta || core.createDuration(0), 1690 prevEvent: eventApi, 1691 event: new core.EventApi(// the data AFT
1691ER the mutation 1692 calendar, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), 1693 revert: function () { 1694 calendar.dispatch({ 1695 type: 'MERGE_EVENTS', 1696 eventStore: relevantEvents 1697 }); 1698 }, 1699 jsEvent: ev.origEvent, 1700 view: view 1701 } 1702 ]); 1703 } 1704 else { 1705 calendar.publiclyTrigger('_noEventResize'); 1706 } 1707 // reset all internal state 1708 _this.draggingSeg = null; 1709 _this.relevantEvents = null; 1710 _this.validMutation = null; 1711 // okay to keep eventInstance around. useful to set it in handlePointerDown 1712 }; 1713 var component = settings.component; 1714 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 1715 dragging.pointer.selector = '.fc-resizer'; 1716 dragging.touchScrollAllowed = false; 1717 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 1718 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 1719 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 1720 hitDragging.emitter.on('dragstart', _this.handleDragStart); 1721 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 1722 hitDragging.emitter.on('dragend', _this.handleDragEnd); 1723 return _this; 1724 } 1725 EventDragging.prototype.destroy = function () { 1726 this.dragging.destroy(); 1727 }; 1728 EventDragging.prototype.querySeg = function (ev) { 1729 return core.getElSeg(core.elementClosest(ev.subjectEl, this.component.fgSegSelector)); 1730 }; 1731 return EventDragging; 1732 }(core.Interaction)); 1733 function computeMutation(hit0, hit1, isFromStart, instanceRange, transforms) { 1734 var dateEnv = hit0.component.dateEnv; 1735 var date0 = hit0.dateSpan.range.start; 1736 var date1 = hit1.dateSpan.range.start; 1737 var delta = core.diffDates(date0, date1, dateEnv, hit0.component.largeUnit); 1738 var props = {}; 1739 for (var _i = 0, transforms_1 = transforms; _i < transforms_1.length; _i++) { 1740 var transform = transforms_1[_i]; 1741 var res = transform(hit0, hit1); 1742 if (res === false) { 1743 return null; 1744 } 1745 else if (res) { 1746 __assign(props, res); 1747 } 1748 } 1749 if (isFromStart) { 1750 if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) { 1751 props.startDelta = delta; 1752 return props; 1753 } 1754 } 1755 else { 1756 if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) { 1757 props.endDelta = delta; 1758 return props; 1759 } 1760 } 1761 return null; 1762 } 1763 1764 var UnselectAuto = /** @class */ (function () { 1765 function UnselectAuto(calendar) { 1766 var _this = this; 1767 this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system 1768 this.onSelect = function (selectInfo) { 1769 if (selectInfo.jsEvent) { 1770 _this.isRecentPointerDateSelect = true; 1771 } 1772 }; 1773 this.onDocumentPointerUp = function (pev) { 1774 var _a = _this, calendar = _a.calendar, documentPointer = _a.documentPointer; 1775 var state = calendar.state; 1776 // touch-scrolling should never unfocus any type of selection 1777 if (!documentPointer.wasTouchScroll) { 1778 if (state.dateSelection && // an existing date selection? 1779 !_this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp? 1780 ) { 1781 var unselectAuto = calendar.viewOpt('unselectAuto'); 1782 var unselectCancel = calendar.viewOpt('unselectCancel'); 1783 if (unselectAuto && (!unselectAuto || !core.elementClosest(documentPointer.downEl, unselectCancel))) { 1784 calendar.unselect(pev); 1785 } 1786 } 1787 if (state.eventSelection && // an existing event selected? 1788 !core.elementClosest(documentPointer.downEl, EventDragging.SELECTOR) // interaction DIDN'T start on an event 1789 ) { 1790 calendar.dispatch({ type: 'UNSELECT_EVENT' }); 1791 } 1792 } 1793 _this.isRecentPointerDateSelect = false; 1794 }; 1795 this.calendar = calendar; 1796 var documentPointer = this.documentPointer = new PointerDragging(document); 1797 documentPointer.shouldIgnoreMove = true; 1798 documentPointer.shouldWatchScroll = false; 1799 documentPointer.emitter.on('pointerup', this.onDocumentPointerUp); 1800 /* 1801 TODO: better way to know about whether there was a selection with the pointer 1802 */ 1803 calendar.on('select', this.onSelect); 1804 } 1805 UnselectAuto.prototype.destroy = function () { 1806 this.calendar.off('select', this.onSelect); 1807 this.documentPointer.destroy(); 1808 }; 1809 return UnselectAuto; 1810 }()); 1811 1812 /* 1813 Given an already instantiated draggable object for one-or-more elements, 1814 Interprets any dragging as an attempt to drag an events that lives outside 1815 of a calendar onto a calendar. 1816 */
1817 var ExternalElementDragging = /** @class */ (function () { 1818 function ExternalElementDragging(dragging, suppliedDragMeta) { 1819 var _this = this; 1820 this.receivingCalendar = null; 1821 this.droppableEvent = null; // will exist for all drags, even if create:false 1822 this.suppliedDragMeta = null; 1823 this.dragMeta = null; 1824 this.handleDragStart = function (ev) { 1825 _this.dragMeta = _this.buildDragMeta(ev.subjectEl); 1826 }; 1827 this.handleHitUpdate = function (hit, isFinal, ev) { 1828 var dragging = _this.hitDragging.dragging; 1829 var receivingCalendar = null; 1830 var droppableEvent = null; 1831 var isInvalid = false; 1832 var interaction = { 1833 affectedEvents: core.createEmptyEventStore(), 1834 mutatedEvents: core.createEmptyEventStore(), 1835 isEvent: _this.dragMeta.create, 1836 origSeg: null 1837 }; 1838 if (hit) { 1839 receivingCalendar = hit.component.calendar; 1840 if (_this.canDropElOnCalendar(ev.subjectEl, receivingCalendar)) { 1841 droppableEvent = computeEventForDateSpan(hit.dateSpan, _this.dragMeta, receivingCalendar); 1842 interaction.mutatedEvents = core.eventTupleToStore(droppableEvent); 1843 isInvalid = !core.isInteractionValid(interaction, receivingCalendar); 1844 if (isInvalid) { 1845 interaction.mutatedEvents = core.createEmptyEventStore(); 1846 droppableEvent = null; 1847 } 1848 } 1849 } 1850 _this.displayDrag(receivingCalendar, interaction); 1851 // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?) 1852 // TODO: wish we could somehow wait for dispatch to guarantee render 1853 dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-mirror')); 1854 if (!isInvalid) { 1855 core.enableCursor(); 1856 } 1857 else { 1858 core.disableCursor(); 1859 } 1860 if (!isFinal) { 1861 dragging.setMirrorNeedsRevert(!droppableEvent); 1862 _this.receivingCalendar = receivingCalendar; 1863 _this.droppableEvent = droppableEvent; 1864 } 1865 }; 1866 this.handleDragEnd = function (pev) { 1867 var _a = _this, receivingCalendar = _a.receivingCalendar, droppableEvent = _a.droppableEvent; 1868 _this.clearDrag(); 1869 if (receivingCalendar && droppableEvent) { 1870 var finalHit = _this.hitDragging.finalHit; 1871 var finalView = finalHit.component.view; 1872 var dragMeta = _this.dragMeta; 1873 var arg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView }); 1874 receivingCalendar.publiclyTrigger('drop', [arg]); 1875 if (dragMeta.create) { 1876 receivingCalendar.dispatch({ 1877 type: 'MERGE_EVENTS', 1878 eventStore: core.eventTupleToStore(droppableEvent) 1879 }); 1880 if (pev.isTouch) { 1881 receivingCalendar.dispatch({ 1882 type: 'SELECT_EVENT', 1883 eventInstanceId: droppableEvent.instance.instanceId 1884 }); 1885 } 1886 // signal that an external event landed 1887 receivingCalendar.publiclyTrigger('eventReceive', [ 1888 { 1889 draggedEl: pev.subjectEl, 1890 event: new core.EventApi(receivingCalendar, droppableEvent.def, droppableEvent.instance), 1891 view: finalView 1892 } 1893 ]); 1894 } 1895 } 1896 _this.receivingCalendar = null; 1897 _this.droppableEvent = null; 1898 }; 1899 var hitDragging = this.hitDragging = new HitDragging(dragging, core.interactionSettingsStore); 1900 hitDragging.requireInitial = false; // will start outside of a component 1901 hitDragging.emitter.on('dragstart', this.handleDragStart); 1902 hitDragging.emitter.on('hitupdate', this.handleHitUpdate); 1903 hitDragging.emitter.on('dragend', this.handleDragEnd); 1904 this.suppliedDragMeta = suppliedDragMeta; 1905 } 1906 ExternalElementDragging.prototype.buildDragMeta = function (sub
1906jectEl) { 1907 if (typeof this.suppliedDragMeta === 'object') { 1908 return core.parseDragMeta(this.suppliedDragMeta); 1909 } 1910 else if (typeof this.suppliedDragMeta === 'function') { 1911 return core.parseDragMeta(this.suppliedDragMeta(subjectEl)); 1912 } 1913 else { 1914 return getDragMetaFromEl(subjectEl); 1915 } 1916 }; 1917 ExternalElementDragging.prototype.displayDrag = function (nextCalendar, state) { 1918 var prevCalendar = this.receivingCalendar; 1919 if (prevCalendar && prevCalendar !== nextCalendar) { 1920 prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 1921 } 1922 if (nextCalendar) { 1923 nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); 1924 } 1925 }; 1926 ExternalElementDragging.prototype.clearDrag = function () { 1927 if (this.receivingCalendar) { 1928 this.receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 1929 } 1930 }; 1931 ExternalElementDragging.prototype.canDropElOnCalendar = function (el, receivingCalendar) { 1932 var dropAccept = receivingCalendar.opt('dropAccept'); 1933 if (typeof dropAccept === 'function') { 1934 return dropAccept(el); 1935 } 1936 else if (typeof dropAccept === 'string' && dropAccept) { 1937 return Boolean(core.elementMatches(el, dropAccept)); 1938 } 1939 return true; 1940 }; 1941 return ExternalElementDragging; 1942 }()); 1943 // Utils for computing event store from the DragMeta 1944 // ---------------------------------------------------------------------------------------------------- 1945 function computeEventForDateSpan(dateSpan, dragMeta, calendar) { 1946 var defProps = __assign({}, dragMeta.leftoverProps); 1947 for (var _i = 0, _a = calendar.pluginSystem.hooks.externalDefTransforms; _i < _a.length; _i++) { 1948 var transform = _a[_i]; 1949 __assign(defProps, transform(dateSpan, dragMeta)); 1950 } 1951 var def = core.parseEventDef(defProps, dragMeta.sourceId, dateSpan.allDay, calendar.opt('forceEventDuration') || Boolean(dragMeta.duration), // hasEnd 1952 calendar); 1953 var start = dateSpan.range.start; 1954 // only rely on time info if drop zone is all-day, 1955 // otherwise, we already know the time 1956 if (dateSpan.allDay && dragMeta.startTime) { 1957 start = calendar.dateEnv.add(start, dragMeta.startTime); 1958 } 1959 var end = dragMeta.duration ? 1960 calendar.dateEnv.add(start, dragMeta.duration) : 1961 calendar.getDefaultEventEnd(dateSpan.allDay, start); 1962 var instance = core.createEventInstance(def.defId, { start: start, end: end }); 1963 return { def: def, instance: instance }; 1964 } 1965 // Utils for extracting data from element 1966 // ---------------------------------------------------------------------------------------------------- 1967 function getDragMetaFromEl(el) { 1968 var str = getEmbeddedElData(el, 'event'); 1969 var obj = str ? 1970 JSON.parse(str) : 1971 { create: false }; // if no embedded data, assume no event creation 1972 return core.parseDragMeta(obj); 1973 } 1974 core.config.dataAttrPrefix = ''; 1975 function getEmbeddedElData(el, name) { 1976 var prefix = core.config.dataAttrPrefix; 1977 var prefixedName = (prefix ? prefix + '-' : '') + name; 1978 return el.getAttribute('data-' + prefixedName) || ''; 1979 } 1980 1981 /* 1982 Makes an element (that is *external* to any calendar) draggable. 1983 Can pass in data that determines how an event will be created when dropped onto a calendar. 1984 Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system. 1985 */ 1986 var ExternalDraggable = /** @class */ (function () { 1987 function ExternalDraggable(el, settings) { 1988 var _this = this; 1989 if (settings === void 0) { settings = {}; } 1990 this.handlePointerDown = function (ev) { 1991 var dragging = _this.dragging; 1992 var _a = _this.settings, minDistance = _a.minDistance, longPressDelay = _a.longPressDelay; 1993 dragging.minDistance = 1994 minDistance != null ? 1995 minDistance : 1996 (ev.isTouch ? 0 : core.globalDefaults.eventDragMinDistance); 1997 dragging.delay = 1998 ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv 1999 (longPressDelay != null ? longPressDelay : core.globalDefaults.longPressDelay) : 2000 0; 2001 }; 2002 this.handleDragStart = function (ev) { 2003 if (ev.isTouch && 2004 _this.dragging.delay && 2005 ev.subjectEl.classList.contains('fc-event')) { 2006 _this.dragging.mirror.getMirrorEl().classList.add('fc-selected'); 2007 } 2008 }; 2009 this.settings = settings; 2010 var dragging = this.dragging = new FeaturefulElementDragging(el); 2011 dragging.touchScrollAllowed = false; 2012 if (settings.itemSelector != null) { 2013 dragging.pointer.selector = settings.itemSelector; 2014 } 2015 if (settings.appendTo != null) { 2016 dragging.mirror.parentNode = settings.appendTo; // TODO: write tests 2017 } 2018 dragging.emitter.on('pointerdown', this.handlePointerDown);
2019 dragging.emitter.on('dragstart', this.handleDragStart); 2020 new ExternalElementDragging(dragging, settings.eventData); 2021 } 2022 ExternalDraggable.prototype.destroy = function () { 2023 this.dragging.destroy(); 2024 }; 2025 return ExternalDraggable; 2026 }()); 2027 2028 /* 2029 Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements. 2030 The third-party system is responsible for drawing the visuals effects of the drag. 2031 This class simply monitors for pointer movements and fires events. 2032 It also has the ability to hide the moving element (the "mirror") during the drag. 2033 */ 2034 var InferredElementDragging = /** @class */ (function (_super) { 2035 __extends(InferredElementDragging, _super); 2036 function InferredElementDragging(containerEl) { 2037 var _this = _super.call(this, containerEl) || this; 2038 _this.shouldIgnoreMove = false; 2039 _this.mirrorSelector = ''; 2040 _this.currentMirrorEl = null; 2041 _this.handlePointerDown = function (ev) { 2042 _this.emitter.trigger('pointerdown', ev); 2043 if (!_this.shouldIgnoreMove) { 2044 // fire dragstart right away. does not support delay or min-distance 2045 _this.emitter.trigger('dragstart', ev); 2046 } 2047 }; 2048 _this.handlePointerMove = function (ev) { 2049 if (!_this.shouldIgnoreMove) { 2050 _this.emitter.trigger('dragmove', ev); 2051 } 2052 }; 2053 _this.handlePointerUp = function (ev) { 2054 _this.emitter.trigger('pointerup', ev); 2055 if (!_this.shouldIgnoreMove) { 2056 // fire dragend right away. does not support a revert animation 2057 _this.emitter.trigger('dragend', ev); 2058 } 2059 }; 2060 var pointer = _this.pointer = new PointerDragging(containerEl); 2061 pointer.emitter.on('pointerdown', _this.handlePointerDown); 2062 pointer.emitter.on('pointermove', _this.handlePointerMove); 2063 pointer.emitter.on('pointerup', _this.handlePointerUp); 2064 return _this; 2065 } 2066 InferredElementDragging.prototype.destroy = function () { 2067 this.pointer.destroy(); 2068 }; 2069 InferredElementDragging.prototype.setIgnoreMove = function (bool) { 2070 this.shouldIgnoreMove = bool; 2071 }; 2072 InferredElementDragging.prototype.setMirrorIsVisible = function (bool) { 2073 if (bool) { 2074 // restore a previously hidden element. 2075 // use the reference in case the selector class has already been removed. 2076 if (this.currentMirrorEl) { 2077 this.currentMirrorEl.style.visibility = ''; 2078 this.currentMirrorEl = null; 2079 } 2080 } 2081 else { 2082 var mirrorEl = this.mirrorSelector ? 2083 document.querySelector(this.mirrorSelector) : 2084 null; 2085 if (mirrorEl) { 2086 this.currentMirrorEl = mirrorEl; 2087 mirrorEl.style.visibility = 'hidden'; 2088 } 2089 } 2090 }; 2091 return InferredElementDragging; 2092 }(core.ElementDragging)); 2093 2094 /* 2095 Bridges third-party drag-n-drop systems with FullCalendar. 2096 Must be instantiated and destroyed by caller. 2097 */ 2098 var ThirdPartyDraggable = /** @class */ (function () { 2099 function ThirdPartyDraggable(containerOrSettings, settings) { 2100 var containerEl = document; 2101 if ( 2102 // wish we could just test instanceof EventTarget, but doesn't work in IE11 2103 containerOrSettings === document || 2104 containerOrSettings instanceof Element) { 2105 containerEl = containerOrSettings; 2106 settings = settings || {}; 2107 } 2108 else { 2109 settings = (containerOrSettings || {}); 2110 } 2111 var dragging = this.dragging = new InferredElementDragging(containerEl); 2112 if (typeof settings.itemSelector === 'string') { 2113 dragging.pointer.selector = settings.itemSelector; 2114 } 2115 else if (containerEl === document) { 2116 dragging.pointer.selector = '[data-event]'; 2117 } 2118 if (typeof settings.mirrorSelector === 'string') { 2119 dragging.mirrorSelector = settings.mirrorSelector; 2120 } 2121 new ExternalElementDragging(dragging, settings.eventData); 2122 } 2123 ThirdPartyDraggable.prototype.destroy = function () { 2124 this.dragging.destroy(); 2125 }; 2126 return ThirdPartyDraggable; 2127 }()); 2128 2129 var main = core.createPlugin({ 2130 componentInteractions: [DateClicking, DateSelecting, EventDragging, EventDragging$1], 2131 calendarInteractions: [UnselectAuto], 2132 elementDraggingImpl: FeaturefulElementDragging 2133 });
2134 2135 exports.Draggable = ExternalDraggable; 2136 exports.FeaturefulElementDragging = FeaturefulElementDragging; 2137 exports.PointerDragging = PointerDragging; 2138 exports.ThirdPartyDraggable = ThirdPartyDraggable; 2139 exports.default = main; 2140 2141 Object.defineProperty(exports, '__esModule', { value: true }); 2142 2143}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.