Odak sistemi

Odak sistemi, kullanıcının Blockly düzenleyicideki konumunu (odak) takip eder. Blockly ve özel kod tarafından, şu anda hangi bileşenin (blok, alan, araç kutusu kategorisi vb.) odaklandığını belirlemek ve bu odağı başka bir bileşene taşımak için kullanılır.

Özel kodunuzun odak sistemiyle doğru şekilde çalıştığından emin olabilmek için odak sistemini anlamanız önemlidir.

Mimari

Odaklanma sistemi üç bölümden oluşur:

  • FocusManager, Blockly'deki tüm odakları koordine eden tekil bir öğedir. Blockly'nin hangi bileşene odaklandığını öğrenmek ve Blockly'nin odağını farklı bir bileşene taşımak için Blockly ve özel kod tarafından kullanılır. Ayrıca, DOM odak etkinliklerini dinler, Blockly odaklanması ile DOM odaklanmasını senkronize eder ve hangi bileşenin odaklandığını belirten CSS sınıflarını yönetir.

    Odak yöneticisi esas olarak Blockly tarafından kullanılır. Bazen odak sistemiyle etkileşim kurmak için özel kod tarafından kullanılır.

  • IFocusableTree, Blockly düzenleyicisinin bağımsız bir alanıdır (ör. çalışma alanı veya araç kutusu). Bloklar ve alanlar gibi odaklanılabilir düğümlerden oluşur. Ağaçların alt ağaçları da olabilir. Örneğin, ana çalışma alanındaki bir blokta bulunan mutasyon çalışma alanı, ana çalışma alanının bir alt ağacıdır.

    IFocusableTree öncelikli olarak odak yöneticisi tarafından kullanılır. Özel bir araç kutusu yazmadığınız sürece uygulamanız muhtemelen gerekmez.

  • IFocusableNode, odaklanabilen bir Blockly bileşenidir (ör. blok, alan veya araç kutusu kategorisi). Odaklanılabilir düğümler, düğümü görüntüleyen ve düğüm Blockly odağına sahip olduğunda DOM odağına sahip bir DOM öğesine sahiptir. Ağaçların da odaklanılabilir düğümler olduğunu unutmayın. Örneğin, çalışma alanının tamamına odaklanabilirsiniz.

    IFocusableNode bölümündeki yöntemler öncelikle odak yöneticisi tarafından çağrılır.

    Odaklanılan bileşeni temsil etmek için IFocusableNode kullanılır. Örneğin, bir kullanıcı bloğun bağlam menüsünde bir öğe seçtiğinde blok, öğenin geri çağırma işlevine IFocusableNode olarak iletilir.

    Özel bileşenler yazarsanız uygulamanız IFocusableNode gerekebilir.

Odak türleri

Odak sistemi, çeşitli odak türlerini tanımlar.

Blockly odağı ve DOM odağı

İki ana odak türü vardır: Blockly odağı ve DOM odağı.

  • Blockly odaklanma, hangi Blockly bileşeninin (blok, alan, araç kutusu kategorisi vb.) odaklandığını belirtir. Blockly bileşenleri düzeyinde çalışmak için gereklidir. Örneğin, klavye ile gezinme eklentisi, kullanıcıların ok tuşlarını kullanarak bileşenler arasında (ör. bloktan alana) geçiş yapmasına olanak tanır. Benzer şekilde, içerik menüsü sistemi de mevcut bileşene uygun bir menü oluşturur. Yani çalışma alanları, bloklar ve çalışma alanı yorumları için farklı menüler oluşturur.

  • DOM odağı, hangi DOM öğesinin odaklandığını belirtir. DOM öğeleri düzeyinde çalışmak için gereklidir. Örneğin, ekran okuyucular, DOM odaklı olan öğeyle ilgili bilgileri sunar ve sekmeler, DOM öğesinden DOM öğesine geçiş yapar (odak değiştirir).

Odak yöneticisi, Blockly odağını ve DOM odağını senkronize tutar. Bu nedenle, bir düğüm (Blockly bileşeni) Blockly odağına sahip olduğunda temel alınan DOM öğesi DOM odağına sahip olur ve bunun tersi de geçerlidir.

Etkin ve pasif odak

Blockly odağı, etkin odak ve pasif odak olarak ikiye ayrılır. Etkin odak, bir düğümün tuşa basma gibi kullanıcı girişi alacağı anlamına gelir. Pasif odak, bir düğümün daha önce aktif odağa sahip olduğu ancak kullanıcının başka bir ağdaki bir düğüme (örneğin, çalışma alanından araç kutusuna) veya Blockly düzenleyicisinden tamamen uzaklaşmasıyla odağı kaybettiği anlamına gelir. Ağaç yeniden odaklandığında pasif olarak odaklanılan düğüm etkin odağı yeniden kazanır.

Her ağacın ayrı bir odaklanma bağlamı vardır. Yani ağaçtaki en fazla bir düğüm odaklanabilir. Bu odağın etkin mi yoksa pasif mi olduğu, ağacın odaklanıp odaklanmadığına bağlıdır. Sayfanın tamamında en fazla bir etkin odaklanma düğümü olabilir.

Odak yöneticisi, etkin ve pasif olarak odaklanmış düğümler için farklı vurgular (CSS sınıfları) kullanır. Bu özellikler, kullanıcıların bulundukları yeri ve geri dönecekleri yeri anlamalarına olanak tanır.

Geçici odak

Geçici odak adı verilen başka bir odak türü daha vardır. İletişim kutuları veya alan düzenleyiciler gibi ayrı iş akışları, odak yöneticisinden geçici odak ister. Odak yöneticisi geçici odak verdiğinde odak sistemini askıya alır. Pratik açıdan bu, bu tür iş akışlarının, odak sisteminin de bu etkinlikler üzerinde işlem yapabileceğinden endişelenmeden DOM odak etkinliklerini yakalayabileceği ve bu etkinlikler üzerinde işlem yapabileceği anlamına gelir.

Odak yöneticisi geçici odak verdiğinde, etkin olarak odaklanılan düğümü pasif odak olarak değiştirir. Geçici odak döndürüldüğünde etkin odak geri yüklenir.

Örnekler

Aşağıdaki örneklerde, Blockly'nin odak sistemini nasıl kullandığı gösterilmektedir. Bu dokümanlar, kodunuzun odak sistemine nasıl uyduğunu ve odak sistemini nasıl kullanabileceğini anlamanıza yardımcı olmalıdır.

Klavyeyle odağı taşıma

İki alan içeren bir blokta, blokun DOM öğesindeki vurgu (CSS sınıfı) ile belirtildiği gibi Blockly odağı olduğunu varsayalım. Şimdi de kullanıcının sağ oku bastığını varsayalım:

  1. Klavye ile gezinme eklentisi:
    • Tuşa basma etkinliği alır.
    • Navigasyon sisteminden (çekirdek Blockly'nin bir parçası) odağı "sonraki" bileşene taşımasını ister.
  2. Navigasyon sistemi:
    • Odak yöneticisine, Blockly odağına sahip bileşeni sorar. Odak yöneticisi, bloğu IFocusableNode olarak döndürür.
    • IFocusableNode öğesinin BlockSvg olduğunu belirler ve bloklarda gezinme kurallarını inceler. Bu kurallar, Blockly odağının bloktan bir bütün olarak bloktaki ilk alana taşınması gerektiğini belirtir.
    • Odağı yöneticiye, Blockly odağını ilk alana taşımasını söyler.
  3. Odak yöneticisi:
    • Durumunu, Blockly odağını ilk alana ayarlayacak şekilde günceller.
    • DOM odağını alanın DOM öğesine ayarlar.
    • Vurgu sınıfını bloğun öğesinden alanın öğesine taşır.

Fareyle odağı taşıma

Şimdi kullanıcının bloktaki ikinci alanı tıkladığını varsayalım. Odak yöneticisi:

  1. İlk alanın DOM öğesinde bir DOM focusout etkinliği, ikinci alanın DOM öğesinde ise bir focusin etkinliği alır.
  2. Odaklanan DOM öğesinin ikinci alana karşılık geldiğini belirler.
  3. Durumunu, Blockly odağını ikinci alana ayarlayacak şekilde günceller. (Tarayıcı bunu zaten yaptığından focus yöneticisinin DOM odağını ayarlaması gerekmez.)
  4. Vurgu sınıfını ilk alanın öğesinden ikinci alanın öğesine taşır.

Diğer örnekler

Diğer bazı örnekler:

  • Kullanıcı, araç kutusundan çalışma alanına bir blok sürüklediğinde fare etkinliği işleyicisi yeni bir blok oluşturur ve Blockly'nin bu blokta odaklanmasını sağlamak için odak yöneticisini çağırır.

  • Bir blok silindiğinde, dispose yöntemi, odağı bloğun üst öğesine taşımak için odak yöneticisini çağırır.

  • Klavye kısayollarında, kısayolun uygulandığı Blockly bileşenini belirlemek için IFocusableNode kullanılır.

  • Bağlam menüleri, menünün çağrıldığı Blockly bileşenini tanımlamak için IFocusableNode kullanır.

Özelleştirmeler ve odak sistemi

Blockly'yi özelleştirirken kodunuzun odak sistemiyle doğru şekilde çalıştığından emin olmanız gerekir. Ayrıca, odaklanılan düğümü belirlemek ve ayarlamak için odaklanma sistemini de kullanabilirsiniz.

Özel bloklar ve araç kutusu içerikleri

Blockly'yi özelleştirmenin en yaygın yolu özel bloklar tanımlamak ve araç kutusunun içeriğini özelleştirmektir. Bu işlemlerin hiçbiri odaklanma sistemini etkilemez.

Özel sınıflar

Özel sınıfların bir veya iki odak arayüzünü (IFocusableTree ve IFocusableNode) uygulaması gerekebilir. Bu durumun ne zaman geçerli olduğu her zaman açıkça belli olmaz.

Bazı sınıfların odak arayüzlerini uygulaması gerektiği açıktır. Bunlardan bazıları:

  • Özel bir araç kutusu uygulayan sınıf. Bu sınıfın IFocusableTree ve IFocusableNode uygulaması gerekir.

  • Kullanıcıların gezinebileceği görünür bir bileşen (ör. alan veya simge) oluşturan sınıflar. Bu sınıflar IFocusableNode protokolünü uygulamalıdır.

Bazı sınıflar, görünür bir bileşen oluşturmasalar veya kullanıcıların gezinemeyeceği görünür bir bileşen oluştursalar bile IFocusableNode uygulamalıdır. Bunlardan bazıları:

  • IFocusableNode öğesini genişleten bir arayüz uygulayan sınıflar.

    Örneğin, klavye ile gezinme eklentisindeki taşıma simgesi, bloğun ok tuşlarıyla taşınabileceğini belirten dört yönlü bir ok gösterir. Simgenin kendisi görünmüyor (dört yönlü ok bir balon) ve kullanıcılar bu simgeye gidemiyor. Ancak simgeler IIcon öğesini uyguladığından ve IIcon, IFocusableNode öğesini genişlettiğinden simgenin IFocusableNode öğesini uygulaması gerekir.

  • IFocusableNode gerektiren bir API'de kullanılan sınıflar.

    Örneğin, FlyoutSeparator sınıfı, bir açılır listedeki iki öğe arasında boşluk oluşturur. Herhangi bir DOM öğesi oluşturmadığı için görünür bir bileşeni yoktur ve kullanıcılar bu bileşene gidemez. Ancak IFocusableNode içinde depolandığı ve FlyoutItem oluşturucusunun IFocusableNode gerektirdiği için IFocusableNode uygulaması gerekir.FlyoutItem

  • IFocusableNode uygulayan bir sınıfı genişleten sınıflar.

    Örneğin, ToolboxSeparator, IFocusableNode'yi uygulayan ToolboxItem'yi genişletir. Araç kutusu ayırıcılarının görünür bir bileşeni olsa da, üzerinde işlem yapılamadığından ve faydalı içerik barındırmadığından kullanıcılar bu bileşenlere gidemez.

Diğer sınıflar, kullanıcının gezinebileceği görünür bileşenler oluşturur ancak IFocusableNode'yı uygulamaları gerekmez. Bunlardan bazıları:

  • Alan düzenleyici veya iletişim kutusu gibi kendi odağını yöneten görünür bir bileşen oluşturan sınıflar. (Bu tür sınıfların, başladıklarında kısa süreli odaklanma alması ve bittiğinde geri vermesi gerektiğini unutmayın. WidgetDiv veya DropDownDiv kullanıldığında bu işlem sizin için yapılır.)

Son olarak, bazı sınıflar odak sistemiyle etkileşime girmez ve IFocusableTree veya IFocusableNode uygulamasına gerek duymaz. Bunlardan bazıları:

  • Kullanıcıların gezinemediği veya üzerinde işlem yapamadığı, ekran okuyucunun kullanabileceği hiçbir bilgi içermeyen görünür bileşenler oluşturan sınıflar. Örneğin, bir oyunda tamamen dekoratif amaçlı kullanılan arka planlar.

  • IMetricsManager veya IVariableMap uygulayan sınıflar gibi odak sistemiyle tamamen alakasız sınıflar.

Sınıfınızın odak sistemiyle etkileşime girip girmeyeceğinden emin değilseniz klavye gezinme eklentisiyle test edin. Bu işlem başarısız olursa IFocusableTree veya IFocusableNode'yi uygulamanız gerekebilir. İşlem başarılı olursa ancak yine de emin değilseniz arayüzlerden birinin gerekli olup olmadığını veya başka etkileşimlerin olup olmadığını görmek için sınıfınızı kullanan kodu okuyun.

Odaklanma arayüzlerini uygulama

IFocusableTree veya IFocusableNode'ı uygulamanın en kolay yolu, bu arayüzleri uygulayan bir sınıfı genişletmektir. Örneğin, özel bir araç kutusu oluşturuyorsanız Toolbox'yı genişletin. Bu, IFocusableTree ve IFocusableNode'yi uygular. Özel alan oluşturuyorsanız Field sınıfını genişletin. Bu sınıf, IFocusableNode sınıfını uygular. Kodunuzun temel sınıftaki odak arayüzü koduyla çakışmadığından emin olun.

Odak arayüzünü uygulayan bir sınıfı genişletirseniz genellikle herhangi bir yöntemi geçersiz kılmanız gerekmez. En yaygın istisna, kullanıcıların bileşeninize gitmesini istemiyorsanız geçersiz kılmanız gereken IFocusableNode.canBeFocused'dır.

Odak geri çağırma yöntemlerini (onTreeFocus ve onTreeBlur, IFocusableTree ve onNodeFocus ve onNodeBlur içinde IFocusableNode) geçersiz kılma ihtiyacı daha az görülür. Bu yöntemlerden odak değiştirmeye (FocusManager.focusNode veya FocusManager.focusTree çağrısı) çalışmanın istisnaya neden olacağını unutmayın.

Özel bir bileşeni sıfırdan yazarsanız odak arayüzlerini kendiniz uygulamanız gerekir. Daha fazla bilgi için IFocusableTree ve IFocusableNode ile ilgili referans belgelerine göz atın.

Sınıfınızı uyguladıktan sonra, bileşeninize gidip gidemediğinizi doğrulamak için klavye navigasyonu eklentisine karşı test edin.

Odak yöneticisini kullanma

Bazı özel sınıflar odak yöneticisini kullanır. Bunun en yaygın nedenleri, şu anda odaklanılan düğümü almak ve farklı bir düğüme odaklanmaktır. Odak yöneticisini almak için Blockly.getFocusManager işlevini çağırın:

const focusManager = Blockly.getFocusManager();

Şu anda odaklanılan düğümü almak için getFocusedNode işlevini çağırın:

const focusedNode = focusManager.getFocusedNode();
// Do something with the focused node.

Odağı farklı bir düğüme taşımak için focusNode işlevini çağırın:

// Move focus to a different block.
focusManager.focusNode(myOtherBlock);

Odağı bir ağaca taşımak için focusTree işlevini çağırın. Bu işlem, düğüm odağını ağacın kök düğümüne de ayarlar.

// Move focus to the main workspace.
focusManager.focusTree(myMainWorkspace);

Odak yöneticisinin kullanılmasının bir diğer yaygın nedeni ise geçici odak almak ve döndürmektir. takeEphemeralFocus işlevi, geçici odak döndürmek için çağırmanız gereken bir lambda döndürür.

const returnEphemeralFocus = focusManager.takeEphemeralFocus();
// Do something.
returnEphemeralFocus();

WidgetDiv veya DropDownDiv kullanıyorsanız geçici odak sizin için işlenir.

Sekme durakları

Odak sistemi, tüm ağaçların (ana çalışma alanı, araç kutusu ve açılır çalışma alanları) kök öğesinde bir sekme durağı (tabindex of 0) ayarlar. Bu sayede kullanıcılar, Blockly düzenleyicisinin ana bölgelerinde gezinmek için sekme tuşunu, bu bölgelerde gezinmek için ise (klavye gezinme eklentisini kullanarak) ok tuşlarını kullanabilir. Bu sekme duraklarını değiştirmeyin. Aksi takdirde, odak yöneticisinin bunları yönetme özelliği etkilenir.

Genel olarak, Blockly tarafından kullanılan diğer DOM öğelerinde sekme durakları ayarlamaktan kaçınmalısınız. Bu, Blockly'nin sekme tuşunu kullanarak düzenleyicinin alanları arasında ve bu alanlarda ok tuşlarını kullanarak gezinme modeline müdahale eder. Ayrıca bu tür sekme durakları, amaçlandığı gibi çalışmayabilir. Bunun nedeni, odaklanılabilir her düğümün bir DOM öğesini odaklanılabilir öğesi olarak bildirmesidir. Odaklanılabilir bir öğenin alt öğesinde sekme durağı ayarlarsanız ve kullanıcı bu öğeye sekmeyle giderse odak yöneticisi, DOM odağını belirtilen odaklanılabilir öğeye taşır.

Uygulamanızdaki Blockly düzenleyicisinin dışında kalan öğelerde sekme durakları ayarlamak güvenlidir. Kullanıcı, sekme tuşuyla düzenleyiciden bu tür bir öğeye geçtiğinde focus manager, Blockly odağını etkin durumdan pasif duruma değiştirir. Erişilebilirlik için tabindex özelliğinin MDN'deki açıklamasında belirtilen uyarıda önerildiği gibi tabindex özelliğini 0 veya -1 olarak ayarlamanız gerekir.

DOM odaklanması

Erişilebilirlik nedeniyle, uygulamalar DOM öğelerinde focus yöntemini çağırmaktan kaçınmalıdır. Bu durum, ekran okuyucu kullanan kullanıcıları şaşırtır. Çünkü bu kullanıcılar, uygulamada aniden bilinmeyen bir konuma taşınır.

Başka bir sorun da odak yöneticisinin, odaklanılabilir öğe olarak tanımlanmış odaklanılan öğenin en yakın üst öğesi veya kendisi üzerinde DOM odağı ayarlayarak odaklanma etkinliklerine tepki vermesidir. Bu, focus öğesinin çağrıldığı öğeden farklı olabilir. (En yakın odaklanılabilir üst öğe veya kendisi yoksa (ör. focus, Blockly düzenleyicisi dışındaki bir öğede çağrıldığında) odak yöneticisi, etkin olarak odaklanılan düğümü pasif odak olarak değiştirir.)

Konumlandırılabilir öğeler

Konumlandırılabilir öğeler, çalışma alanının üstünde konumlandırılan ve IPositionable uygulayan bileşenlerdir. Sırt çantası eklentisindeki çöp kutusu ve sırt çantası buna örnek olarak verilebilir. Konumlandırılabilir öğeler henüz odak sistemine entegre edilmedi.