Susturucular

Mutator, bir bloğa ek serileştirme (kaydedilen ve yüklenen ek durum) ekleyen bir mixin'dir. Örneğin, yerleşik controls_if ve list_create_with bloklarının, kaç girişe sahip olduklarını kaydedebilmeleri için ek serileştirme yapılması gerekir. Kullanıcının bloğun şeklini değiştirebilmesi için bir kullanıcı arayüzü de ekleyebilir.

Liste oluşturma bloğunun üç mutasyonu: giriş yok, üç giriş ve beş giriş.

Bir if/do bloğunun iki mutasyonu: if-do ve if-do-else-if-do-else.

Bloğunuzun şeklini değiştirmenin mutlaka ek serileştirme yapmanız gerektiği anlamına gelmediğini unutmayın. Örneğin, math_number_property bloğunun şekli değişir ancak bu değişiklik, değeri zaten serileştirilmiş olan bir açılır liste alanına göre yapılır. Bu nedenle, yalnızca alan doğrulayıcı kullanabilir ve değiştiriciye ihtiyacı yoktur.

Açılır listesi "even" olarak ayarlanmış `math_number_property` bloğu. Tek bir değer girişi vardır. Açılır listesi "bölünebilir" olarak ayarlanmış `math_number_property`
bloğu. İki değer girişi vardır.

Mutasyon işleyiciye ne zaman ihtiyacınız olduğu ve olmadığı hakkında daha fazla bilgi için serileştirme sayfasını inceleyin.

Mutasyonlar, bazı isteğe bağlı yöntemler sağlarsanız kullanıcıların blokların şekillerini değiştirmesi için yerleşik bir kullanıcı arayüzü de sunar.

Serileştirme kancaları

Değiştiriciler, birlikte çalıştıkları iki çift serileştirme kancasına sahiptir. Bir kanca çifti yeni JSON serileştirme sistemiyle, diğer kanca çifti 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 ek durumunu temsil eden JSON serileştirilebilir bir değer döndürür ve loadExtraState aynı JSON serileştirilebilir değeri kabul edip bloğa 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_();
},

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

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

Durum yok

Blokunuz, seri hale getirildiğinde varsayılan durumundaysa saveExtraState yönteminiz bunu belirtmek için null değerini döndürebilir. saveExtraState yönteminiz null değerini döndürürse JSON'a extraState özelliği eklenmez. Bu sayede kayıt dosyanızın boyutu küçük kalır.

Tam serileştirme ve destekleme verileri

saveExtraState ayrıca isteğe bağlı bir doFullSerialization parametresi de alır. Bu, farklı bir serileştirici (ör. destekleyen veri modelleri) tarafından serileştirilmiş duruma referans veren bloklar tarafından kullanılır. Parametre, başvurulan durumun blok seri durumdan çıkarıldığında kullanılamayacağını belirtir. Bu nedenle, blok tüm destekleyici durumu kendisi serileştirmelidir. Örneğin, bu durum, ayrı bir blok seri hale getirildiğinde veya bir blok kopyalanıp yapıştırıldığında geçerlidir.

Bu özelliğin iki yaygın kullanım alanı şunlardır:

  • Bir blok, destekleyici veri modelinin bulunmadığı bir çalışma alanına yüklendiğinde yeni bir veri modeli oluşturmak için kendi durumunda yeterli bilgiye sahiptir.
  • Bir blok kopyalanıp yapıştırıldığında, mevcut bir veri modeline referans vermek yerine her zaman yeni bir destekleyici veri modeli oluşturulur.

Bu özelliği kullanan bazı bloklar @blockly/block-shareable-procedures bloklarıdır. Normalde, durumlarını depolayan bir destekleyici veri modeline yapılan referansı serileştirirler. Ancak doFullSerialization parametresi doğruysa tüm durumlarını serileştirirler. Paylaşılabilir prosedür blokları, kopyalanıp yapıştırıldıklarında mevcut bir modele referans vermek yerine yeni bir destekleyici veri modeli oluşturmalarını sağlamak için bu özelliği kullanır.

mutationToDom ve domToMutation

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

mutationToDom, bloğun ek durumunu temsil eden bir XML düğümü döndürür. domToMutation ise aynı XML düğümünü kabul eder ve durumu bloğa 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 şu şekilde 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'ye ek öğe eklenmez.

Kullanıcı arayüzü kancaları

Değiştiricinizin bir parçası olarak belirli işlevler sağlarsanız Blockly, bloğunuza varsayılan bir "değiştirici" kullanıcı arayüzü ekler.

Mutatör baloncuğu açık olan bir if-do bloğu. Bu sayede kullanıcılar, if-do bloğuna else-if ve else ifadeleri ekleyebilir.

Ek 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ü kullanmayabilirsiniz.

oluşturma ve ayrıştırma

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

decompose, bloğu taşınabilen, eklenebilen ve silinebilen daha küçük alt bloklara "ayırır". Bu işlev, alt blokların bağlandığı mutasyon çalışma alanındaki ana blok olan bir "üst blok" döndürmelidir.

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

Bu işlevlerin, "mutasyona uğrayan" bloğa "karıştığını" ve bu nedenle this ile söz konusu bloğa referans verilebileceğ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 çalışma alanında bulunan ana bloğunuzun alt öğelerini, mutator çalışma alanınızda bulunan alt bloklarla ilişkilendirme olanağı sunar. Daha sonra bu verileri kullanarak, alt bloklarınız yeniden düzenlendiğinde compose işlevinizin ana bloğunuzun alt öğelerini düzgün şekilde yeniden bağladığından emin olabilirsiniz.

saveConnections, decompose işleviniz tarafından döndürülen "üst blok"u parametre olarak kabul etmelidir. saveConnections işlevi tanımlanmışsa Blockly, compose işlevini çağırmadan önce saveConnections işlevini ç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();
  }
},

Kaydettiriliyor

Mutator'lar yalnızca özel bir mixin türüdür. Bu nedenle, blok türünüzün JSON tanımında kullanabilmeniz için önce kaydedilmeleri 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: Değiştiriciyle ilişkilendirilecek bir dize. Böylece, bu dizeyi JSON'da kullanabilirsiniz.
  • mixinObj: Çeşitli mutasyon yöntemlerini içeren bir nesne. Ör. saveExtraState ve loadExtraState.
  • opt_helperFn: Mixin karıştırıldıktan sonra blokta çalışacak isteğe bağlı bir yardımcı işlevdir.
  • opt_blockList: Kullanıcı arayüzü yöntemleri de tanımlanmışsa varsayılan mutator kullanıcı arayüzündeki açılır menüye eklenecek isteğe bağlı bir blok türleri dizisi (dizeler olarak).

Uzantıların aksine, her blok türünde yalnızca bir mutasyon oluşturucu bulunabileceğini unutmayın.

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

Yardımcı işlev

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

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

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