منوهای زمینه

منوی زمینه شامل فهرستی از اقداماتی است که کاربر می‌تواند روی یک جزء مانند فضای کاری، بلوک یا نظر فضای کاری انجام دهد. منوی زمینه در پاسخ به کلیک راست یا فشار طولانی روی دستگاه لمسی نشان داده می‌شود. اگر از افزونه @blockly/keyboard-navigation استفاده می‌کنید، با یک میانبر صفحه کلید نیز نشان داده می‌شود که به طور پیش‌فرض Ctrl+Enter در ویندوز یا Command+Enter در مک است.

منوی زمینه پیش‌فرض برای یک بلوک

منوهای زمینه مکان مناسبی برای اضافه کردن اقداماتی هستند که کاربر به ندرت انجام می‌دهد، مانند دانلود اسکرین‌شات. اگر فکر می‌کنید یک اقدام بیشتر مورد استفاده قرار می‌گیرد، ممکن است بخواهید روشی قابل کشف‌تر برای فراخوانی آن ایجاد کنید.

منوهای زمینه توسط فضاهای کاری، بلوک‌ها، نظرات فضای کاری، حباب‌ها و اتصالات پشتیبانی می‌شوند. همچنین می‌توانید آنها را روی اجزای سفارشی خود پیاده‌سازی کنید . Blockly منوهای زمینه استانداردی را ارائه می‌دهد که می‌توانید آنها را سفارشی کنید. همچنین می‌توانید منوهای زمینه را در فضاهای کاری و بلوک‌ها بر اساس هر فضای کاری یا هر بلوک سفارشی کنید.

نحوه کار منوهای زمینه

Blockly یک رجیستری دارد که شامل قالب‌هایی برای همه آیتم‌های منوی ممکن است. هر قالب نحوه ساخت یک آیتم واحد در یک منوی زمینه را شرح می‌دهد. وقتی کاربر یک منوی زمینه را روی یک کامپوننت فراخوانی می‌کند، کامپوننت:

  1. از رجیستری می‌پرسد که آیا آرایه‌ای از آیتم‌های منو که به کامپوننت اعمال می‌شوند، در ساختار آن وجود دارد یا خیر. رجیستری از هر الگو می‌پرسد که آیا به کامپوننت اعمال می‌شود یا خیر و در صورت اعمال، یک آیتم منوی مربوطه را به آرایه اضافه می‌کند.

  2. اگر کامپوننت یک فضای کاری یا بلوک باشد، بررسی می‌کند که آیا فضای کاری یا بلوک خاصی که منو در آن فراخوانی شده است ، تابعی برای سفارشی‌سازی منوی زمینه دارد یا خیر. در این صورت، آرایه را به تابع ارسال می‌کند که می‌تواند عناصر آرایه را اضافه، حذف یا تغییر دهد.

  3. Displays the context menu using the (possibly modified) array of context menu items.

Blockly مجموعه‌ای استاندارد از قالب‌ها را برای منوهای زمینه برای فضاهای کاری، بلوک‌ها و نظرات فضای کاری تعریف می‌کند. این ابزار قالب‌های فضاهای کاری و بلوک‌ها را از قبل در رجیستری بارگذاری می‌کند. اگر می‌خواهید از قالب‌ها برای نظرات فضای کاری استفاده کنید، باید خودتان آنها را در رجیستری بارگذاری کنید .

For information on how to add, delete, and modify templates in the registry, see Customize the registry .

محدوده

منوهای زمینه توسط انواع مختلفی از کامپوننت‌ها، از جمله فضاهای کاری، کامنت‌های فضای کاری، اتصالات، بلوک‌ها، حباب‌ها و کامپوننت‌های سفارشی شما پیاده‌سازی می‌شوند. منوهای زمینه برای هر یک از این انواع کامپوننت ممکن است شامل موارد مختلفی باشند و آیتم‌ها ممکن است بسته به نوع کامپوننت، رفتار متفاوتی داشته باشند. بنابراین، سیستم منوی زمینه باید بداند که در کدام کامپوننت فراخوانی شده است.

برای رفع این مشکل، رجیستری از یک شیء Scope استفاده می‌کند. کامپوننتی که منوی زمینه در آن فراخوانی شده است، در ویژگی focusedNode به عنوان شیء‌ای که IFocusableNode پیاده‌سازی می‌کند، ذخیره می‌شود. ( IFocusableNode توسط تمام کامپوننت‌هایی که کاربران می‌توانند روی آنها تمرکز کنند، از جمله آن‌هایی که منوهای زمینه را پیاده‌سازی می‌کنند، پیاده‌سازی می‌شود. برای اطلاعات بیشتر، به Focus system مراجعه کنید.)

شیء Scope به چندین تابع در یک قالب ارسال می‌شود. در هر تابعی که یک شیء Scope دریافت می‌کند، می‌توانید بر اساس نوع شیء در ویژگی focusedNode تصمیم بگیرید که چه کاری انجام دهید. برای مثال، می‌توانید با استفاده از موارد زیر بررسی کنید که آیا کامپوننت یک بلوک است یا خیر:

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

The Scope object has other optional properties that are no longer recommended for use, but may still be set:

  • block is set only if the component whose menu is shown is a BlockSvg .
  • workspace is set only if the component is a WorkspaceSvg .
  • comment is set only if the component is a RenderedWorkspaceComment .

These properties don't cover all types of components that may have a context menu, so you should prefer to use the focusedNode property.

نوع RegistryItem

قالب‌ها از نوع ContextMenuRegistry.RegistryItem هستند که شامل ویژگی‌های زیر است. توجه داشته باشید که ویژگی‌های preconditionFn ، displayText و callback با ویژگی separator ناسازگار هستند.

شناسه

The id property should be a unique string that indicates what your context menu item does.

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

تابع پیش‌شرط

You can use the preconditionFn to restrict when and how a context menu item should be displayed.

It should return one of a set of strings: 'enabled' , 'disabled' , or 'hidden' .

ارزش توضیحات تصویر
'enabled' نشان می‌دهد که مورد فعال است. یک گزینه فعال
'disabled' نشان می‌دهد که مورد فعال نیست. یک گزینه غیرفعال
'hidden' مورد را پنهان می‌کند.

The preconditionFn is also passed a Scope which you can use to determine what type of component the menu was opened on and the state of that component.

For example, you may want an item to only appear for blocks, and only when those blocks are in a particular state:

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';
  },
  // ...
}

نمایش متن

The displayText is what should be shown to the user as part of the menu item. The display text can be a string, or HTML, or a function that returns either a string or HTML.

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

اگر می‌خواهید ترجمه‌ای از Blockly.Msg نمایش دهید، باید از یک تابع استفاده کنید. اگر سعی کنید مقدار را مستقیماً اختصاص دهید، ممکن است پیام‌ها بارگیری نشوند و به جای آن مقدار undefined را دریافت کنید.

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

If you use a function, it is also passed a Scope value. You can use this to add information about the element to your display text.

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,
  // ...
}

Weights for the built-in context menu items go in increasing order starting at 1 and increasing by 1.

تابع فراخوانی

The callback property is a function that performs the action of your context menu item. It is passed several parameters:

  • scope : A Scope object that provides a reference to the component having its menu opened.
  • 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);
    }
  }
}

جداکننده

The separator property draws a line in the context menu.

قالب‌هایی که دارای ویژگی 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,
};

You need a different template for each separator in your context menu. Use the weight property to position each separator.

نوع محدوده

ویژگی scopeType منسوخ شده است. پیش از این، از آن برای تعیین اینکه آیا یک آیتم منو باید در منوی زمینه برای یک بلوک، یک نظر در فضای کاری یا یک فضای کاری نمایش داده شود، استفاده می‌شد. از آنجایی که منوهای زمینه می‌توانند در سایر اجزا باز شوند، ویژگی scopeType بسیار محدودکننده است. در عوض، شما باید از preconditionFn برای نمایش یا پنهان کردن گزینه خود برای اجزای مربوطه استفاده کنید.

اگر قالب‌های منوی زمینه‌ی موجود دارید که از scopeType استفاده می‌کنند، Blockly به نمایش آیتم فقط برای کامپوننت مربوطه ادامه خواهد داد.

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

سفارشی سازی رجیستری

You can add, delete, or modify templates in the registry. You can find the default templates in contextmenu_items.ts .

اضافه کردن الگو

You can add a template to the registry by registering it. You should do this once on page load. It can happen before or after you inject your workspace.

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

حذف یک الگو

You can remove a template from the registry by unregistering it by ID.

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

اصلاح یک الگو

You can modify an existing template by getting the template from the registry and then modifying it in-place.

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

غیرفعال کردن منوهای زمینه بلوک

به طور پیش‌فرض، بلوک‌ها دارای یک منوی زمینه هستند که به کاربران امکان می‌دهد کارهایی مانند اضافه کردن نظرات به بلوک یا کپی کردن بلوک‌ها را انجام دهند.

شما می‌توانید منوی زمینه یک بلوک را با انجام مراحل زیر غیرفعال کنید:

block.contextMenu = false;

In the JSON definition of a block type, use the enableContextMenu key:

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

Customize context menus per block type or workspace

پس از اینکه Blockly آرایه‌ای از آیتم‌های منوی زمینه را ایجاد کرد ، می‌توانید آن را برای بلوک‌ها یا فضاهای کاری جداگانه سفارشی کنید. برای انجام این کار، BlockSvg.customContextMenu یا WorkspaceSvg.configureContextMenu را روی تابعی تنظیم کنید که آرایه را در محل تغییر دهد.

اشیاء موجود در آرایه که به بلوک‌ها ارسال می‌شوند، از نوع ContextMenuOption هستند یا رابط LegacyContextMenuOption را پیاده‌سازی می‌کنند. اشیاء ارسال شده به فضاهای کاری از نوع ContextMenuOption هستند. Blockly از ویژگی‌های زیر از این اشیاء استفاده می‌کند:

  • text : متن نمایشی.
  • enabled : If false , display the item with grey text.
  • 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 فراخوانی کند. توجه داشته باشید که افزونه ناوبری صفحه‌کلید یک کنترل‌کننده رویداد ارائه می‌دهد که وقتی کاربر Ctrl+Enter (ویندوز) یا Command+Enter (مک) را فشار می‌دهد، showContextMenu را فراخوانی می‌کند.

  4. برای موارد منوی زمینه خود، قالب‌هایی را به رجیستری اضافه کنید .