قوائم السياقات

تحتوي قائمة السياق على قائمة بالإجراءات التي يمكن للمستخدم تنفيذها على أحد المكوّنات، مثل مساحة عمل أو فقرة أو تعليق في مساحة العمل. تظهر قائمة السياق استجابةً للنقر بزر الماوس الأيمن أو الضغط مع الاستمرار على جهاز مزوّد بشاشة تعمل باللمس. إذا كنت تستخدم الإضافة @blockly/keyboard-navigation، سيظهر أيضًا اختصار لوحة المفاتيح، وهو Ctrl+Enter تلقائيًا على أجهزة Windows أو Command+Enter على أجهزة Mac.

قائمة السياق التلقائية لأي حظر

تُعدّ قوائم السياق مكانًا مناسبًا لإضافة الإجراءات التي ينفّذها المستخدم بشكل غير متكرّر، مثل تنزيل لقطة شاشة. إذا كنت تعتقد أنّ إجراءً معيّنًا سيُستخدم بشكل أكثر شيوعًا، يمكنك إنشاء طريقة أسهل للعثور عليه واستخدامه.

تتوافق قوائم السياق مع مساحات العمل والكتل وتعليقات مساحة العمل والفقاعات والروابط. يمكنك أيضًا تنفيذها على مكوّناتك المخصّصة. توفّر Blockly قوائم سياقية عادية يمكنك تخصيصها. يمكنك أيضًا تخصيص قوائم السياق في مساحات العمل والحظر على أساس كل مساحة عمل أو كل حظر.

طريقة عمل قوائم السياق

يحتوي Blockly على سجلّ يتضمّن نماذج لجميع عناصر القائمة المحتملة. يصف كل نموذج كيفية إنشاء عنصر واحد في قائمة السياق. عندما يستدعي المستخدم قائمة سياق على أحد المكوّنات، يقوم المكوّن بما يلي:

  1. يطلب من السجلّ إنشاء مصفوفة من عناصر القائمة التي تنطبق على المكوّن. يسأل السجلّ كل نموذج عمّا إذا كان ينطبق على المكوّن، وإذا كان الأمر كذلك، يضيف عنصر قائمة مطابقًا إلى الصفيف.

  2. إذا كان العنصر مساحة عمل أو كتلة، يتم التحقّق مما إذا كانت مساحة العمل أو الكتلة المحدّدة التي تم استدعاء القائمة فيها تتضمّن دالة لتخصيص قائمة السياق. وفي هذه الحالة، يتم تمرير المصفوفة إلى الدالة، التي يمكنها إضافة عناصر إلى المصفوفة أو حذفها أو تعديلها.

  3. تعرض هذه السمة قائمة السياقات باستخدام مصفوفة عناصر قائمة السياقات (التي ربما تم تعديلها).

تحدّد Blockly مجموعة عادية من النماذج لقوائم السياق الخاصة بمساحات العمل والكتل وتعليقات مساحة العمل. يتم تحميل النماذج مسبقًا للمساحات وعناصر البناء في السجلّ. إذا أردت استخدام النماذج لتعليقات مساحة العمل، عليك تحميلها إلى السجلّ بنفسك.

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

النطاق

يتم تنفيذ قوائم السياق من خلال أنواع مختلفة من المكوّنات، بما في ذلك مساحات العمل وتعليقات مساحة العمل والروابط والمربّعات والفقاعات والمكوّنات المخصّصة. قد تحتوي قوائم السياق الخاصة بكل نوع من هذه الأنواع على عناصر مختلفة، وقد تختلف طريقة عمل العناصر استنادًا إلى نوع المكوّن. وبالتالي، يجب أن يعرف نظام قائمة السياق المكوّن الذي تم استدعاؤه عليه.

ولحلّ هذه المشكلة، يستخدم السجلّ كائن Scope. يتم تخزين المكوّن الذي تم استدعاء قائمة السياق عليه في السمة focusedNode كعنصر ينفّذ IFocusableNode. يتم تنفيذ IFocusableNode من خلال جميع المكوّنات التي يمكن للمستخدمين التركيز عليها، بما في ذلك تلك التي تنفّذ قوائم السياق. لمزيد من المعلومات، اطّلِع على نظام التركيز).

يتم تمرير العنصر Scope إلى العديد من الدوال في النموذج. في أي دالة تتلقّى عنصر Scope، يمكنك تحديد الإجراء الذي تريد اتّخاذه استنادًا إلى نوع العنصر في السمة focusedNode. على سبيل المثال، يمكنك التحقّق مما إذا كان المكوّن عبارة عن كتلة باستخدام:

if (scope.focusedNode instanceof Blockly.BlockSvg) {
  // do something with the block
}

يحتوي العنصر Scope على سمات اختيارية أخرى لم يعُد يُنصح باستخدامها، ولكن قد يظلّ من الممكن ضبطها:

  • لا يتم ضبط block إلا إذا كان المكوّن الذي تظهر قائمته هو BlockSvg.
  • يتم ضبط workspace فقط إذا كان المكوّن WorkspaceSvg.
  • يتم ضبط comment فقط إذا كان المكوّن RenderedWorkspaceComment.

لا تغطي هذه الخصائص جميع أنواع المكوّنات التي قد تتضمّن قائمة خاصة بالسياق، لذا يُفضّل استخدام السمة focusedNode.

نوع RegistryItem

تكون أنواع النماذج ContextMenuRegistry.RegistryItem، التي تحتوي على السمات التالية. يُرجى العِلم أنّ السمة preconditionFn والسمة displayText والسمة callback تستبعد كلّ منها السمة separator.

ID

يجب أن تكون السمة id سلسلة فريدة تشير إلى وظيفة عنصر قائمة السياق.

const collapseTemplate = {
  id: 'collapseBlock',
  // ...
};

دالة الشرط المُسبَق

يمكنك استخدام preconditionFn لفرض قيود على وقت وطريقة عرض عنصر قائمة السياقات.

يجب أن تعرض إحدى السلاسل التالية: 'enabled' أو 'disabled' أو 'hidden'.

القيمة الوصف صورة
'enabled' يشير إلى أنّ العنصر نشط. خيار مفعَّل
'disabled' يشير إلى أنّ العنصر غير نشط. خيار غير مفعّل
'hidden' يخفي العنصر.

يتم أيضًا تمرير Scope إلى preconditionFn، ويمكنك استخدامها لتحديد نوع المكوّن الذي تم فتح القائمة عليه وحالة هذا المكوّن.

على سبيل المثال، قد تريد أن يظهر عنصر فقط للمربّعات، وعندما تكون هذه المربّعات في حالة معيّنة فقط:

const collapseTemplate = {
  // ...
  preconditionFn: (scope) => {
    if (scope.focusedNode instanceof Blockly.BlockSvg) {
      if (!scope.focusedNode.isCollapsed()) {
        // The component is a block and it is not already collapsed
        return 'enabled';
      } else {
        // The block is already collapsed
        return 'disabled';
      }
    }
    // The component is not a block
    return 'hidden';
  },
  // ...
}

النص الذي يظهر للمستخدم

displayText هو ما يجب عرضه للمستخدم كجزء من عنصر القائمة. يمكن أن يكون النص المعروض سلسلة أو HTML أو دالة تعرض سلسلة أو HTML.

const collapseTemplate = {
  // ...
  displayText: 'Collapse block',
  // ...
};

إذا أردت عرض ترجمة من Blockly.Msg، عليك استخدام دالة. إذا حاولت تعيين القيمة مباشرةً، قد لا يتم تحميل الرسائل وستظهر لك القيمة undefined بدلاً من ذلك.

const collapseTemplate = {
  // ...
  displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
  // ...
};

إذا كنت تستخدم دالة، يتم أيضًا تمرير القيمة Scope إليها. يمكنك استخدام هذه السمة لإضافة معلومات حول العنصر إلى النص المعروض.

const collapseTemplate = {
  // ...
  displayText: (scope) => {
    if (scope.focusedNode instanceof Blockly.Block) {
      return `Collapse ${scope.focusedNode.type} block`;
    }
    // Shouldn't be possible, as our preconditionFn only shows this item for blocks
    return '';
  },
  // ...
}

الوزن

يحدّد weight ترتيب عرض عناصر قائمة السياقات. تظهر القيم الأكثر إيجابية في أسفل القائمة مقارنةً بالقيم الأقل إيجابية. (يمكنك تخيّل أنّ العناصر ذات الأوزان الأعلى تكون "أثقل"، لذا فإنّها تغرق إلى الأسفل).

const collapseTemplate = {
  // ...
  weight: 10,
  // ...
}

تكون أوزان عناصر قائمة السياق المضمّنة بترتيب تصاعدي بدءًا من 1 وتزداد بمقدار 1.

دالّة رد الاتصال

السمة callback هي دالة تنفّذ إجراء عنصر قائمة السياق. يتم تمرير عدة معلَمات إليها:

  • scope: عنصر Scope يوفّر مرجعًا إلى المكوّن الذي تم فتح القائمة الخاصة به.
  • menuOpenEvent: Event الذي أدّى إلى فتح قائمة السياق قد يكون هذا الإجراء PointerEvent أو KeyboardEvent، وذلك حسب الطريقة التي فتح بها المستخدم القائمة.
  • menuSelectEvent: Event الذي اختار عنصر قائمة السياق هذا من القائمة. قد تكون هذه الحالة PointerEvent أو KeyboardEvent، حسب الطريقة التي اختار بها المستخدم العنصر.
  • location: Coordinate في إحداثيات البكسل حيث تم فتح القائمة. يتيح لك ذلك، على سبيل المثال، إنشاء كتلة جديدة في الموقع الجغرافي الذي تم النقر فيه.
const collapseTemplate = {
  // ...
  callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
    if (scope.focusedNode instanceof Blockly.BlockSvg) {
      scope.focusedNode.collapse();
    }
  },
}

يمكنك استخدام scope لتصميم نماذج تعمل بشكل مختلف حسب المكوّن الذي تم فتحها عليه:

const collapseTemplate = {
  // ...
  callback: (scope) => {
    if (scope.focusedNode instance of Blockly.BlockSvg) {
      // On a block, collapse just the block.
      const block = scope.focusedNode;
      block.collapse();
    } else if (scope.focusedNode instanceof Blockly.WorkspaceSvg) {
      // On a workspace, collapse all the blocks.
      let workspace = scope.focusedNode;
      collapseAllBlocks(workspace);
    }
  }
}

فاصل

ترسم السمة separator خطًا في قائمة السياقات.

لا يمكن أن تتضمّن النماذج التي تحتوي على السمة separator السمات preconditionFn أو displayText أو callback، ويمكن تحديد نطاقها باستخدام السمة scopeType فقط. ويعني القيد الأخير أنّه لا يمكن استخدامها إلا في قوائم السياق الخاصة بمساحات العمل والفقرات وتعليقات مساحة العمل.

const separatorAfterCollapseBlockTemplate = {
  id: 'separatorAfterCollapseBlock',
  scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
  weight: 11, // Between the weights of the two items you want to separate.
  separator: true,
};

تحتاج إلى نموذج مختلف لكل فاصل في قائمة الاختصارات. استخدِم السمة weight لتحديد موضع كل فاصل.

نوع النطاق

تم إيقاف سمة scopeType نهائيًا. في السابق، كان يُستخدم لتحديد ما إذا كان يجب عرض عنصر قائمة في قائمة السياق الخاصة بكتلة أو تعليق في مساحة العمل أو مساحة عمل. بما أنّه يمكن فتح قوائم السياقات على مكوّنات أخرى، فإنّ السمة scopeType مقيّدة جدًا. بدلاً من ذلك، عليك استخدام preconditionFn لعرض خيارك أو إخفائه للمكوّنات ذات الصلة.

إذا كانت لديك نماذج حالية لقائمة السياق تستخدم scopeType، سيواصل Blockly عرض العنصر للمكوّن المناسب فقط.

const collapseTemplate = {
  // ...
  scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
  // ...
};

تخصيص السجلّ

يمكنك إضافة قوالب أو حذفها أو تعديلها في السجلّ. يمكنك العثور على النماذج التلقائية في contextmenu_items.ts.

إضافة نموذج

يمكنك إضافة نموذج إلى قاعدة بيانات المسجّلين من خلال تسجيله. يجب إجراء ذلك مرة واحدة عند تحميل الصفحة. يمكن أن يحدث ذلك قبل أو بعد إدخال مساحة العمل.

const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);

حذف نموذج

يمكنك إزالة نموذج من السجلّ عن طريق إلغاء تسجيله باستخدام رقم التعريف.

Blockly.ContextMenuRegistry.registry.unregister('someID');

تعديل نموذج

يمكنك تعديل نموذج حالي من خلال الحصول عليه من السجلّ ثم تعديله في مكانه.

const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';

إيقاف قوائم السياقات الخاصة بالحظر

تتضمّن مربّعات الحظر تلقائيًا قائمة سياق تتيح للمستخدمين تنفيذ إجراءات مثل إضافة تعليقات إلى مربّعات الحظر أو تكرارها.

يمكنك إيقاف قائمة السياق لكتلة فردية من خلال اتّباع الخطوات التالية:

block.contextMenu = false;

في تعريف JSON لنوع الحظر، استخدِم المفتاح enableContextMenu:

{
  // ...,
  "enableContextMenu": false,
}

تخصيص قوائم السياق لكل نوع من أنواع البلوكات أو مساحة العمل

بعد أن تنشئ Blockly مصفوفة من عناصر قائمة السياق، يمكنك تخصيصها للمربّعات الفردية أو مساحات العمل. لإجراء ذلك، اضبط BlockSvg.customContextMenu أو WorkspaceSvg.configureContextMenu على دالة تعدّل الصفيف في مكانه.

تكون أنواع العناصر في المصفوفة التي يتم تمريرها إلى الكتل البرمجية ContextMenuOption أو تنفّذ الواجهة LegacyContextMenuOption. تكون الكائنات التي يتم تمريرها إلى مساحات العمل من النوع ContextMenuOption. يستخدم Blockly الخصائص التالية من هذه العناصر:

  • text: النص المعروض
  • enabled: إذا كانت القيمة false، اعرض السلعة بنص رمادي.
  • callback: الدالة التي سيتم استدعاؤها عند النقر على العنصر.
  • separator: السلعة هي فاصل. تتجاهل هذه السمة السمات الثلاث الأخرى.

راجِع المستندات المرجعية لأنواع المواقع وتوقيعات الدوال.

على سبيل المثال، إليك دالة تضيف عنصر Hello, World! إلى قائمة السياق الخاصة بمساحة عمل:

workspace.configureContextMenu = function (menuOptions, e) {
  const item = {
    text: 'Hello, World!',
    enabled: true,
    callback: function () {
      alert('Hello, World!');
    },
  };
  // Add the item to the end of the context menu.
  menuOptions.push(item);
}

عرض قائمة سياق على عنصر مخصّص

يمكنك إظهار قوائم السياق للمكوّنات المخصّصة باتّباع الخطوات التالية:

  1. نفِّذ IFocusableNode أو وسِّع فئة تنفِّذ IFocusableNode. يتم استخدام هذه الواجهة في نظام قائمة السياق من أجل تحديد المكوّن. ويسمح أيضًا للمستخدمين بالانتقال إلى المكوّن باستخدام المكوّن الإضافي للتنقّل باستخدام لوحة المفاتيح.
  2. نفِّذ IContextMenu الذي يحتوي على الدالة showContextMenu. تحصل هذه الدالة على عناصر قائمة السياق من السجل، وتحسب الموقع الجغرافي على الشاشة الذي سيتم عرض القائمة فيه، ثم تعرض القائمة إذا كان هناك أي عناصر لعرضها.

    const MyBubble implements IFocusableNode, IContextMenu {
      ...
      showContextMenu(menuOpenEvent) {
        // Get the items from the context menu registry
        const scope = {focusedNode: this};
        const items = Blockly.ContextMenuRegistry.registry.getContextMenuOptions(scope, menuOpenEvent);
    
        // Return early if there are no items available
        if (!items.length) return;
    
        // Show the menu at the same location on screen as this component
        // The location is in pixel coordinates, so translate from workspace coordinates
        const location = Blockly.utils.svgMath.wsToScreenCoordinates(new Coordinate(this.x, this.y));
    
        // Show the context menu
        Blockly.ContextMenu.show(menuOpenEvent, items, this.workspace.RTL, this.workspace, location);
      }
    }
    
  3. أضِف معالج أحداث يستدعي showContextMenu عندما ينقر المستخدم بزر الماوس الأيمن على المكوّن. يُرجى العِلم أنّ مكوّن التنقّل باستخدام لوحة المفاتيح الإضافي يوفّر معالج أحداث يستدعي showContextMenu عندما يضغط المستخدم على Ctrl+Enter (في نظام التشغيل Windows) أو Command+Enter (في نظام التشغيل Mac).

  4. أضِف نماذج إلى السجلّ لعناصر قائمة السياق.