منوهای زمینه

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

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

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

منوهای زمینه توسط فضاهای کاری، بلوک ها، نظرات فضای کاری، حباب ها و اتصالات پشتیبانی می شوند. شما همچنین می توانید آنها را بر روی اجزای سفارشی خود پیاده سازی کنید . 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 باید یک رشته منحصر به فرد باشد که نشان می دهد آیتم منوی زمینه شما چه کاری انجام می دهد.

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

تابع پیش شرط

می توانید از preconditionFn برای محدود کردن زمان و نحوه نمایش آیتم های منوی زمینه استفاده کنید.

باید یکی از مجموعه‌ای از رشته‌ها را برگرداند: 'enabled' ، 'disabled' یا 'hidden' .

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

به preconditionFn نیز یک Scope ارسال می شود که می توانید از آن برای تعیین نوع مؤلفه ای که منو روی آن باز شده و وضعیت آن مؤلفه استفاده کنید.

به عنوان مثال، ممکن است بخواهید یک آیتم فقط برای بلوک ها ظاهر شود و فقط زمانی که آن بلوک ها در یک وضعیت خاص هستند:

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);

یک الگو را حذف کنید

با لغو ثبت آن توسط ID می توانید یک الگو را از رجیستری حذف کنید.

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 را فراخوانی می کند. توجه داشته باشید که پلاگین پیمایش صفحه کلید یک کنترل کننده رویداد ارائه می دهد که وقتی کاربر Ctrl+Enter (ویندوز) یا Command+Enter (Mac) را فشار می دهد showContextMenu را فراخوانی می کند.

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