Menu konteks

Menu konteks berisi daftar tindakan yang dapat dilakukan pengguna pada komponen seperti ruang kerja, blok, atau komentar ruang kerja. Menu konteks ditampilkan sebagai respons terhadap klik kanan atau tekan lama pada perangkat sentuh. Jika Anda menggunakan plugin @blockly/keyboard-navigation, plugin tersebut juga ditampilkan dengan pintasan keyboard, yang secara default adalah Ctrl+Enter di Windows atau Command+Enter di Mac.

Menu konteks default untuk blok

Menu konteks adalah tempat yang tepat untuk menambahkan tindakan yang jarang dilakukan pengguna, seperti mendownload screenshot. Jika Anda merasa suatu tindakan akan lebih sering digunakan, Anda mungkin ingin membuat cara yang lebih mudah ditemukan untuk memanggilnya.

Menu konteks didukung oleh ruang kerja, blok, komentar ruang kerja, balon, dan koneksi. Anda juga dapat menerapkannya pada komponen kustom Anda sendiri. Blockly menyediakan menu konteks standar yang dapat Anda sesuaikan. Anda juga dapat menyesuaikan menu konteks di ruang kerja dan blok berdasarkan per ruang kerja atau per blok.

Cara kerja menu konteks

Blockly memiliki registri yang berisi template untuk semua kemungkinan item menu. Setiap template menjelaskan cara membuat satu item dalam menu konteks. Saat pengguna memanggil menu konteks pada komponen, komponen:

  1. Meminta konstruksi registry membuat array item menu yang berlaku untuk komponen. Registry akan menanyakan kepada setiap template apakah template tersebut berlaku untuk komponen dan, jika ya, akan menambahkan item menu yang sesuai ke array.

  2. Jika komponen adalah ruang kerja atau blok, periksa apakah ruang kerja atau blok tertentu tempat menu dipanggil memiliki fungsi untuk menyesuaikan menu konteks. Jika demikian, array akan diteruskan ke fungsi, yang dapat menambahkan, menghapus, atau mengubah elemen array.

  3. Menampilkan menu konteks menggunakan array item menu konteks (yang mungkin telah diubah).

Blockly menentukan serangkaian template standar untuk menu konteks bagi ruang kerja, blok, dan komentar ruang kerja. Plugin ini memuat sebelumnya template untuk ruang kerja dan blok ke dalam registry. Jika ingin menggunakan template untuk komentar ruang kerja, Anda harus memuatnya ke dalam registri sendiri.

Untuk mengetahui informasi tentang cara menambahkan, menghapus, dan mengubah template di registry, lihat Menyesuaikan registry.

Cakupan

Menu konteks diimplementasikan oleh berbagai jenis komponen, termasuk ruang kerja, komentar ruang kerja, koneksi, blok, balon, dan komponen kustom Anda sendiri. Menu konteks untuk setiap jenis komponen ini dapat berisi item yang berbeda, dan item dapat berperilaku berbeda berdasarkan jenis komponen. Oleh karena itu, sistem menu konteks perlu mengetahui komponen mana yang memanggilnya.

Untuk mengatasi hal ini, registri menggunakan objek Scope. Komponen tempat menu konteks dipanggil disimpan dalam properti focusedNode sebagai objek yang mengimplementasikan IFocusableNode. (IFocusableNode diterapkan oleh semua komponen yang dapat difokuskan pengguna, termasuk yang menerapkan menu konteks. Untuk mengetahui informasi selengkapnya, lihat Sistem fokus.)

Objek Scope diteruskan ke beberapa fungsi dalam template. Dalam fungsi apa pun yang mendapatkan objek Scope, Anda dapat memutuskan tindakan yang akan dilakukan berdasarkan jenis objek dalam properti focusedNode. Misalnya, Anda dapat memeriksa apakah komponen adalah blok dengan:

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

Objek Scope memiliki properti opsional lain yang tidak lagi direkomendasikan untuk digunakan, tetapi masih dapat ditetapkan:

  • block hanya disetel jika komponen yang menunya ditampilkan adalah BlockSvg.
  • workspace hanya ditetapkan jika komponennya adalah WorkspaceSvg.
  • comment hanya ditetapkan jika komponennya adalah RenderedWorkspaceComment.

Properti ini tidak mencakup semua jenis komponen yang mungkin memiliki menu konteks, jadi sebaiknya gunakan properti focusedNode.

Jenis RegistryItem

Template memiliki jenis ContextMenuRegistry.RegistryItem, yang berisi properti berikut. Perhatikan bahwa properti preconditionFn, displayText, dan callback tidak dapat terjadi bersamaan dengan properti separator.

ID

Properti id harus berupa string unik yang menunjukkan fungsi item menu konteks Anda.

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

Fungsi prasyarat

Anda dapat menggunakan preconditionFn untuk membatasi kapan dan bagaimana item menu konteks harus ditampilkan.

Metode ini harus menampilkan salah satu dari serangkaian string: 'enabled', 'disabled', atau 'hidden'.

Nilai Deskripsi Gambar
'enabled' Menunjukkan bahwa item aktif. Opsi yang diaktifkan
'disabled' Menunjukkan bahwa item tidak aktif. Opsi yang dinonaktifkan
'hidden' Menyembunyikan item.

preconditionFn juga meneruskan Scope yang dapat Anda gunakan untuk menentukan jenis komponen tempat menu dibuka dan status komponen tersebut.

Misalnya, Anda mungkin ingin item hanya muncul untuk blok, dan hanya saat blok tersebut dalam status tertentu:

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

Teks tampilan

displayText adalah yang harus ditampilkan kepada pengguna sebagai bagian dari item menu. Teks tampilan dapat berupa string, atau HTML, atau fungsi yang menampilkan string atau HTML.

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

Jika Anda ingin menampilkan terjemahan dari Blockly.Msg, Anda harus menggunakan fungsi. Jika Anda mencoba menetapkan nilai secara langsung, pesan mungkin tidak dimuat dan Anda akan mendapatkan nilai undefined.

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

Jika Anda menggunakan fungsi, fungsi tersebut juga akan meneruskan nilai Scope. Anda dapat menggunakan ini untuk menambahkan informasi tentang elemen ke teks tampilan.

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

Berat

weight menentukan urutan item menu konteks ditampilkan. Nilai yang lebih positif ditampilkan lebih rendah dalam daftar daripada nilai yang kurang positif. (Anda dapat membayangkan bahwa item dengan bobot yang lebih tinggi "lebih berat" sehingga tenggelam ke bagian bawah.)

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

Bobot untuk item menu konteks bawaan diurutkan dalam urutan menaik, dimulai dari 1 dan bertambah 1.

Fungsi callback

Properti callback adalah fungsi yang melakukan tindakan item menu konteks Anda. Fungsi ini meneruskan beberapa parameter:

  • scope: Objek Scope yang memberikan referensi ke komponen yang menunya dibuka.
  • menuOpenEvent: Event yang memicu pembukaan menu konteks. Ini dapat berupa PointerEvent atau KeyboardEvent, bergantung pada cara pengguna membuka menu.
  • menuSelectEvent: Event yang memilih item menu konteks tertentu ini dari menu. Ini dapat berupa PointerEvent atau KeyboardEvent, bergantung pada cara pengguna memilih item.
  • location: Coordinate dalam koordinat piksel tempat menu dibuka. Dengan demikian, Anda dapat, misalnya, membuat blok baru di lokasi klik.
const collapseTemplate = {
  // ...
  callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
    if (scope.focusedNode instanceof Blockly.BlockSvg) {
      scope.focusedNode.collapse();
    }
  },
}

Anda dapat menggunakan scope untuk mendesain template yang berfungsi secara berbeda, bergantung pada komponen tempat template tersebut dibuka:

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

Pemisah

Properti separator menggambar garis di menu konteks.

Template dengan properti separator tidak boleh memiliki properti preconditionFn, displayText, atau callback dan hanya dapat dicakup dengan properti scopeType. Pembatasan terakhir berarti mereka hanya dapat digunakan di menu konteks untuk ruang kerja, blok, dan komentar ruang kerja.

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

Anda memerlukan template yang berbeda untuk setiap pemisah di menu konteks. Gunakan properti weight untuk memosisikan setiap pemisah.

Jenis cakupan

Properti scopeType tidak digunakan lagi. Sebelumnya, opsi ini digunakan untuk menentukan apakah item menu harus ditampilkan di menu konteks untuk blok, komentar ruang kerja, atau ruang kerja. Karena menu konteks dapat dibuka di komponen lain, properti scopeType terlalu membatasi. Sebagai gantinya, Anda harus menggunakan preconditionFn untuk menampilkan atau menyembunyikan opsi untuk komponen yang sesuai.

Jika Anda memiliki template menu konteks yang sudah ada dan menggunakan scopeType, Blockly akan terus menampilkan item hanya untuk komponen yang sesuai.

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

Menyesuaikan registri

Anda dapat menambahkan, menghapus, atau mengubah template di registri. Anda dapat menemukan template default di contextmenu_items.ts.

Menambahkan template

Anda dapat menambahkan template ke registry dengan mendaftarkannya. Anda harus melakukannya sekali saat pemuatan halaman. Hal ini dapat terjadi sebelum atau setelah Anda menyuntikkan ruang kerja.

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

Menghapus template

Anda dapat menghapus template dari registri dengan membatalkan pendaftarannya menurut ID.

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

Mengubah template

Anda dapat mengubah template yang ada dengan mengambil template dari registry lalu mengubahnya di tempat.

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

Nonaktifkan menu konteks pemblokiran

Secara default, blok memiliki menu konteks yang memungkinkan pengguna melakukan hal-hal seperti menambahkan komentar blok atau menduplikasi blok.

Anda dapat menonaktifkan menu konteks setiap blok dengan melakukan:

block.contextMenu = false;

Dalam definisi JSON jenis blok, gunakan kunci enableContextMenu:

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

Menyesuaikan menu konteks per jenis blok atau ruang kerja

Setelah Blockly membuat array item menu konteks, Anda dapat menyesuaikannya untuk setiap blok atau ruang kerja. Untuk melakukannya, tetapkan BlockSvg.customContextMenu atau WorkspaceSvg.configureContextMenu ke fungsi yang mengubah array di tempat.

Objek dalam array yang diteruskan ke blok memiliki jenis ContextMenuOption atau mengimplementasikan antarmuka LegacyContextMenuOption. Objek yang diteruskan ke ruang kerja memiliki jenis ContextMenuOption. Blockly menggunakan properti berikut dari objek ini:

  • text: Teks tampilan.
  • enabled: Jika false, tampilkan item dengan teks berwarna abu-abu.
  • callback: Fungsi yang akan dipanggil saat item diklik.
  • separator: Item adalah pemisah. Tidak dapat muncul bersamaan dengan tiga properti lainnya.

Lihat dokumentasi referensi untuk jenis properti dan tanda tangan fungsi.

Misalnya, berikut adalah fungsi yang menambahkan item Hello, World! ke menu konteks ruang kerja:

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

Menampilkan menu konteks pada objek kustom

Anda dapat membuat menu konteks muncul untuk komponen kustom dengan mengikuti langkah-langkah berikut:

  1. Terapkan IFocusableNode atau perluas class yang menerapkan IFocusableNode. Antarmuka ini digunakan dalam sistem menu konteks untuk mengidentifikasi komponen Anda. Hal ini juga memungkinkan pengguna menavigasi ke komponen Anda menggunakan plugin navigasi keyboard.
  2. Implementasikan IContextMenu, yang berisi fungsi showContextMenu. Fungsi ini mendapatkan item menu konteks dari registri, menghitung lokasi di layar tempat menu akan ditampilkan, dan akhirnya menampilkan menu jika ada item yang akan ditampilkan.

    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. Tambahkan pengendali peristiwa yang memanggil showContextMenu saat pengguna mengklik kanan komponen Anda. Perhatikan bahwa plugin navigasi keyboard menyediakan pengendali peristiwa yang memanggil showContextMenu saat pengguna menekan Ctrl+Enter (Windows) atau Command+Enter (Mac).

  4. Tambahkan template ke registry untuk item menu konteks Anda.