浏览代码

clean up element mirror

Adam Shaw 7 年之前
父节点
当前提交
a885b55a7e

+ 2 - 8
src/dnd/ElementDragging.ts

@@ -4,12 +4,11 @@ import EmitterMixin from '../common/EmitterMixin'
 - pointerdown
 - dragstart
 - dragmove
-- pointerup ... TODO: change order!
+- pointerup
 - dragend
 */
 export default abstract class ElementDragging {
 
-  isDragging: boolean = false // will go away when DragMirror is more loosely coupled
   emitter: EmitterMixin
 
   constructor() {
@@ -22,12 +21,7 @@ export default abstract class ElementDragging {
   setIgnoreMove(bool: boolean) {
   }
 
-  enableMirror() {
-    // TODO: make it a switch
-  }
-
-  disableMirror() {
-    // TODO: make it a switch
+  setMirrorIsVisible(bool: boolean) {
   }
 
   setMirrorNeedsRevert(bool: boolean) {

+ 48 - 74
src/dnd/DragMirror.ts → src/dnd/ElementMirror.ts

@@ -1,92 +1,69 @@
-import ElementDragging from '../dnd/ElementDragging'
-import { PointerDragEvent } from '../dnd/PointerDragging'
 import { removeElement, applyStyle } from '../util/dom-manip'
 import { computeRect } from '../util/dom-geom'
 import { whenTransitionDone } from '../util/dom-event'
 
-export default class DragMirror {
+export default class ElementMirror {
 
-  dragging: ElementDragging
-  isEnabled: boolean = false
-  pointerDownX: number
-  pointerDownY: number
+  isVisible: boolean = false
+  origX: number
+  origY: number
   deltaX: number
   deltaY: number
   sourceEl: HTMLElement
   mirrorEl: HTMLElement
   sourceElRect: any
-  needsRevert: boolean = true
   revertDuration: number = 1000
-  isReverting: boolean = false
-  revertDoneCallback: any
-
-  constructor(dragging: ElementDragging) {
-    this.dragging = dragging
-    dragging.emitter.on('pointerdown', this.onPointerDown)
-    dragging.emitter.on('dragstart', this.onDragStart)
-    dragging.emitter.on('dragmove', this.onDragMove)
-    dragging.emitter.on('pointerup', this.onPointerUp)
-  }
 
-  enable() {
-    if (!this.isEnabled) {
-      this.isEnabled = true
+  start(sourceEl, left, top) {
+    this.sourceEl = sourceEl
+    this.origX = left
+    this.origY = top
+    this.deltaX = 0
+    this.deltaY = 0
+    this.updateElPosition()
+  }
 
-      if (this.dragging.isDragging) {
+  handleMove(left, top) {
+    this.deltaX = left - this.origX
+    this.deltaY = top - this.origY
+    this.updateElPosition()
+  }
 
+  setIsVisible(bool: boolean) {
+    if (bool) {
+      if (!this.isVisible) {
         if (this.mirrorEl) {
           this.mirrorEl.style.display = ''
         }
-
         this.updateElPosition()
       }
-    }
-  }
-
-  disable() {
-    if (this.isEnabled) {
-      this.isEnabled = false
-
-      if (this.mirrorEl) {
-        this.mirrorEl.style.display = 'none'
+    } else {
+      if (this.isVisible) {
+        if (this.mirrorEl) {
+          this.mirrorEl.style.display = 'none'
+        }
       }
     }
-  }
 
-  onPointerDown = (ev: PointerDragEvent) => {
-    this.pointerDownX = ev.pageX
-    this.pointerDownY = ev.pageY
-    this.sourceEl = ev.subjectEl
+    this.isVisible = bool
   }
 
-  onDragStart = (ev: PointerDragEvent) => {
-    this.handleDragEvent(ev)
-  }
-
-  onDragMove = (ev: PointerDragEvent) => {
-    this.handleDragEvent(ev)
-  }
-
-  onPointerUp = (ev: PointerDragEvent) => {
-
-    if (this.mirrorEl) {
-
-      if (this.isEnabled && this.needsRevert && (this.deltaX || this.deltaY)) {
-        this.revertAndRemove(this.mirrorEl)
-      } else {
-        removeElement(this.mirrorEl)
-      }
-
-      this.mirrorEl = null
+  // always async
+  stop(doRevertAnimation, callback) {
+    let done = () => {
+      this.cleanup()
+      callback()
     }
 
-    this.sourceEl = null
-    this.sourceElRect = null // so knows to recompute next time
+    if (doRevertAnimation && this.mirrorEl && this.isVisible) {
+      this.doAnimation(done)
+    } else {
+      setTimeout(done, 0)
+    }
   }
 
-  // can happen after drag has finished and a new one begins
-  revertAndRemove(mirrorEl) {
-    this.isReverting = true
+  doAnimation(callback) {
+    let { mirrorEl } = this
 
     mirrorEl.style.transition =
       'top ' + this.revertDuration + 'ms,' +
@@ -99,25 +76,22 @@ export default class DragMirror {
 
     whenTransitionDone(mirrorEl, () => {
       mirrorEl.style.transition = ''
-      removeElement(mirrorEl)
-      this.isReverting = false
-
-      if (this.revertDoneCallback) {
-        this.revertDoneCallback()
-        this.revertDoneCallback = null
-      }
+      callback()
     })
   }
 
-  handleDragEvent(ev: PointerDragEvent) {
-    this.deltaX = ev.pageX - this.pointerDownX
-    this.deltaY = ev.pageY - this.pointerDownY
-    this.updateElPosition()
+  cleanup() {
+    if (this.mirrorEl) {
+      removeElement(this.mirrorEl)
+      this.mirrorEl = null
+    }
+
+    this.sourceEl = null
+    this.sourceElRect = null // so knows to recompute next time
   }
 
   updateElPosition() {
-    if (this.isEnabled) {
-
+    if (this.isVisible) {
       if (!this.sourceElRect) {
         this.sourceElRect = computeRect(this.sourceEl)
       }

+ 21 - 33
src/dnd/FeaturefulElementDragging.ts

@@ -1,15 +1,14 @@
-import { default as EmitterMixin } from '../common/EmitterMixin'
 import { default as PointerDragging, PointerDragEvent } from './PointerDragging'
 import { preventSelection, allowSelection, preventContextMenu, allowContextMenu } from '../util/misc'
-import DragMirror from './DragMirror'
+import ElementMirror from './ElementMirror'
 import ElementDragging from './ElementDragging'
 
 
 export default class FeaturefulElementDragging extends ElementDragging {
 
   pointer: PointerDragging
-  emitter: EmitterMixin
-  dragMirror: DragMirror // TODO: move out of here?
+  mirror: ElementMirror
+  mirrorNeedsRevert: boolean = false
 
   // options
   delay: number
@@ -17,7 +16,7 @@ export default class FeaturefulElementDragging extends ElementDragging {
   touchScrollAllowed: boolean = true
 
   isWatchingPointer: boolean = false
-  isDragging: boolean = false // is it INTENTFULLY dragging? lasts until after revert animation // TODO: exclude revert anim?
+  isDragging: boolean = false // is it INTENTFULLY dragging? lasts until after revert animation
   isDelayEnded: boolean = false
   isDistanceSurpassed: boolean = false
 
@@ -28,23 +27,18 @@ export default class FeaturefulElementDragging extends ElementDragging {
   constructor(containerEl: HTMLElement) {
     super()
 
-    this.emitter = new EmitterMixin()
-    this.dragMirror = new DragMirror(this)
-
     let pointer = this.pointer = new PointerDragging(containerEl)
     pointer.emitter.on('pointerdown', this.onPointerDown)
     pointer.emitter.on('pointermove', this.onPointerMove)
     pointer.emitter.on('pointerup', this.onPointerUp)
+
+    this.mirror = new ElementMirror()
   }
 
   destroy() {
     this.pointer.destroy()
   }
 
-  on(name, handler) {
-    this.emitter.on(name, handler)
-  }
-
   onPointerDown = (ev: PointerDragEvent) => {
     if (!this.isDragging) { // mainly so new drag doesn't happen while revert animation is going
       this.isWatchingPointer = true
@@ -58,6 +52,7 @@ export default class FeaturefulElementDragging extends ElementDragging {
       this.origY = ev.pageY
 
       this.emitter.trigger('pointerdown', ev)
+      this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY)
 
       // if moving is being ignored, don't fire any initial drag events
       if (!this.pointer.shouldIgnoreMove) {
@@ -75,6 +70,7 @@ export default class FeaturefulElementDragging extends ElementDragging {
   onPointerMove = (ev: PointerDragEvent) => {
     if (this.isWatchingPointer) { // if false, still waiting for previous drag's revert
       this.emitter.trigger('pointermove', ev)
+      this.mirror.handleMove(ev.pageX, ev.pageY)
 
       if (!this.isDistanceSurpassed) {
         let dx = ev.pageX - this.origX
@@ -139,6 +135,7 @@ export default class FeaturefulElementDragging extends ElementDragging {
     if (this.isDelayEnded && this.isDistanceSurpassed) {
       if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) {
         this.isDragging = true
+        this.mirrorNeedsRevert = false
         this.emitter.trigger('dragstart', ev)
 
         if (this.touchScrollAllowed === false) {
@@ -149,38 +146,29 @@ export default class FeaturefulElementDragging extends ElementDragging {
   }
 
   tryStopDrag(ev) {
-    let stopDrag = this.stopDrag.bind(this, ev) // bound with args
-
-    if (this.dragMirror.isReverting) {
-      this.dragMirror.revertDoneCallback = stopDrag // will clear itself
-    } else {
-      // HACK - we want to make sure dragend fires after all pointerup events.
-      // Without doing this hack, pointer-up event propogation might reach an ancestor
-      // node after dragend
-      setTimeout(stopDrag, 0)
-    }
+    // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events
+    // that come from the document to fire beforehand. much more convenient this way.
+    this.mirror.stop(
+      this.mirrorNeedsRevert,
+      this.stopDrag.bind(this, ev) // bound with args
+    )
   }
 
   stopDrag(ev) {
-    this.isDragging = false // go first because DragMirror::enable relies on it :(
+    this.isDragging = false
     this.emitter.trigger('dragend', ev)
   }
 
-
-  enableMirror() {
-    this.dragMirror.enable()
+  setIgnoreMove(bool: boolean) {
+    this.pointer.shouldIgnoreMove = bool
   }
 
-  disableMirror() {
-    this.dragMirror.disable()
+  setMirrorIsVisible(bool: boolean) {
+    this.mirror.setIsVisible(bool)
   }
 
   setMirrorNeedsRevert(bool: boolean) {
-    this.dragMirror.needsRevert = bool
-  }
-
-  setIgnoreMove(bool: boolean) {
-    this.pointer.shouldIgnoreMove = bool
+    this.mirrorNeedsRevert = true
   }
 
 }

+ 0 - 3
src/interactions-external/DumbElementDragging.ts

@@ -10,7 +10,6 @@ import ElementDragging from '../dnd/ElementDragging'
 */
 export default class DumbElementDragging extends ElementDragging {
 
-  isDragging: boolean
   options: any
   pointer: PointerDragging
   currentMirrorEl: HTMLElement
@@ -32,7 +31,6 @@ export default class DumbElementDragging extends ElementDragging {
   }
 
   handlePointerDown = (ev: PointerDragEvent) => {
-    this.isDragging = true
     this.emitter.trigger('pointerdown', ev)
     this.emitter.trigger('dragstart', ev)
   }
@@ -42,7 +40,6 @@ export default class DumbElementDragging extends ElementDragging {
   }
 
   handlePointerUp = (ev: PointerDragEvent) => {
-    this.isDragging = false
     this.emitter.trigger('pointerup', ev)
     this.emitter.trigger('dragend', ev)
   }

+ 8 - 9
src/interactions-external/ExternalElementDragging.ts

@@ -23,7 +23,7 @@ export default class ExternalElementDragging {
     hitDragging.on('hitout', this.onHitOut)
     hitDragging.on('dragend', this.onDragEnd)
 
-    dragging.enableMirror()
+    dragging.setMirrorIsVisible(true)
 
     this.explicitEventCreationData = rawEventCreationData ? processExplicitData(rawEventCreationData) : null
   }
@@ -66,12 +66,11 @@ export default class ExternalElementDragging {
 
     dragging.setMirrorNeedsRevert(false)
 
-    // TODO wish we could somehow wait for dispatch to guarantee render
-    if (!document.querySelector('.fc-helper')) {
-      dragging.enableMirror()
-    } else {
-      dragging.disableMirror()
-    }
+    // show mirror if no already-rendered helper element
+    // TODO: wish we could somehow wait for dispatch to guarantee render
+    dragging.setMirrorIsVisible(
+      !document.querySelector('.fc-helper')
+    )
   }
 
   onHitOut = (hit) => { // TODO: onHitChange?
@@ -89,12 +88,12 @@ export default class ExternalElementDragging {
 
     let { dragging } = this.hitDragging
 
-    dragging.enableMirror()
+    dragging.setMirrorIsVisible(true)
     dragging.setMirrorNeedsRevert(true)
   }
 
   onDragEnd = (pev: PointerDragEvent) => {
-    this.hitDragging.dragging.enableMirror() // always restore!
+    this.hitDragging.dragging.setMirrorIsVisible(true) // always restore!
 
     if (this.addableEventStore) {
       let finalHit = this.hitDragging.finalHit

+ 4 - 3
src/interactions/DateClicking.ts

@@ -18,11 +18,12 @@ export default class DateClicking {
   }
 
   onPointerDown = (ev: PointerDragEvent) => {
-    let { component } = this
-    let { pointer } = this.dragging
+    let { dragging } = this
 
     // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired
-    pointer.shouldIgnoreMove = !component.isValidDateInteraction(pointer.downEl)
+    dragging.setIgnoreMove(
+      !this.component.isValidDateInteraction(dragging.pointer.downEl)
+    )
   }
 
   onDragEnd = (ev: PointerDragEvent) => {

+ 1 - 1
src/interactions/DateSelecting.ts

@@ -40,7 +40,7 @@ export default class DateSelecting {
       component.isValidDateInteraction(ev.origEvent.target as HTMLElement)
 
     // don't bother to watch expensive moves if component won't do selection
-    dragging.pointer.shouldIgnoreMove = !isValid
+    dragging.setIgnoreMove(!isValid)
 
     dragging.delay = (isValid && ev.isTouch) ?
       getComponentDelay(component) :

+ 13 - 17
src/interactions/EventDragging.ts

@@ -43,13 +43,14 @@ export default class EventDragging {
     dragging.delay = this.computeDragDelay(ev)
 
     // to prevent from cloning the sourceEl before it is selected
-    dragging.dragMirror.disable()
+    dragging.setMirrorIsVisible(false)
 
     let origTarget = ev.origEvent.target as HTMLElement
 
-    dragging.pointer.shouldIgnoreMove =
+    dragging.setIgnoreMove(
       !this.component.isValidSegInteraction(origTarget) ||
       elementClosest(origTarget, '.fc-resizer')
+    )
   }
 
   computeDragDelay(ev: PointerDragEvent): number {
@@ -112,17 +113,16 @@ export default class EventDragging {
       }
     })
 
-    let { dragMirror } = this.dragging
+    let { dragging } = this
 
-    // TODO wish we could somehow wait for dispatch to guarantee render
-    if (!document.querySelector('.fc-helper')) {
-      dragMirror.enable()
-    } else {
-      dragMirror.disable()
-    }
+    // render the mirror if no already-rendered helper
+    // TODO: wish we could somehow wait for dispatch to guarantee render
+    dragging.setMirrorIsVisible(
+      !document.querySelector('.fc-helper')
+    )
 
     let isSame = isHitsEqual(initialHit, hit)
-    dragMirror.needsRevert = isSame
+    dragging.setMirrorNeedsRevert(isSame)
 
     if (!isSame) {
       this.mutation = mutation
@@ -142,16 +142,12 @@ export default class EventDragging {
       }
     })
 
-    let { dragMirror } = this.dragging
+    let { dragging } = this
 
-    dragMirror.enable()
-    dragMirror.needsRevert = true
+    dragging.setMirrorIsVisible(true)
+    dragging.setMirrorNeedsRevert(true)
   }
 
-  /*
-  TODO: rethinking ordering of onDocumentPointerUp firing,
-  we want something that will always fire LAST, in case drag never activated
-  */
   onDocumentPointerUp = (ev, wasTouchScroll) => {
     if (
       !this.mutation &&

+ 2 - 1
src/interactions/EventResizing.ts

@@ -38,9 +38,10 @@ export default class EventDragging {
     let eventInstanceId = seg.eventRange.eventInstance.instanceId
 
     // if touch, need to be working with a selected event
-    this.dragging.pointer.shouldIgnoreMove =
+    this.dragging.setIgnoreMove(
       !this.component.isValidSegInteraction(ev.origEvent.target) ||
       (ev.isTouch && this.component.selectedEventInstanceId !== eventInstanceId)
+    )
   }
 
   onDragStart = (ev) => {