Uzantılar ve Susturucular

Uzantılar, blok oluşturulurken belirli bir türdeki her blokta çalışan işlevlerdir. Bunlar genellikle bir engellemeye özel yapılandırma veya davranış ekler.

Mutator, bir bloka özel serileştirme ve bazen de kullanıcı arayüzü ekleyen özel bir uzantı türüdür.

Uzantılar

Uzantılar, blok oluşturulurken belirli bir türdeki her blokta çalışan işlevlerdir. Özel yapılandırma (ör. engellemenin ipucunu ayarlama) veya özel davranış (ör. engellemeye bir etkinlik işleyici ekleme) ekleyebilirler.

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

Uzantıların bir dize anahtarıyla ilişkilendirilebilmeleri için "kayıtlı" olmaları gerekir. Daha sonra, uzantıyı bloka uygulamak için bu dize anahtarını blok türünüzün JSON tanımının extensions özelliğine atayabilirsiniz.

{
 //...,
 "extensions": ["parent_tooltip_extension",]
}

Ayrıca, tek seferde birden fazla uzantı da ekleyebilirsiniz. Yalnızca bir uzantı uyguluyor olsanız bile extensions özelliğinin bir dizi olması gerektiğini unutmayın.

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

Karışımlar

Blockly, bir bloka bazı özellikler/yardımcı işlevler eklemek istediğiniz ancak bunları hemen çalıştırmamak istediğiniz durumlar için de kolaylık sağlar. Bu, tüm ek özelliklerinizi/yöntemlerinizi içeren bir mixin nesnesi kaydetmenize olanak tanıyarak çalışır. Daha sonra mixin nesnesi, belirtilen blok türünün her örneği oluşturulduğunda mix'i uygulayan bir fonksiyona sarmalanır.

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

Mix'ler ile ilişkili dize anahtarlarına JSON'da diğer uzantılar gibi referans verilebilir.

{
 //...,
 "extensions": ["my_mixin"],
}

Mutatörler

Mutator, bir bloka ekstra serileştirme (kaydedilen ve yüklenen ekstra durum) ekleyen özel bir uzantı türüdür. Örneğin, yerleşik controls_if ve list_create_with blokları, sahip oldukları giriş sayısını kaydedebilmek için ekstra serileştirmeye ihtiyaç duyar.

Bloğunuzun şeklini değiştirmenin, daha fazla serileştirmeye ihtiyacınız gerektiği anlamına gelmediğini unutmayın. Örneğin, math_number_property blokunun şekli değişir, ancak bunu, değeri halihazırda serileştirilmiş olan bir açılır menü alanını temel alarak yapar. Bu nedenle, sadece bir alan doğrulayıcısı kullanabilir ve bir mutatöre ihtiyacı yoktur.

Ne zaman mutatöre ihtiyacınız olup olmadığı hakkında daha fazla bilgi için serileştirme sayfasını inceleyin.

Bazı isteğe bağlı yöntemler sağlarsanız mutatörler, kullanıcıların blokların şekillerini değiştirmeleri için yerleşik bir kullanıcı arayüzü de sağlar.

Serileştirme kancaları

Mutator'lar, çalıştıkları iki adet serileştirme kancasına sahiptir. Bir çift kanca, yeni JSON serileştirme sistemiyle, diğer çift ise eski XML serileştirme sistemiyle çalışır. Bu çiftlerden en az birini sağlamanız gerekir.

SaveExtraState ve loadExtraState

saveExtraState ve loadExtraState, yeni JSON serileştirme sistemiyle çalışan serileştirme kancalarıdır. saveExtraState, bloğun ekstra durumunu temsil eden bir JSON serileştirilebilir değeri döndürür ve loadExtraState, aynı JSON seri hale getirilebilir değerini kabul ederek bloka uygular.

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Sonuç olarak elde edilen JSON şöyle görünür:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
Durum yok

Bloğunuz seri hale getirilirken varsayılan durumundaysa saveExtraState yönteminiz bunu belirtmek için null döndürebilir. saveExtraState yönteminiz null değerini döndürürse JSON'a hiçbir extraState özelliği eklenmez. Bu, kaydettiğiniz dosyanın boyutunu küçültür.

Tam serileştirme ve veri yedekleme

saveExtraState, isteğe bağlı bir doFullSerialization parametresi de alır. Bu, farklı bir serileyici tarafından serileştirilmiş referans durumu blokları (ör. yedekleme veri modelleri) tarafından kullanılır. Parametre, blok seri durumdan çıkarıldığında referans verilen durumun kullanılamayacağını belirtir. Bu nedenle, bloğun tüm yedekleme durumunu seri hale getirmesi gerekir. Örneğin, tek bir blok serileştirildiğinde veya bir blok kopyalayıp yapıştırıldığında bu doğrudur.

Bunun iki yaygın kullanım alanı vardır:

  • Tek bir blok, yedekleme veri modelinin bulunmadığı bir çalışma alanına yüklendiğinde yeni bir veri modeli oluşturmak için kendi durumunda yeterli bilgiye sahip olur.
  • Bir blok kopyalayıp yapıştırıldığında, mevcut bir bloka referans vermek yerine her zaman yeni bir yedekleme veri modeli oluşturur.

Bunu kullanan bazı bloklar, @blockly/block-shareable-procedures bloklarıdır. Normalde bu dosyalar, durumlarını depolayan bir yedek veri modeline bir referansı seriler. Ancak doFullSerialization parametresi true (doğru) değerine ayarlanırsa tüm durumlarını serilerler. Paylaşılabilir prosedür blokları, kopyalanıp yapıştırıldıklarında mevcut bir modele referans vermek yerine yeni bir yedekleme veri modeli oluşturmalarını sağlamak için bunu kullanır.

mutasyonToDom ve domToMutation

mutationToDom ve domToMutation, eski XML serileştirme sistemiyle çalışan serileştirme kancalarıdır. Bu kancaları yalnızca gerektiğinde kullanın (ör. henüz taşınmamış eski bir kod tabanı üzerinde çalışıyorsanız) aksi takdirde saveExtraState ve loadExtraState kullanın.

mutationToDom, blokun ekstra durumunu temsil eden bir XML düğümü döndürür ve domToMutation, aynı XML düğümünü kabul edip durumu bloka uygular.

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Elde edilen XML şöyle görünür:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

mutationToDom işleviniz null değerini döndürürse XML'e fazladan öğe eklenmez.

Kullanıcı Arayüzü Kancaları

Mutatörünüzün parçası olarak belirli işlevler sağlarsanız Blockly, blokunuza varsayılan bir "mutatör" kullanıcı arayüzü ekler.

Fazladan serileştirme eklemek istiyorsanız bu kullanıcı arayüzünü kullanmanız gerekmez. blocks-plus-minus eklentisinin sağladığı gibi özel bir kullanıcı arayüzü kullanabilir veya hiç kullanıcı arayüzünü kullanamazsınız!

oluşturmak ve ayırmak

Varsayılan kullanıcı arayüzü compose ve decompose işlevlerini kullanır.

decompose, bloku hareket ettirilebilen, eklenebilen ve silinebilen daha küçük alt bloklara "patlar". Bu işlev, alt blokların bağlandığı mutatör çalışma alanında ana blok olan bir "üst blok" döndürmelidir.

compose, daha sonra alt blokların yapılandırmasını yorumlar ve ana bloğu değiştirmek için kullanır. Bu işlev, decompose tarafından parametre olarak döndürülen "üst blok"u kabul etmelidir.

Bu işlevlerin, "mutasyona uğrayan" blokla "karma"landığını ve bu nedenle, söz konusu bloka atıfta bulunmak için this işlevinin kullanılabileceğini unutmayın.

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

İsteğe bağlı olarak, varsayılan kullanıcı arayüzüyle çalışan bir saveConnections işlevi de tanımlayabilirsiniz. Bu işlev, ana blokunuzun (ana çalışma alanında bulunan) alt bloklarını, mutatör çalışma alanınızda bulunan alt bloklarla ilişkilendirmenize olanak tanır. Ardından bu verileri, alt bloklarınız yeniden düzenlendiğinde compose işlevinin ana blokunuzun alt öğelerini düzgün şekilde yeniden bağladığından emin olmak için kullanabilirsiniz.

saveConnections, decompose işleviniz tarafından döndürülen "üst blok"u bir parametre olarak kabul etmelidir. saveConnections işlevi tanımlıysa Blockly, compose işlevini çağırmadan önce bunu çağırır.

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

Kaydı yapılıyor

Mutatörler, yalnızca özel bir uzantı türüdür. Bu nedenle, blok türünüzün JSON tanımında kullanabilmeniz için öncesinde mutasyonların kaydedilmesi gerekir.

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name: JSON'da kullanabilmeniz için mutatörle ilişkilendirilecek bir dize.
  • mixinObj: Çeşitli mutasyon yöntemlerini içeren bir nesne. Ör. saveExtraState ve loadExtraState.
  • opt_helperFn: Karıştırma karıştırıldıktan sonra blokta çalışacak isteğe bağlı bir yardımcı işlev.
  • opt_blockList: Kullanıcı arayüzü yöntemleri de tanımlanmışsa varsayılan mutatör kullanıcı arayüzündeki uç noktaya eklenecek isteğe bağlı bir blok türleri dizisi (dize olarak).

Uzantılardan farklı olarak, her blok türünün yalnızca bir mutatörü olabilir.

{
  //...
  "mutator": "controls_if_mutator"
}

Yardımcı işlev

Karışımla birlikte, bir mutatör bir yardımcı fonksiyon kaydedebilir. Bu işlev, belirtilen türdeki her blokta oluşturulduktan ve mixinObj eklendikten sonra çalıştırılır. Bir mutasyona ek tetikleyiciler veya efektler eklemek için kullanılabilir.

Örneğin, liste benzeri blokunuza öğelerin başlangıç sayısını ayarlayan bir yardımcı ekleyebilirsiniz:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}