مسحب

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

هناك حالات قليلة جدًا قد تحتاج فيها إلى استخدام أداة سحب مخصّصة، لأنّه ليس هناك الكثير من العناصر التي قد تحتاج إلى تخصيصها في ما يتعلّق بتنسيق عملية السحب. ينفِّذ مكوّن 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 عملية السحب. من المفترض أن يخزن أي بيانات مطلوبة ل تنفيذ عملية السحب. ويجب أيضًا استدعاء 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,
  },
});