{"version":3,"file":"DraggableTextDelegate.min.mjs","names":[],"sources":["../../../../src/shapes/IText/DraggableTextDelegate.ts"],"sourcesContent":["import type {\n  DragEventData,\n  DropEventData,\n  TPointerEvent,\n} from '../../EventTypeDefs';\nimport { Point } from '../../Point';\nimport type { IText } from './IText';\nimport { setStyle } from '../../util/internals/dom_style';\nimport { cloneStyles } from '../../util/internals/cloneStyles';\nimport type { TextStyleDeclaration } from '../Text/StyledText';\nimport { getDocumentFromElement } from '../../util/dom_misc';\nimport { CHANGED, NONE } from '../../constants';\n\n/**\n * #### Dragging IText/Textbox Lifecycle\n * - {@link start} is called from `mousedown` {@link IText#_mouseDownHandler} and determines if dragging should start by testing {@link isPointerOverSelection}\n * - if true `mousedown` {@link IText#_mouseDownHandler} is blocked to keep selection\n * - if the pointer moves, canvas fires numerous mousemove {@link Canvas#_onMouseMove} that we make sure **aren't** prevented ({@link IText#shouldStartDragging}) in order for the window to start a drag session\n * - once/if the session starts canvas calls {@link onDragStart} on the active object to determine if dragging should occur\n * - canvas fires relevant drag events that are handled by the handlers defined in this scope\n * - {@link end} is called from `mouseup` {@link IText#mouseUpHandler}, blocking IText default click behavior\n * - in case the drag session didn't occur, {@link end} handles a click, since logic to do so was blocked during `mousedown`\n */\nexport class DraggableTextDelegate {\n  readonly target: IText;\n  private __mouseDownInPlace = false;\n  private __dragStartFired = false;\n  private __isDraggingOver = false;\n  private __dragStartSelection?: {\n    selectionStart: number;\n    selectionEnd: number;\n  };\n  private __dragImageDisposer?: VoidFunction;\n  private _dispose?: () => void;\n\n  constructor(target: IText) {\n    this.target = target;\n    const disposers = [\n      this.target.on('dragenter', this.dragEnterHandler.bind(this)),\n      this.target.on('dragover', this.dragOverHandler.bind(this)),\n      this.target.on('dragleave', this.dragLeaveHandler.bind(this)),\n      this.target.on('dragend', this.dragEndHandler.bind(this)),\n      this.target.on('drop', this.dropHandler.bind(this)),\n    ];\n    this._dispose = () => {\n      disposers.forEach((d) => d());\n      this._dispose = undefined;\n    };\n  }\n\n  isPointerOverSelection(e: TPointerEvent) {\n    const target = this.target;\n    const newSelection = target.getSelectionStartFromPointer(e);\n    return (\n      target.isEditing &&\n      newSelection >= target.selectionStart &&\n      newSelection <= target.selectionEnd &&\n      target.selectionStart < target.selectionEnd\n    );\n  }\n\n  /**\n   * @public override this method to disable dragging and default to mousedown logic\n   */\n  start(e: TPointerEvent) {\n    return (this.__mouseDownInPlace = this.isPointerOverSelection(e));\n  }\n\n  /**\n   * @public override this method to disable dragging without discarding selection\n   */\n  isActive() {\n    return this.__mouseDownInPlace;\n  }\n\n  /**\n   * Ends interaction and sets cursor in case of a click\n   * @returns true if was active\n   */\n  end(e: TPointerEvent) {\n    const active = this.isActive();\n    if (active && !this.__dragStartFired) {\n      // mousedown has been blocked since `active` is true => cursor has not been set.\n      // `__dragStartFired` is false => dragging didn't occur, pointer didn't move and is over selection.\n      // meaning this is actually a click, `active` is a false positive.\n      this.target.setCursorByClick(e);\n      this.target.initDelayedCursor(true);\n    }\n    this.__mouseDownInPlace = false;\n    this.__dragStartFired = false;\n    this.__isDraggingOver = false;\n    return active;\n  }\n\n  getDragStartSelection() {\n    return this.__dragStartSelection;\n  }\n\n  /**\n   * Override to customize the drag image\n   * https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setDragImage\n   */\n  setDragImage(\n    e: DragEvent,\n    {\n      selectionStart,\n      selectionEnd,\n    }: {\n      selectionStart: number;\n      selectionEnd: number;\n    },\n  ) {\n    const target = this.target;\n    const canvas = target.canvas!;\n    const flipFactor = new Point(target.flipX ? -1 : 1, target.flipY ? -1 : 1);\n    const boundaries = target._getCursorBoundaries(selectionStart);\n    const selectionPosition = new Point(\n      boundaries.left + boundaries.leftOffset,\n      boundaries.top + boundaries.topOffset,\n    ).multiply(flipFactor);\n    const pos = selectionPosition.transform(target.calcTransformMatrix());\n    const pointer = canvas.getScenePoint(e);\n    const diff = pointer.subtract(pos);\n    const retinaScaling = target.getCanvasRetinaScaling();\n    const bbox = target.getBoundingRect();\n    const correction = pos.subtract(new Point(bbox.left, bbox.top));\n    const vpt = canvas.viewportTransform;\n    const offset = correction.add(diff).transform(vpt, true);\n    //  prepare instance for drag image snapshot by making all non selected text invisible\n    const bgc = target.backgroundColor;\n    const styles = cloneStyles(target.styles);\n    target.backgroundColor = '';\n    const styleOverride = {\n      stroke: 'transparent',\n      fill: 'transparent',\n      textBackgroundColor: 'transparent',\n    };\n    target.setSelectionStyles(styleOverride, 0, selectionStart);\n    target.setSelectionStyles(styleOverride, selectionEnd, target.text.length);\n    target.dirty = true;\n    const dragImage = target.toCanvasElement({\n      enableRetinaScaling: canvas.enableRetinaScaling,\n      viewportTransform: true,\n    });\n    // restore values\n    target.backgroundColor = bgc;\n    target.styles = styles;\n    target.dirty = true;\n    //  position drag image offscreen\n    setStyle(dragImage, {\n      position: 'fixed',\n      left: `${-dragImage.width}px`,\n      border: NONE,\n      width: `${dragImage.width / retinaScaling}px`,\n      height: `${dragImage.height / retinaScaling}px`,\n    });\n    this.__dragImageDisposer && this.__dragImageDisposer();\n    this.__dragImageDisposer = () => {\n      dragImage.remove();\n    };\n    getDocumentFromElement(\n      (e.target || this.target.hiddenTextarea)! as HTMLElement,\n    ).body.appendChild(dragImage);\n    e.dataTransfer?.setDragImage(dragImage, offset.x, offset.y);\n  }\n\n  /**\n   * @returns {boolean} determines whether {@link target} should/shouldn't become a drag source\n   */\n  onDragStart(e: DragEvent): boolean {\n    this.__dragStartFired = true;\n    const target = this.target;\n    const active = this.isActive();\n    if (active && e.dataTransfer) {\n      const selection = (this.__dragStartSelection = {\n        selectionStart: target.selectionStart,\n        selectionEnd: target.selectionEnd,\n      });\n      const value = target._text\n        .slice(selection.selectionStart, selection.selectionEnd)\n        .join('');\n      const data = { text: target.text, value, ...selection };\n      e.dataTransfer.setData('text/plain', value);\n      e.dataTransfer.setData(\n        'application/fabric',\n        JSON.stringify({\n          value: value,\n          styles: target.getSelectionStyles(\n            selection.selectionStart,\n            selection.selectionEnd,\n            true,\n          ),\n        }),\n      );\n      e.dataTransfer.effectAllowed = 'copyMove';\n      this.setDragImage(e, data);\n    }\n    target.abortCursorAnimation();\n    return active;\n  }\n\n  /**\n   * use {@link targetCanDrop} to respect overriding\n   * @returns {boolean} determines whether {@link target} should/shouldn't become a drop target\n   */\n  canDrop(e: DragEvent): boolean {\n    if (\n      this.target.editable &&\n      !this.target.getActiveControl() &&\n      !e.defaultPrevented\n    ) {\n      if (this.isActive() && this.__dragStartSelection) {\n        //  drag source trying to drop over itself\n        //  allow dropping only outside of drag start selection\n        const index = this.target.getSelectionStartFromPointer(e);\n        const dragStartSelection = this.__dragStartSelection;\n        return (\n          index < dragStartSelection.selectionStart ||\n          index > dragStartSelection.selectionEnd\n        );\n      }\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * in order to respect overriding {@link IText#canDrop} we call that instead of calling {@link canDrop} directly\n   */\n  protected targetCanDrop(e: DragEvent) {\n    return this.target.canDrop(e);\n  }\n\n  dragEnterHandler({ e }: DragEventData) {\n    const canDrop = this.targetCanDrop(e);\n    if (!this.__isDraggingOver && canDrop) {\n      this.__isDraggingOver = true;\n    }\n  }\n\n  dragOverHandler(ev: DragEventData) {\n    const { e } = ev;\n    const canDrop = this.targetCanDrop(e);\n    if (!this.__isDraggingOver && canDrop) {\n      this.__isDraggingOver = true;\n    } else if (this.__isDraggingOver && !canDrop) {\n      //  drop state has changed\n      this.__isDraggingOver = false;\n    }\n    if (this.__isDraggingOver) {\n      //  can be dropped, inform browser\n      e.preventDefault();\n      //  inform event subscribers\n      ev.canDrop = true;\n      ev.dropTarget = this.target;\n    }\n  }\n\n  dragLeaveHandler() {\n    if (this.__isDraggingOver || this.isActive()) {\n      this.__isDraggingOver = false;\n    }\n  }\n\n  /**\n   * Override the `text/plain | application/fabric` types of {@link DragEvent#dataTransfer}\n   * in order to change the drop value or to customize styling respectively, by listening to the `drop:before` event\n   * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#performing_a_drop\n   */\n  dropHandler(ev: DropEventData) {\n    const { e } = ev;\n    const didDrop = e.defaultPrevented;\n    this.__isDraggingOver = false;\n    // inform browser that the drop has been accepted\n    e.preventDefault();\n    let insert = e.dataTransfer?.getData('text/plain');\n    if (insert && !didDrop) {\n      const target = this.target;\n      const canvas = target.canvas!;\n      let insertAt = target.getSelectionStartFromPointer(e);\n      const { styles } = (\n        e.dataTransfer!.types.includes('application/fabric')\n          ? JSON.parse(e.dataTransfer!.getData('application/fabric'))\n          : {}\n      ) as { styles: TextStyleDeclaration[] };\n      const trailing = insert[Math.max(0, insert.length - 1)];\n      const selectionStartOffset = 0;\n      //  drag and drop in same instance\n      if (this.__dragStartSelection) {\n        const selectionStart = this.__dragStartSelection.selectionStart;\n        const selectionEnd = this.__dragStartSelection.selectionEnd;\n        if (insertAt > selectionStart && insertAt <= selectionEnd) {\n          insertAt = selectionStart;\n        } else if (insertAt > selectionEnd) {\n          insertAt -= selectionEnd - selectionStart;\n        }\n        target.removeChars(selectionStart, selectionEnd);\n        // prevent `dragend` from handling event\n        delete this.__dragStartSelection;\n      }\n      //  remove redundant line break\n      if (\n        target._reNewline.test(trailing) &&\n        (target._reNewline.test(target._text[insertAt]) ||\n          insertAt === target._text.length)\n      ) {\n        insert = insert.trimEnd();\n      }\n      //  inform subscribers\n      ev.didDrop = true;\n      ev.dropTarget = target;\n      //  finalize\n      target.insertChars(insert, styles, insertAt);\n      // can this part be moved in an outside event? andrea to check.\n      canvas.setActiveObject(target);\n      target.enterEditing(e);\n      target.selectionStart = Math.min(\n        insertAt + selectionStartOffset,\n        target._text.length,\n      );\n      target.selectionEnd = Math.min(\n        target.selectionStart + insert.length,\n        target._text.length,\n      );\n      target.hiddenTextarea!.value = target.text;\n      target._updateTextarea();\n      target.hiddenTextarea!.focus();\n      target.fire(CHANGED, {\n        index: insertAt + selectionStartOffset,\n        action: 'drop',\n      });\n      canvas.fire('text:changed', { target });\n      canvas.contextTopDirty = true;\n      canvas.requestRenderAll();\n    }\n  }\n\n  /**\n   * fired only on the drag source after drop (if occurred)\n   * handle changes to the drag source in case of a drop on another object or a cancellation\n   * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#finishing_a_drag\n   */\n  dragEndHandler({ e }: DragEventData) {\n    if (this.isActive() && this.__dragStartFired) {\n      //  once the drop event finishes we check if we need to change the drag source\n      //  if the drag source received the drop we bail out since the drop handler has already handled logic\n      if (this.__dragStartSelection) {\n        const target = this.target;\n        const canvas = this.target.canvas!;\n        const { selectionStart, selectionEnd } = this.__dragStartSelection;\n        const dropEffect = e.dataTransfer?.dropEffect || NONE;\n        if (dropEffect === NONE) {\n          // pointer is back over selection\n          target.selectionStart = selectionStart;\n          target.selectionEnd = selectionEnd;\n          target._updateTextarea();\n          target.hiddenTextarea!.focus();\n        } else {\n          target.clearContextTop();\n          if (dropEffect === 'move') {\n            target.removeChars(selectionStart, selectionEnd);\n            target.selectionStart = target.selectionEnd = selectionStart;\n            target.hiddenTextarea &&\n              (target.hiddenTextarea.value = target.text);\n            target._updateTextarea();\n            target.fire(CHANGED, {\n              index: selectionStart,\n              action: 'dragend',\n            });\n            canvas.fire('text:changed', { target });\n            canvas.requestRenderAll();\n          }\n          target.exitEditing();\n        }\n      }\n    }\n\n    this.__dragImageDisposer && this.__dragImageDisposer();\n    delete this.__dragImageDisposer;\n    delete this.__dragStartSelection;\n    this.__isDraggingOver = false;\n  }\n\n  dispose() {\n    this._dispose && this._dispose();\n  }\n}\n"],"mappings":"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"}