Adam Shaw пре 7 година
родитељ
комит
78b13204f5

+ 3 - 0
src/common/GlobalContext.ts

@@ -3,6 +3,7 @@ import DateClicking from '../interactions/DateClicking'
 import DateSelecting from '../interactions/DateSelecting'
 import EventClicking from '../interactions/EventClicking'
 import EventHovering from '../interactions/EventHovering'
+import EventDragging from '../interactions/EventDragging'
 
 let componentCnt = 0
 let componentHash = {}
@@ -34,10 +35,12 @@ export default {
 
   bind() {
     this.dateSelecting = new DateSelecting(componentHash)
+    this.eventDragging = new EventDragging(componentHash)
   },
 
   unbind() {
     this.dateSelecting.destroy()
+    this.eventDragging.destroy()
   },
 
   bindComponent(component: DateComponent) {

+ 1 - 1
src/component/renderers/EventRenderer.ts

@@ -448,7 +448,7 @@ export default class EventRenderer {
 
 
   isEventDefStartEditable(eventDef) {
-    return false // TODO
+    return true // TODO
   }
 
 

+ 155 - 0
src/dnd/DragMirror.ts

@@ -0,0 +1,155 @@
+import IntentfulDragListener from '../dnd/IntentfulDragListener'
+import { PointerDragEvent } from '../dnd/PointerDragListener'
+import { removeElement, applyStyle } from '../util/dom-manip'
+import { computeRect } from '../util/dom-geom'
+import { whenTransitionDone } from '../util/dom-event'
+
+export default class DragMirror {
+
+  dragListener: IntentfulDragListener
+  isEnabled: boolean = false
+  pointerDownX: number
+  pointerDownY: number
+  deltaX: number
+  deltaY: number
+  sourceEl: HTMLElement
+  mirrorEl: HTMLElement
+  sourceElRect: any
+  needsRevert: boolean = true
+  revertDuration: number = 1000
+
+  constructor(dragListener: IntentfulDragListener) {
+    this.dragListener = dragListener
+    dragListener.on('pointerdown', this.onPointerDown)
+    dragListener.on('dragstart', this.onDragStart)
+    dragListener.on('dragmove', this.onDragMove)
+    dragListener.on('dragend', this.onDragEnd)
+  }
+
+  enable() {
+    if (!this.isEnabled) {
+      this.isEnabled = true
+
+      if (this.dragListener.isDragging) {
+
+        if (this.mirrorEl) {
+          this.mirrorEl.style.display = ''
+        }
+
+        this.updateElPosition()
+      }
+    }
+  }
+
+  disable() {
+    if (this.isEnabled) {
+      this.isEnabled = false
+
+      if (this.mirrorEl) {
+        this.mirrorEl.style.display = 'none'
+      }
+    }
+  }
+
+  onPointerDown = (ev: PointerDragEvent) => {
+    this.pointerDownX = ev.pageX
+    this.pointerDownY = ev.pageY
+    this.sourceEl = ev.el
+  }
+
+  onDragStart = (ev: PointerDragEvent) => {
+    this.sourceElRect = computeRect(this.sourceEl)
+    this.handleDragEvent(ev)
+  }
+
+  onDragMove = (ev: PointerDragEvent) => {
+    this.handleDragEvent(ev)
+  }
+
+  onDragEnd = (ev: PointerDragEvent) => {
+    if (this.needsRevert && (this.deltaX || this.deltaY)) { // needs delta otherwise revert wont work
+      this.doRevert()
+    } else {
+      this.cleanup()
+    }
+  }
+
+  doRevert() {
+    let { mirrorEl } = this
+
+    mirrorEl.style.transition =
+      'top ' + this.revertDuration + 'ms,' +
+      'left ' + this.revertDuration + 'ms'
+
+    applyStyle(mirrorEl, {
+      left: this.sourceElRect.left,
+      top: this.sourceElRect.top
+    })
+
+    whenTransitionDone(mirrorEl, () => {
+      mirrorEl.style.transition = ''
+      this.cleanup()
+    })
+  }
+
+  cleanup() {
+    if (this.mirrorEl) {
+      removeElement(this.mirrorEl)
+      this.mirrorEl = null
+    }
+
+    this.sourceEl = null
+  }
+
+  handleDragEvent(ev: PointerDragEvent) {
+    this.deltaX = ev.pageX - this.pointerDownX
+    this.deltaY = ev.pageY - this.pointerDownY
+    this.updateElPosition()
+  }
+
+  updateElPosition() {
+    if (this.isEnabled) {
+      applyStyle(this.getMirrorEl(), {
+        left: this.sourceElRect.left + this.deltaX,
+        top: this.sourceElRect.top + this.deltaY
+      })
+    }
+  }
+
+  getMirrorEl(): HTMLElement {
+    let mirrorEl = this.mirrorEl
+
+    if (!mirrorEl) {
+      mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true) as HTMLElement // cloneChildren=true
+      // we don't want long taps or any mouse interaction causing selection/menus.
+      // would use preventSelection(), but that prevents selectstart, causing problems.
+      mirrorEl.classList.add('fc-unselectable')
+
+      // if (this.options.additionalClass) {
+      //   mirrorEl.classList.add(this.options.additionalClass)
+      // }
+
+      // TODO: do fixed positioning?
+      // TODO: how would that work with auto-scrolling?
+
+      applyStyle(mirrorEl, {
+        position: 'absolute',
+        visibility: '', // in case original element was hidden (commonly through hideEvents())
+        margin: 0,
+        right: 'auto', // erase and set width instead
+        bottom: 'auto', // erase and set height instead
+
+        // vvv use sourceElRect instead?
+        width: this.sourceEl.offsetWidth, // explicit height in case there was a 'right' value
+        height: this.sourceEl.offsetHeight, // explicit width in case there was a 'bottom' value
+        //opacity: this.options.opacity || '',
+        //zIndex: this.options.zIndex
+      })
+
+      document.body.appendChild(mirrorEl)
+    }
+
+    return mirrorEl
+  }
+
+}

+ 14 - 6
src/dnd/HitDragListener.ts

@@ -1,7 +1,7 @@
 import EmitterMixin from '../common/EmitterMixin'
 import { PointerDragEvent } from './PointerDragListener'
 import { default as IntentfulDragListener, IntentfulDragOptions } from './IntentfulDragListener'
-import DateComponent from '../component/DateComponent'
+import DateComponent, { DateComponentHash } from '../component/DateComponent'
 import { Selection } from '../reducers/selection'
 
 export interface Hit extends Selection {
@@ -17,15 +17,21 @@ fires:
 */
 export default class HitDragListener {
 
-  droppableComponents: DateComponent[]
+  droppableComponentHash: DateComponentHash
   emitter: EmitterMixin
   dragListener: IntentfulDragListener
   initialHit: Hit
   movingHit: Hit
   finalHit: Hit // won't ever be populated if options.ignoreMove is false
 
-  constructor(options: IntentfulDragOptions, droppableComponents: DateComponent[]) {
-    this.droppableComponents = droppableComponents
+  constructor(options: IntentfulDragOptions, droppableComponent: DateComponent, droppableComponentHash?: DateComponentHash) {
+
+    if (droppableComponent) {
+      this.droppableComponentHash = { [droppableComponent.uid]: droppableComponent }
+    } else {
+      this.droppableComponentHash = droppableComponentHash
+    }
+
     this.emitter = new EmitterMixin()
     this.dragListener = new IntentfulDragListener(options)
     this.dragListener.on('pointerdown', this.onPointerDown)
@@ -95,13 +101,15 @@ export default class HitDragListener {
   }
 
   prepareComponents() {
-    for (let component of this.droppableComponents) {
+    for (let id in this.droppableComponentHash) {
+      let component = this.droppableComponentHash[id]
       component.buildCoordCaches()
     }
   }
 
   queryHit(x, y): Hit {
-    for (let component of this.droppableComponents) {
+    for (let id in this.droppableComponentHash) {
+      let component = this.droppableComponentHash[id]
       let hit = component.queryHit(x, y) as Hit
 
       if (hit) {

+ 1 - 1
src/interactions/DateClicking.ts

@@ -12,7 +12,7 @@ export default class DateClicking {
     this.hitListener = new HitDragListener({
       containerEl: component.el
       // don't do ignoreMove:false because finalHit needs it
-    }, [ component ])
+    }, component)
 
     this.hitListener.on('dragend', this.onDragEnd)
   }

+ 1 - 1
src/interactions/DateSelecting.ts

@@ -44,7 +44,7 @@ export default class DateSelecting {
         containerEl: component.el,
         touchDelay: getComponentDelay(component),
         touchScrollAllowed: false
-      }, [ component ])
+      }, component)
 
       this.dragComponent = component
       this.dragSelection = null