Bağlam menüleri

Bağlam menüsünde, kullanıcının bir bileşende (ör. çalışma alanı, blok veya çalışma alanı yorumu) gerçekleştirebileceği işlemlerin listesi yer alır. İçerik menüsü, sağ tıklama veya dokunmatik cihazda uzun basma işlemine yanıt olarak gösterilir. @blockly/keyboard-navigation eklentisini kullanıyorsanız bu eklenti de klavye kısayoluyla gösterilir. Bu kısayol, Windows'da varsayılan olarak Ctrl+Enter, Mac'te ise Command+Enter olarak ayarlanır.

Bir blok için varsayılan içerik menüsü

Bağlam menüleri, kullanıcının nadiren gerçekleştirdiği işlemleri (ör. ekran görüntüsü indirme) eklemek için iyi bir yerdir. Bir işlemin daha yaygın olarak kullanılacağını düşünüyorsanız bu işlemi çağırmak için daha kolay bulunabilir bir yöntem oluşturabilirsiniz.

İçerik menüleri çalışma alanları, bloklar, çalışma alanı yorumları, balonlar ve bağlantılar tarafından desteklenir. Ayrıca kendi özel bileşenlerinizde de uygulayabilirsiniz. Blockly, özelleştirebileceğiniz standart bağlam menüleri sağlar. Ayrıca, çalışma alanlarındaki ve bloklardaki bağlam menülerini çalışma alanı veya blok bazında özelleştirebilirsiniz.

İçerik menülerinin işleyiş şekli

Blockly'de, olası tüm menü öğelerinin şablonlarını içeren bir kayıt defteri bulunur. Her şablon, bağlam menüsünde tek bir öğenin nasıl oluşturulacağını açıklar. Kullanıcı bir bileşende içerik menüsünü çağırdığında bileşen:

  1. Kayıt defterinden, bileşen için geçerli olan bir menü öğeleri dizisi oluşturmasını ister. Kayıt defteri, her şablona bileşen için geçerli olup olmadığını sorar ve geçerliyse diziye ilgili menü öğesini ekler.

  2. Bileşen bir çalışma alanı veya bloksa menünün çağrıldığı çalışma alanında ya da blokta bağlam menüsünü özelleştirme işlevi olup olmadığını kontrol eder. Bu durumda, diziyi işlevine iletir. İşlev, dizinin öğelerini ekleyebilir, silebilir veya değiştirebilir.

  3. İçerik menüsü öğelerinin (muhtemelen değiştirilmiş) dizisini kullanarak içerik menüsünü görüntüler.

Blockly, çalışma alanları, bloklar ve çalışma alanı yorumları için bağlam menülerine yönelik standart bir şablon grubu tanımlar. Çalışma alanları ve bloklarla ilgili şablonları kayıt defterine önceden yükler. Çalışma alanı yorumları için şablonları kullanmak istiyorsanız şablonları kayıt defterine kendiniz yüklemeniz gerekir.

Kayıt defterine şablon ekleme, şablon silme ve şablon değiştirme hakkında bilgi edinmek için Kayıt defterini özelleştirme başlıklı makaleyi inceleyin.

Kapsam

İçerik menüleri; çalışma alanları, çalışma alanı yorumları, bağlantılar, bloklar, balonlar ve kendi özel bileşenleriniz dahil olmak üzere farklı bileşen türleri tarafından uygulanır. Bu bileşen türlerinin her birine ait içerik menüleri farklı öğeler içerebilir ve öğeler, bileşen türüne bağlı olarak farklı şekilde davranabilir. Bu nedenle, içerik menüsü sisteminin hangi bileşende çağrıldığını bilmesi gerekir.

Bu sorunu çözmek için kayıt defteri Scope nesnesini kullanır. Bağlam menüsünün çağrıldığı bileşen, focusedNode özelliğinde IFocusableNode uygulayan bir nesne olarak depolanır. (IFocusableNode, bağlam menülerini uygulayanlar da dahil olmak üzere kullanıcıların odaklanabileceği tüm bileşenler tarafından uygulanır. Daha fazla bilgi için Odaklanma sistemi başlıklı makaleyi inceleyin.)

Scope nesnesi, şablondaki işlevlerin birçoğuna iletilir. Scope nesnesi alan herhangi bir işlevde, focusedNode özelliğindeki nesnenin türüne göre ne yapacağınıza karar verebilirsiniz. Örneğin, bileşenin aşağıdakileri içeren bir blok olup olmadığını kontrol edebilirsiniz:

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

Scope nesnesinin, artık kullanılması önerilmeyen ancak yine de ayarlanabilen başka isteğe bağlı özellikleri vardır:

  • block yalnızca menüsü gösterilen bileşen bir BlockSvg ise ayarlanır.
  • workspace yalnızca bileşen bir WorkspaceSvg ise ayarlanır.
  • comment yalnızca bileşen bir RenderedWorkspaceComment ise ayarlanır.

Bu özellikler, bağlam menüsü olabilecek tüm bileşen türlerini kapsamaz. Bu nedenle focusedNode özelliğini kullanmanız önerilir.

RegistryItem türü

Şablonlar, aşağıdaki özellikleri içeren ContextMenuRegistry.RegistryItem türündedir. preconditionFn, displayText ve callback özelliklerinin separator özelliğiyle aynı anda kullanılamadığını unutmayın.

Kimlik

id özelliği, bağlam menüsü öğenizin ne yaptığını gösteren benzersiz bir dize olmalıdır.

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

Ön koşul işlevi

Bir içerik menüsü öğesinin ne zaman ve nasıl gösterileceğini kısıtlamak için preconditionFn öğesini kullanabilirsiniz.

'enabled', 'disabled' veya 'hidden' gibi bir dizi dizeden birini döndürmelidir.

Değer Açıklama Resim
'enabled' Öğenin etkin olduğunu gösterir. Etkinleştirilmiş bir seçenek
'disabled' Öğenin etkin olmadığını gösterir. Devre dışı bırakılmış bir seçenek
'hidden' Öğeyi gizler.

preconditionFn işlevine, menünün hangi tür bileşende açıldığını ve bu bileşenin durumunu belirlemek için kullanabileceğiniz bir Scope de iletilir.

Örneğin, bir öğenin yalnızca bloklar için ve yalnızca bu bloklar belirli bir durumdayken görünmesini isteyebilirsiniz:

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

Görünen metin

displayText, menü öğesinin bir parçası olarak kullanıcıya gösterilmesi gereken öğedir. Görünen metin bir dize, HTML veya dize ya da HTML döndüren bir işlev olabilir.

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

Blockly.Msg kaynağından çeviri göstermek istiyorsanız bir işlev kullanmanız gerekir. Değeri doğrudan atamaya çalışırsanız mesajlar yüklenmeyebilir ve bunun yerine undefined değeri gösterilir.

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

Bir işlev kullanırsanız bu işlev de Scope değerini alır. Bunu, öğe hakkında bilgileri görünen metninize eklemek için kullanabilirsiniz.

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

Ağırlık

weight, içerik menüsü öğelerinin gösterilme sırasını belirler. Daha pozitif değerler, listede daha az pozitif değerlerden daha aşağıda gösterilir. (Daha yüksek ağırlığa sahip öğelerin "daha ağır" olduğunu ve bu nedenle en alta battığını düşünebilirsiniz.)

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

Yerleşik içerik menüsü öğelerinin ağırlıkları 1'den başlayarak 1'er artan sırada verilir.

Geri çağırma işlevi

callback özelliği, bağlam menüsü öğenizin işlemini gerçekleştiren bir işlevdir. Birkaç parametre iletilir:

  • scope: Menüsü açılan bileşene referans sağlayan bir Scope nesnesi.
  • menuOpenEvent: İçerik menüsünün açılmasını tetikleyen Event. Bu, kullanıcının menüyü nasıl açtığına bağlı olarak PointerEvent veya KeyboardEvent olabilir.
  • menuSelectEvent: Menüden bu bağlam menüsü öğesini seçen Event. Bu, kullanıcının öğeyi nasıl seçtiğine bağlı olarak PointerEvent veya KeyboardEvent olabilir.
  • location: Menünün açıldığı piksel koordinatlarında Coordinate. Bu sayede, örneğin tıklama konumunda yeni bir blok oluşturabilirsiniz.
const collapseTemplate = {
  // ...
  callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
    if (scope.focusedNode instanceof Blockly.BlockSvg) {
      scope.focusedNode.collapse();
    }
  },
}

scope kullanarak, açıldıkları bileşene bağlı olarak farklı şekilde çalışan şablonlar tasarlayabilirsiniz:

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

Ayırıcı

separator özelliği, içerik menüsünde bir çizgi çizer.

separator özelliği içeren şablonlarda preconditionFn, displayText veya callback özellikleri bulunamaz ve yalnızca scopeType özelliğiyle kapsamlandırılabilir. Bu kısıtlama, bu emojilerin yalnızca çalışma alanları, bloklar ve çalışma alanı yorumları için bağlam menülerinde kullanılabileceği anlamına gelir.

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

Bağlam menünüzdeki her ayırıcı için farklı bir şablona ihtiyacınız vardır. Her ayırıcıyı konumlandırmak için weight özelliğini kullanın.

Kapsam türü

scopeType özelliğinin desteği sonlandırıldı. Daha önce, bir menü öğesinin blok, çalışma alanı yorumu veya çalışma alanı için içerik menüsünde gösterilip gösterilmeyeceğini belirlemek için kullanılıyordu. Bağlam menüleri diğer bileşenlerde açılabildiğinden scopeType özelliği çok kısıtlayıcıdır. Bunun yerine, ilgili bileşenler için seçeneğinizi göstermek veya gizlemek üzere preconditionFn kullanmanız gerekir.

scopeType kullanan mevcut içerik menüsü şablonlarınız varsa Blockly, öğeyi yalnızca uygun bileşen için göstermeye devam eder.

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

Kayıt defterini özelleştirme

Kayıt defterine şablon ekleyebilir, şablonları silebilir veya değiştirebilirsiniz. Varsayılan şablonları contextmenu_items.ts bölümünde bulabilirsiniz.

Şablon ekleme

Bir şablonu kaydederek kayıt defterine ekleyebilirsiniz. Bu işlemi sayfa yüklendiğinde bir kez yapmanız gerekir. Bu durum, çalışma alanınızı eklemeden önce veya ekledikten sonra gerçekleşebilir.

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

Şablon silme

Bir şablonu kimliğine göre kaydını silerek kayıt defterinden kaldırabilirsiniz.

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

Şablonu değiştirme

Kayıt defterinden alıp yerinde değiştirerek mevcut bir şablonu değiştirebilirsiniz.

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

İçerik menülerinin engellenmesini devre dışı bırakma

Varsayılan olarak bloklarda, kullanıcıların blok yorumları ekleme veya blokları çoğaltma gibi işlemler yapmasına olanak tanıyan bir bağlam menüsü bulunur.

Aşağıdaki yöntemlerle tek bir bloğun bağlam menüsünü devre dışı bırakabilirsiniz:

block.contextMenu = false;

Bir blok türünün JSON tanımında enableContextMenu anahtarını kullanın:

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

İçerik menülerini blok türüne veya çalışma alanına göre özelleştirme

Blockly bir bağlam menüsü öğeleri dizisi oluşturduktan sonra bunu tek tek bloklar veya çalışma alanları için özelleştirebilirsiniz. Bunu yapmak için BlockSvg.customContextMenu veya WorkspaceSvg.configureContextMenu işlevini, diziyi yerinde değiştiren bir işlev olarak ayarlayın.

Bloklara iletilen dizideki nesneler ContextMenuOption türündedir veya LegacyContextMenuOption arayüzünü uygular. Çalışma alanlarına aktarılan nesneler ContextMenuOption türündedir. Blockly, bu nesnelerden aşağıdaki özellikleri kullanır:

  • text: Görünen metin.
  • enabled: false ise öğeyi gri metinle gösterin.
  • callback: Öğe tıklandığında çağrılacak işlev.
  • separator: Öğe bir ayraçtır. Diğer üç özellik ile karşılıklı olarak dışlayıcıdır.

Mülk türleri ve işlev imzalarıyla ilgili referans belgelerine bakın.

Örneğin, bir çalışma alanının içerik menüsüne Hello, World! öğesi ekleyen bir işlevi aşağıda bulabilirsiniz:

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

Özel bir nesnede içerik menüsü gösterme

Aşağıdaki adımları uygulayarak özel bileşenler için bağlam menülerinin görünmesini sağlayabilirsiniz:

  1. IFocusableNode uygulayan veya IFocusableNode uygulayan bir sınıfı genişleten bir sınıf uygulayın. Bu arayüz, bağlam menüsü sisteminde bileşeninizi tanımlamak için kullanılır. Ayrıca, kullanıcıların klavye gezinme eklentisini kullanarak bileşeninizde gezinmesine de olanak tanır.
  2. IContextMenu işlevini içeren showContextMenu işlevini uygulayın. Bu işlev, içerik menüsü öğelerini kayıt defterinden alır, menünün ekranda gösterileceği konumu hesaplar ve son olarak gösterilecek öğeler varsa menüyü gösterir.

    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. Kullanıcı bileşeninizi sağ tıkladığında showContextMenu işlevini çağıran bir etkinlik işleyici ekleyin. Klavye ile gezinme eklentisinin, kullanıcı Ctrl+Enter (Windows) veya Command+Enter (Mac) tuşuna bastığında showContextMenu işlevini çağıran bir etkinlik işleyici sağladığını unutmayın.

  4. Bağlam menüsü öğeleriniz için kayıt defterine şablon ekleyin.