أدوات سحب مخصّصة

أداة السحب هي عنصر تحكّم ينسق عملية سحب العناصر القابلة للسحب استجابةً لتفاعلات المستخدم.

هناك حالات قليلة جدًا قد تحتاج فيها إلى تنفيذ أداة سحب مخصّصة، لأنّه ليس هناك الكثير من العناصر التي قد تحتاج إلى تخصيصها في ما يتعلّق بتنسيق عملية السحب. ينفِّذ مكوّن scroll-options الإضافي أداة سحب مخصّصة لأنّه أراد إضافة ميزة التمرير على حافة مساحة العمل، ما يغيّر طريقة تحويل إحداثيات البكسل إلى إحداثيات مساحة العمل.

المسؤوليات

تتحمّل عملية السحب عدة مسؤوليات عند تنفيذ عمليات السحب:

  • استدعاء طرق السحب على العنصر القابل للسحب
  • احتساب الموضع الذي يجب أن ينتقل إليه العنصر القابل للسحب في إحداثيات مساحته
  • استدعاء طرق استهداف السحب على أي استهدافات سحب تم تمرير مؤشر الماوس فوقها

التنفيذ

لإنشاء أداة سحب مخصّصة، عليك تنفيذ واجهة IDragger.

class MyDragger implements IDragger {
  // Takes in the draggable being dragged and the workspace the drag
  // is occurring in.
  constructor(draggable, workspace);
}

يمكنك أيضًا إنشاء فئة فرعية للعنصر المضمّن Blockly.dragging.Dragger الذي يتولّى المهام الأساسية.

بدء عمليات السحب

تبدأ طريقة onDragStart عملية السحب. من المفترض أن يخزن أي بيانات مطلوبة ل ejecutant السحب. ويجب أيضًا أن يُطلِق العنصر startDrag على العنصر القابل للسحب الذي يتم سحبه.

onDragStart(e) {
  this.startLoc = this.draggable.getRelativeToSurfaceXY();

  this.draggable.startDrag(e);
}

السحب

تنفِّذ الطريقة onDrag عملية سحب. من المفترض أن يحسب العنصر موقع مساحة العمل الجديد للعنصر القابل للسحب استنادًا إلى totalDelta، والذي يتم تقديمه في إحداثيات البكسل.

من المفترض أن يؤدي ذلك أيضًا إلى تعديل أي أهداف سحب يتم تمرير مؤشر الماوس فوقها.

  • يجب دائمًا استدعاء wouldDelete قبل استدعاء أدوات الربط الأخرى في هدف السحب.
  • يجب دائمًا استدعاء onDragExit على هدف السحب القديم قبل استدعاء onDragEnter على هدف السحب الجديد.
  • يجب استدعاء onDragOver بعد onDragEnter المرة الأولى التي يتم فيها تمرير مؤشر الماوس فوق ‎drag target، وفي كلّ استدعاء إضافي لواجهة onDrag عندما لا يزال مؤشر الماوس مركّزًا على ‎drag target.
onDrag(e, totalDelta) {
  // Update the draggable location.
  const delta = this.pixelsToWorkspaceUnits(totalDelta);
  const newLoc = Coordinate.sum(this.startLoc, delta);
  this.draggable.drag(newLoc, e);

  // Call wouldDeleteDraggable.
  if (isDeletable(this.draggable)) {
    this.draggable.setDeleteStyle(
      // Checks that the drag target is an `IDeleteArea` and calls `wouldDelete`
      // on it.
      this.wouldDeleteDraggable(e, this.draggable),
    );
  }

  const newDragTarget = this.workspace.getDragTarget(e);
  if (this.dragTarget !== newDragTarget) {
    // Call `onDragExit` then `onDragEnter`.
    this.dragTarget?.onDragExit(this.draggable);
    newDragTarget?.onDragEnter(this.draggable);
  }
  // Always call `onDragOver`
  newDragTarget?.onDragOver(this.draggable);
  this.dragTarget = newDragTarget;
}

إنهاء عمليات السحب

تُنهي الطريقة onEndDrag عملية السحب. يجب أن يُعلم العنصر القابل للسحب بأنّه تم إنهاء السحب وأيّ هدف سحب تم تمرير مؤشر الماوس فوقه بأنّه تم إسقاط العنصر القابل للسحب. ومن المفترض أن يؤدي ذلك أيضًا إلى إزالة العنصر القابل للسحب إذا كان هدف السحب هو منطقة حذف.

  • يجب دائمًا استدعاء onDrop قبل الطرق الأخرى.
  • يجب استدعاء revertDrag إذا كان هدف السحب يمنع عمليات السحب.
  • يجب استدعاء endDrag بعد التراجع عن السحب، ولكن قبل التخلص.
  • يجب استدعاء dispose إذا كان هدف السحب هو منطقة حذف.
onDragEnd(e) {
  // Call `onDrop` first.
  const dragTarget = this.workspace.getDragTarget(e);
  if (dragTarget) {
    this.dragTarget?.onDrop(this.draggable);
  }

  // Then revert the drag (if applicable).
  if (this.shouldReturnToStart(e, this.draggable)) {
    this.draggable.revertDrag();
  }

  // Then end the drag.
  this.draggable.endDrag(e);

  // Then delete the draggable (if applicable).
  if (
    isDeletable(this.draggable) &&
    this.wouldDeleteDraggable(e, this.draggable)
  ) {
    this.draggable.dispose();
  }
}

التسجيل

يجب تسجيل فئة أداة السحب لكي يتم إنشاؤها عند رصد عمليات السحب.

// Note that the type is BLOCK_DRAGGER even though draggers drag more than
// blocks. The name is for backwards compatibility.
Blockly.registry.register(registry.Type.BLOCK_DRAGGER, 'MY_DRAGGER', MyDragger);

الاستخدام

بعد تنفيذ أداة السحب المخصّصة، يمكنك استخدامها من خلال تمريرها إلى خيارات الضبط.

const myWorkspace = Blockly.inject('blocklyDiv', {
  plugins: {
    // Note that we pass this to blockDragger even though draggers drag more
    // than blocks. The name is for backwards compatibility.
    blockDragger: MyDragger,
  },
});