Ekstensi dan Mutator

Ekstensi adalah fungsi yang berjalan di setiap blok jenis tertentu karena blok dibuat. Hal ini sering kali menambahkan beberapa konfigurasi atau perilaku kustom ke blok.

Mutator adalah jenis ekstensi khusus yang menambahkan serialisasi kustom, dan terkadang UI, ke blok.

Ekstensi

Ekstensi adalah fungsi yang berjalan di setiap blok jenis tertentu karena blok dibuat. Mereka dapat menambahkan konfigurasi khusus (mis. menyetel tooltip blok) atau perilaku kustom (misalnya, menambahkan pemroses peristiwa ke blok).

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

Ekstensi harus "didaftarkan" sehingga mereka dapat dikaitkan dengan suatu tombol. Selanjutnya, Anda dapat menetapkan kunci string ini ke properti extensions JSON jenis pemblokiran definisi untuk menerapkan ekstensi ke blok tersebut.

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

Anda juga dapat menambahkan beberapa ekstensi sekaligus. Perhatikan bahwa extensions harus berupa array, meskipun Anda hanya menerapkan satu ekstensi.

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

Mixin

Blockly juga menyediakan metode praktis untuk situasi saat Anda ingin menambahkan beberapa properti/fungsi helper ke blok, tetapi tidak menjalankannya secara langsung. Ini dengan memungkinkan Anda mendaftarkan mixin yang berisi semua properti/metode tambahan. Objek mixin kemudian dibungkus dalam fungsi yang menerapkan {i> mixin<i} setiap kali sebuah instance jenis blok yang ditentukan dibuat.

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

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

Kunci string yang terkait dengan mixin dapat direferensikan di JSON seperti yang lainnya .

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

Mutator

Mutator adalah jenis ekstensi khusus yang menambahkan serialisasi ekstra (ekstra yang disimpan dan dimuat) ke sebuah blok. Misalnya, {i>built-in<i} Blok controls_if dan list_create_with memerlukan serialisasi tambahan sehingga mereka bisa menyimpan berapa banyak input yang mereka miliki.

Perhatikan bahwa mengubah bentuk blok tidak selalu berarti Anda perlu serialisasi tambahan. Misalnya, blok math_number_property mengubah {i>shape<i}, tetapi hal itu dilakukan berdasarkan {i>field<i} {i>dropdown<i}, yang nilainya sudah didapatkan diserialisasi. Dengan demikian, instance tersebut dapat menggunakan kolom validator, dan tidak memerlukan mutator.

Lihat serialisasi halaman untuk informasi selengkapnya tentang kapan Anda memerlukan mutator dan tidak.

Mutator juga menyediakan UI bawaan bagi pengguna untuk mengubah bentuk blok jika Anda menyediakan beberapa metode opsional.

Hook serialisasi

Mutator memiliki dua pasang hook serialisasi yang digunakan. Sepasang hook berfungsi dengan sistem serialisasi JSON yang baru, sedangkan pasangan lainnya berfungsi dengan sistem serialisasi XML lama. Anda harus memberikan setidaknya salah satu dari pasangan data tersebut.

saveExtraState dan loadExtraState

saveExtraState dan loadExtraState adalah hook serialisasi yang berfungsi dengan sistem serialisasi JSON yang baru. saveExtraState menampilkan JSON yang dapat diserialisasi nilai yang mewakili status tambahan blok, dan loadExtraState menerima nilai serialisabel JSON yang sama, dan menerapkannya ke blok.

// 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_();
},

JSON yang dihasilkan akan terlihat seperti:

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

Jika blok Anda berada dalam status {i>default<i} saat diserialisasi, maka Metode saveExtraState dapat menampilkan null untuk menunjukkannya. Jika Metode saveExtraState menampilkan null, lalu tidak ada properti extraState yang ditambahkan ke JSON. Tindakan ini menjaga ukuran file yang disimpan tetap kecil.

Serialisasi lengkap dan data cadangan

saveExtraState juga menerima parameter doFullSerialization opsional. Ini digunakan oleh blok yang mereferensikan status yang diserialisasi oleh serializer (seperti model data pendukung). Parameter tersebut menandakan bahwa status yang direferensikan tidak akan tersedia ketika blok dideserialisasi, sehingga harus melakukan serialisasi semua status cadangannya. Sebagai contoh, ini adalah {i>true<i} ketika blok individual diserialisasi, atau ketika suatu blok disalin-tempel.

Dua kasus penggunaan umum untuk hal ini adalah:

  • Saat blok individual dimuat ke ruang kerja tempat data pendukung model tidak ada, terdapat cukup informasi dalam statusnya sendiri untuk membuat model data baru.
  • Jika suatu blok disalin dan ditempel, blok tersebut akan selalu membuat pendukung baru alih-alih mereferensikan model yang sudah ada.

Beberapa blok yang menggunakan ini adalah Blok @blockly/block-shareable-procedures. Biasanya mereka membuat serial referensi ke model data pendukung, yang menyimpan statusnya. Namun, jika parameter doFullSerialization benar, parameter tersebut akan menserialisasi semua status mereka. Blok prosedur yang dapat dibagikan menggunakan ini untuk memastikan bahwa ketika menyalin dan menempel, mereka membuat model data pendukung baru, alih-alih mereferensikan model yang sudah ada.

mutationToDom dan domToMutation

mutationToDom dan domToMutation adalah hook serialisasi yang berfungsi dengan sistem serialisasi XML lama. Gunakan hook ini hanya jika perlu (misalnya, Anda mengerjakan basis kode lama yang belum bermigrasi), jika tidak, gunakan saveExtraState dan loadExtraState.

mutationToDom menampilkan node XML yang mewakili status tambahan , dan domToMutation menerima node XML yang sama dan menerapkan status ke blok tersebut.

// 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_();
},

XML yang dihasilkan akan terlihat seperti:

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

Jika fungsi mutationToDom menampilkan null, tidak ada elemen tambahan yang akan ditambahkan ke XML.

Hook UI

Jika Anda menyediakan fungsi tertentu sebagai bagian dari mutator, Blockly akan menambahkan "mutator" default UI ke blok Anda.

Anda tidak perlu menggunakan UI ini jika ingin menambahkan serialisasi ekstra. Anda dapat gunakan UI khusus, seperti blok-plus-minus plugin atau Anda tidak bisa menggunakan UI sama sekali.

tulis dan uraikan

UI default bergantung pada fungsi compose dan decompose.

decompose "meledak" blok menjadi sub-blok yang lebih kecil yang dapat dipindahkan ada, ditambahkan, dan dihapus. Fungsi ini akan menampilkan "blok atas" yang merupakan blok utama di ruang kerja mutator yang terhubung dengan sub-blok.

compose kemudian menafsirkan konfigurasi sub-blok dan menggunakannya untuk mengubah blok utama. Fungsi ini harus menerima "blok atas" yang merupakan yang ditampilkan oleh decompose sebagai parameter.

Perlu diingat bahwa fungsi ini akan "tercampur dalam" ke blok yang "dimutated" jadi this dapat digunakan untuk merujuk ke blok tersebut.

// 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

Atau, Anda juga dapat menentukan fungsi saveConnections yang berfungsi dengan UI default. Fungsi ini memberi Anda kesempatan untuk mengaitkan turunan blok utama (yang ada di ruang kerja utama) dengan sub-blok yang ada di ruang kerja mutator Anda. Anda kemudian dapat menggunakan data ini untuk memastikan compose berfungsi menghubungkan ulang turunan blok utama dengan benar sub-blok diatur ulang.

saveConnections harus menerima "blok atas" dikembalikan oleh decompose Anda berfungsi sebagai parameter. Jika fungsi saveConnections ditentukan, Blockly akan memanggilnya sebelum memanggil compose.

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

Mendaftarkan

Mutator hanyalah jenis ekstensi khusus, jadi mereka juga harus terdaftar sebelum Anda dapat menggunakannya di JSON jenis pemblokiran definisinya.

// 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: String yang akan dikaitkan dengan mutator sehingga Anda dapat menggunakannya di JSON.
  • mixinObj: Objek yang berisi berbagai metode mutasi. Mis. saveExtraState dan loadExtraState.
  • opt_helperFn: Fungsi bantuan opsional yang akan berjalan di blok setelah {i> mixin<i} dicampur.
  • opt_blockList: Array opsional dari jenis blok (sebagai string) yang akan ditambahkan ke flyout di UI mutator default, jika metode UI juga didefinisikan.

Perlu diperhatikan bahwa tidak seperti ekstensi, setiap jenis blok mungkin hanya memiliki satu mutator.

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

Fungsi bantuan

Bersama dengan mixin, mutator dapat mendaftarkan fungsi bantuan. Fungsi ini adalah berjalan pada setiap blok dari tipe yang diberikan setelah itu dibuat dan mixinObj akan ditambahkan. Dapat digunakan untuk menambahkan pemicu atau efek tambahan ke mutasi.

Misalnya, Anda bisa menambahkan bantuan ke blok seperti daftar yang menyetel jumlah awal item:

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