Просмотр исходного кода

fix touch resizable-but-not-draggable event

Adam Shaw 7 лет назад
Родитель
Сommit
8c3097ff78
1 измененных файлов с 113 добавлено и 89 удалено
  1. 113 89
      src/interactions/EventDragging.ts

+ 113 - 89
src/interactions/EventDragging.ts

@@ -15,14 +15,15 @@ import { EventRenderRange } from '../component/event-rendering'
 import EventApi from '../api/EventApi'
 import { isEventStoreValid } from './constraint'
 
-export default class EventDragging {
+export default class EventDragging { // TODO: rename to EventSelectingAndDragging
 
   component: DateComponent
   dragging: FeaturefulElementDragging
   hitDragging: HitDragging
 
   // internal state
-  draggingSeg: Seg | null = null
+  subjectSeg: Seg | null = null // the seg being selected/dragged
+  isDragging: boolean = false
   eventRange: EventRenderRange | null = null
   relatedEvents: EventStore | null = null
   receivingCalendar: Calendar | null = null
@@ -33,7 +34,7 @@ export default class EventDragging {
     this.component = component
 
     let dragging = this.dragging = new FeaturefulElementDragging(component.el)
-    dragging.pointer.selector = '.fc-draggable'
+    dragging.pointer.selector = '.fc-draggable, .fc-resizable' // TODO: test this in IE11
     dragging.touchScrollAllowed = false
 
     let hitDragging = this.hitDragging = new HitDragging(this.dragging, browserContext.componentHash)
@@ -53,8 +54,8 @@ export default class EventDragging {
     let { component, dragging } = this
     let { mirror } = dragging
     let initialCalendar = component.getCalendar()
-    let draggingSeg = this.draggingSeg = getElSeg(ev.subjectEl as HTMLElement)!
-    let eventRange = this.eventRange = draggingSeg.eventRange!
+    let subjectSeg = this.subjectSeg = getElSeg(ev.subjectEl as HTMLElement)!
+    let eventRange = this.eventRange = subjectSeg.eventRange!
     let eventInstanceId = eventRange.eventInstance!.instanceId
 
     this.relatedEvents = getRelatedEvents(
@@ -76,10 +77,16 @@ export default class EventDragging {
     // to prevent from cloning the sourceEl before it is selected
     dragging.setMirrorIsVisible(false)
 
-    dragging.setIgnoreMove(
-      !this.component.isValidSegDownEl(origTarget) ||
-      Boolean(elementClosest(origTarget, '.fc-resizer'))
-    )
+    let isValid =
+      this.component.isValidSegDownEl(origTarget) &&
+      !elementClosest(origTarget, '.fc-resizer')
+
+    dragging.setIgnoreMove(!isValid)
+
+    // disable dragging for elements that are resizable (ie, selectable)
+    // but are not draggable
+    this.isDragging = isValid &&
+      (ev.subjectEl as HTMLElement).classList.contains('fc-draggable')
   }
 
   handleDragStart = (ev: PointerDragEvent) => {
@@ -105,17 +112,24 @@ export default class EventDragging {
       browserContext.unselectEvent()
     }
 
-    initialCalendar.publiclyTrigger('eventDragStart', [
-      {
-        el: this.draggingSeg.el,
-        event: new EventApi(initialCalendar, eventRange.eventDef, eventRange.eventInstance),
-        jsEvent: ev.origEvent,
-        view: this.component.view
-      }
-    ])
+    if (this.isDragging) {
+      initialCalendar.publiclyTrigger('eventDragStart', [
+        {
+          el: this.subjectSeg.el,
+          event: new EventApi(initialCalendar, eventRange.eventDef, eventRange.eventInstance),
+          jsEvent: ev.origEvent,
+          view: this.component.view
+        }
+      ])
+    }
   }
 
   handleHitUpdate = (hit: Hit | null, isFinal: boolean) => {
+
+    if (!this.isDragging) {
+      return
+    }
+
     let relatedEvents = this.relatedEvents!
     let initialHit = this.hitDragging.initialHit!
     let initialCalendar = this.component.getCalendar()
@@ -145,7 +159,7 @@ export default class EventDragging {
       affectedEvents: relatedEvents,
       mutatedEvents: mutatedRelatedEvents || createEmptyEventStore(),
       isEvent: true,
-      origSeg: this.draggingSeg
+      origSeg: this.subjectSeg
     })
 
     if (!isInvalid || isFinal) {
@@ -181,88 +195,88 @@ export default class EventDragging {
   onDocumentPointerUp = (ev: PointerDragEvent, wasTouchScroll: boolean) => {
     if (
       !wasTouchScroll &&
-      !this.draggingSeg && // was never dragging
-      // was the previously event-selected component?
-      browserContext.eventSelectedComponent === this.component
+      !this.subjectSeg && // no events were selected/dragged during this interaction
+      browserContext.eventSelectedComponent === this.component // this component owned the previous event selection
     ) {
       browserContext.unselectEvent()
     }
+
+    if (!this.isDragging) {
+      this.cleanup() // because handleDragEnd won't fire
+    }
   }
 
   handleDragEnd = (ev: PointerDragEvent) => {
-    let initialCalendar = this.component.getCalendar()
-    let initialView = this.component.view
-    let { receivingCalendar } = this
-    let { eventDef, eventInstance } = this.eventRange!
-    let eventApi = new EventApi(initialCalendar, eventDef, eventInstance)
-    let relatedEvents = this.relatedEvents!
-    let mutatedRelatedEvents = this.mutatedRelatedEvents!
-
-    this.clearDrag() // must happen after revert animation
-
-    initialCalendar.publiclyTrigger('eventDragStop', [
-      {
-        el: this.draggingSeg.el,
-        event: eventApi,
-        jsEvent: ev.origEvent,
-        view: initialView
-      }
-    ])
-
-    if (this.validMutation) {
-
-      // dropped within same calendar
-      if (receivingCalendar === initialCalendar) {
-
-        initialCalendar.dispatch({
-          type: 'ADD_EVENTS', // will merge
-          eventStore: mutatedRelatedEvents
-        })
 
-        initialCalendar.publiclyTrigger('eventMutation', [
-          {
-            mutation: this.validMutation, // TODO: public API?
-            prevEvent: eventApi,
-            event: new EventApi( // the data AFTER the mutation
-              initialCalendar,
-              mutatedRelatedEvents.defs[eventDef.defId],
-              eventInstance ? mutatedRelatedEvents.instances[eventInstance.instanceId] : null
-            ),
-            revert: function() {
-              initialCalendar.dispatch({
-                type: 'ADD_EVENTS', // will merge
-                eventStore: relatedEvents
-              })
-            },
-            jsEvent: ev.origEvent,
-            view: initialView
-          }
-        ])
+    if (this.isDragging) {
+      let initialCalendar = this.component.getCalendar()
+      let initialView = this.component.view
+      let { receivingCalendar } = this
+      let { eventDef, eventInstance } = this.eventRange!
+      let eventApi = new EventApi(initialCalendar, eventDef, eventInstance)
+      let relatedEvents = this.relatedEvents!
+      let mutatedRelatedEvents = this.mutatedRelatedEvents!
+
+      this.clearDrag() // must happen after revert animation
+
+      initialCalendar.publiclyTrigger('eventDragStop', [
+        {
+          el: this.subjectSeg.el,
+          event: eventApi,
+          jsEvent: ev.origEvent,
+          view: initialView
+        }
+      ])
+
+      if (this.validMutation) {
+
+        // dropped within same calendar
+        if (receivingCalendar === initialCalendar) {
+
+          initialCalendar.dispatch({
+            type: 'ADD_EVENTS', // will merge
+            eventStore: mutatedRelatedEvents
+          })
+
+          initialCalendar.publiclyTrigger('eventMutation', [
+            {
+              mutation: this.validMutation, // TODO: public API?
+              prevEvent: eventApi,
+              event: new EventApi( // the data AFTER the mutation
+                initialCalendar,
+                mutatedRelatedEvents.defs[eventDef.defId],
+                eventInstance ? mutatedRelatedEvents.instances[eventInstance.instanceId] : null
+              ),
+              revert: function() {
+                initialCalendar.dispatch({
+                  type: 'ADD_EVENTS', // will merge
+                  eventStore: relatedEvents
+                })
+              },
+              jsEvent: ev.origEvent,
+              view: initialView
+            }
+          ])
+
+        // dropped in different calendar
+        // TODO: more public triggers
+        } else if (receivingCalendar) {
+          initialCalendar.dispatch({
+            type: 'REMOVE_EVENT_INSTANCES',
+            instances: this.mutatedRelatedEvents!.instances
+          })
+          receivingCalendar.dispatch({
+            type: 'ADD_EVENTS',
+            eventStore: this.mutatedRelatedEvents!
+          })
+        }
 
-      // dropped in different calendar
-      // TODO: more public triggers
-      } else if (receivingCalendar) {
-        initialCalendar.dispatch({
-          type: 'REMOVE_EVENT_INSTANCES',
-          instances: this.mutatedRelatedEvents!.instances
-        })
-        receivingCalendar.dispatch({
-          type: 'ADD_EVENTS',
-          eventStore: this.mutatedRelatedEvents!
-        })
+      } else {
+        initialCalendar.publiclyTrigger('_noEventDrop')
       }
-
-    } else {
-      initialCalendar.publiclyTrigger('_noEventDrop')
     }
 
-    // reset all internal state
-    this.draggingSeg = null
-    this.eventRange = null
-    this.relatedEvents = null
-    this.receivingCalendar = null
-    this.validMutation = null
-    this.mutatedRelatedEvents = null
+    this.cleanup()
   }
 
   // render a drag state on the next receivingCalendar
@@ -311,6 +325,16 @@ export default class EventDragging {
     }
   }
 
+  cleanup() { // reset all internal state
+    this.subjectSeg = null
+    this.isDragging = false
+    this.eventRange = null
+    this.relatedEvents = null
+    this.receivingCalendar = null
+    this.validMutation = null
+    this.mutatedRelatedEvents = null
+  }
+
 }
 
 function computeEventMutation(hit0: Hit, hit1: Hit): EventMutation {