boost()

in packages/designer/src/designer/dragon.ts [173:541]


  boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) {
    const { designer } = this;
    const masterSensors = this.getMasterSensors();
    const handleEvents = makeEventsHandler(boostEvent, masterSensors);
    const newBie = !isDragNodeObject(dragObject);
    const forceCopyState =
      isDragNodeObject(dragObject) && dragObject.nodes.some((node: Node | IPublicModelNode) => (typeof node.isSlot === 'function' ? node.isSlot() : node.isSlot));
    const isBoostFromDragAPI = isDragEvent(boostEvent);
    let lastSensor: IPublicModelSensor | undefined;

    this._dragging = false;

    const getRGL = (e: MouseEvent | DragEvent) => {
      const locateEvent = createLocateEvent(e);
      const sensor = chooseSensor(locateEvent);
      if (!sensor || !sensor.getNodeInstanceFromElement) return {};
      const nodeInst = sensor.getNodeInstanceFromElement(e.target as Element);
      return nodeInst?.node?.getRGL() || {};
    };

    const checkesc = (e: KeyboardEvent) => {
      if (e.keyCode === 27) {
        designer.clearLocation();
        over();
      }
    };

    let copy = false;
    const checkcopy = (e: MouseEvent | DragEvent | KeyboardEvent) => {
      /* istanbul ignore next */
      if (isDragEvent(e) && e.dataTransfer) {
        if (newBie || forceCopyState) {
          e.dataTransfer.dropEffect = 'copy';
        }
        return;
      }
      if (newBie) {
        return;
      }

      if (e.altKey || e.ctrlKey) {
        copy = true;
        this.setCopyState(true);
        /* istanbul ignore next */
        if (isDragEvent(e) && e.dataTransfer) {
          e.dataTransfer.dropEffect = 'copy';
        }
      } else {
        copy = false;
        if (!forceCopyState) {
          this.setCopyState(false);
          /* istanbul ignore next */
          if (isDragEvent(e) && e.dataTransfer) {
            e.dataTransfer.dropEffect = 'move';
          }
        }
      }
    };

    let lastArrive: any;
    const drag = (e: MouseEvent | DragEvent) => {
      // FIXME: donot setcopy when: newbie & no location
      checkcopy(e);

      if (isInvalidPoint(e, lastArrive)) return;

      if (lastArrive && isSameAs(e, lastArrive)) {
        lastArrive = e;
        return;
      }
      lastArrive = e;

      const { isRGL, rglNode } = getRGL(e);
      const locateEvent = createLocateEvent(e);
      const sensor = chooseSensor(locateEvent);

      /* istanbul ignore next */
      if (isRGL) {
        // 禁止被拖拽元素的阻断
        const nodeInst = dragObject.nodes[0].getDOMNode();
        if (nodeInst && nodeInst.style) {
          this.nodeInstPointerEvents = true;
          nodeInst.style.pointerEvents = 'none';
        }
        // 原生拖拽
        this.emitter.emit('rgl.sleeping', false);
        if (fromRglNode && fromRglNode.id === rglNode.id) {
          designer.clearLocation();
          this.clearState();
          this.emitter.emit('drag', locateEvent);
          return;
        }
        this._canDrop = !!sensor?.locate(locateEvent);
        if (this._canDrop) {
          this.emitter.emit('rgl.add.placeholder', {
            rglNode,
            fromRglNode,
            node: locateEvent.dragObject?.nodes[0],
            event: e,
          });
          designer.clearLocation();
          this.clearState();
          this.emitter.emit('drag', locateEvent);
          return;
        }
      } else {
        this._canDrop = false;
        this.emitter.emit('rgl.remove.placeholder');
        this.emitter.emit('rgl.sleeping', true);
      }
      if (sensor) {
        sensor.fixEvent(locateEvent);
        sensor.locate(locateEvent);
      } else {
        designer.clearLocation();
      }
      this.emitter.emit('drag', locateEvent);
    };

    const dragstart = () => {
      this._dragging = true;
      setShaken(boostEvent);
      const locateEvent = createLocateEvent(boostEvent);
      if (newBie || forceCopyState) {
        this.setCopyState(true);
      } else {
        chooseSensor(locateEvent);
      }
      this.setDraggingState(true);
      // ESC cancel drag
      if (!isBoostFromDragAPI) {
        handleEvents((doc) => {
          doc.addEventListener('keydown', checkesc, false);
        });
      }

      this.emitter.emit('dragstart', locateEvent);
    };

    // route: drag-move
    const move = (e: MouseEvent | DragEvent) => {
      /* istanbul ignore next */
      if (isBoostFromDragAPI) {
        e.preventDefault();
      }
      if (this._dragging) {
        // process dragging
        drag(e);
        return;
      }

      // first move check is shaken
      if (isShaken(boostEvent, e)) {
        // is shaken dragstart
        dragstart();
        drag(e);
      }
    };

    let didDrop = true;
    /* istanbul ignore next */
    const drop = (e: DragEvent) => {
      e.preventDefault();
      e.stopPropagation();
      didDrop = true;
    };

    // end-tail drag process
    const over = (e?: any) => {
      // 禁止被拖拽元素的阻断
      if (this.nodeInstPointerEvents) {
        const nodeInst = dragObject.nodes[0].getDOMNode();
        if (nodeInst && nodeInst.style) {
          nodeInst.style.pointerEvents = '';
        }
        this.nodeInstPointerEvents = false;
      }

      // 发送drop事件
      if (e) {
        const { isRGL, rglNode } = getRGL(e);
        /* istanbul ignore next */
        if (isRGL && this._canDrop && this._dragging) {
          const tarNode = dragObject.nodes[0];
          if (rglNode.id !== tarNode.id) {
            // 避免死循环
            this.emitter.emit('rgl.drop', {
              rglNode,
              node: tarNode,
            });
            const selection = designer.project.currentDocument?.selection;
            selection?.select(tarNode.id);
          }
        }
      }

      // 移除磁帖占位消息
      this.emitter.emit('rgl.remove.placeholder');

      /* istanbul ignore next */
      if (e && isDragEvent(e)) {
        e.preventDefault();
      }
      if (lastSensor) {
        lastSensor.deactiveSensor();
      }
      /* istanbul ignore next */
      if (isBoostFromDragAPI) {
        if (!didDrop) {
          designer.clearLocation();
        }
      } else {
        this.setNativeSelection(true);
      }
      this.clearState();

      let exception;
      if (this._dragging) {
        this._dragging = false;
        try {
          this.emitter.emit('dragend', { dragObject, copy });
        } catch (ex) /* istanbul ignore next */ {
          exception = ex;
        }
      }
      designer.clearLocation();

      handleEvents((doc) => {
        /* istanbul ignore next */
        if (isBoostFromDragAPI) {
          doc.removeEventListener('dragover', move, true);
          doc.removeEventListener('dragend', over, true);
          doc.removeEventListener('drop', drop, true);
        } else {
          doc.removeEventListener('mousemove', move, true);
          doc.removeEventListener('mouseup', over, true);
        }
        doc.removeEventListener('mousedown', over, true);
        doc.removeEventListener('keydown', checkesc, false);
        doc.removeEventListener('keydown', checkcopy, false);
        doc.removeEventListener('keyup', checkcopy, false);
      });
      /* istanbul ignore next */
      if (exception) {
        throw exception;
      }
    };

    // create drag locate event
    const createLocateEvent = (e: MouseEvent | DragEvent): ILocateEvent => {
      const evt: any = {
        type: 'LocateEvent',
        dragObject,
        target: e.target,
        originalEvent: e,
      };

      const sourceDocument = e.view?.document;

      // event from current document
      if (!sourceDocument || sourceDocument === document) {
        evt.globalX = e.clientX;
        evt.globalY = e.clientY;
      } else /* istanbul ignore next */ {
        // event from simulator sandbox
        let srcSim: ISimulatorHost | undefined;
        const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null;
        // check source simulator
        if (lastSim && lastSim.contentDocument === sourceDocument) {
          srcSim = lastSim;
        } else {
          srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument);
          if (!srcSim && lastSim) {
            srcSim = lastSim;
          }
        }
        if (srcSim) {
          // transform point by simulator
          const g = srcSim.viewport.toGlobalPoint(e);
          evt.globalX = g.clientX;
          evt.globalY = g.clientY;
          evt.canvasX = e.clientX;
          evt.canvasY = e.clientY;
          evt.sensor = srcSim;
        } else {
          // this condition will not happen, just make sure ts ok
          evt.globalX = e.clientX;
          evt.globalY = e.clientY;
        }
      }
      return evt;
    };

    const sourceSensor = getSourceSensor(dragObject);
    /* istanbul ignore next */
    const chooseSensor = (e: ILocateEvent) => {
      // this.sensors will change on dragstart
      const sensors: IPublicModelSensor[] = this.sensors.concat(masterSensors as IPublicModelSensor[]);
      let sensor =
        e.sensor && e.sensor.isEnter(e)
          ? e.sensor
          : sensors.find((s) => s.sensorAvailable && s.isEnter(e));
      if (!sensor) {
        // TODO: enter some area like componentspanel cancel
        if (lastSensor) {
          sensor = lastSensor;
        } else if (e.sensor) {
          sensor = e.sensor;
        } else if (sourceSensor) {
          sensor = sourceSensor;
        }
      }
      if (sensor !== lastSensor) {
        if (lastSensor) {
          lastSensor.deactiveSensor();
        }
        lastSensor = sensor;
      }
      if (sensor) {
        e.sensor = sensor;
        sensor.fixEvent(e);
      }
      this._activeSensor = sensor;
      return sensor;
    };

    /* istanbul ignore next */
    if (isDragEvent(boostEvent)) {
      const { dataTransfer } = boostEvent;

      if (dataTransfer) {
        dataTransfer.effectAllowed = 'all';

        try {
          dataTransfer.setData('application/json', '{}');
        } catch (ex) {
          // ignore
        }
      }

      dragstart();
    } else {
      this.setNativeSelection(false);
    }

    handleEvents((doc) => {
      /* istanbul ignore next */
      if (isBoostFromDragAPI) {
        doc.addEventListener('dragover', move, true);
        // dragexit
        didDrop = false;
        doc.addEventListener('drop', drop, true);
        doc.addEventListener('dragend', over, true);
      } else {
        doc.addEventListener('mousemove', move, true);
        doc.addEventListener('mouseup', over, true);
      }
      doc.addEventListener('mousedown', over, true);
    });

    // future think: drag things from browser-out or a iframe-pane

    if (!newBie && !isBoostFromDragAPI) {
      handleEvents((doc) => {
        doc.addEventListener('keydown', checkcopy, false);
        doc.addEventListener('keyup', checkcopy, false);
      });
    }
  }