Mutator adalah mixin yang menambahkan serialisasi tambahan (status tambahan yang disimpan dan dimuat) ke blok. Misalnya, blok controls_if
dan
list_create_with
bawaan memerlukan serialisasi tambahan agar dapat menyimpan jumlah input yang dimilikinya. Hal ini juga dapat menambahkan UI sehingga pengguna dapat mengubah bentuk
blok.
Perhatikan bahwa mengubah bentuk blok tidak selalu berarti Anda memerlukan
serialisasi tambahan. Misalnya, blok math_number_property
berubah bentuk, tetapi hal itu dilakukan berdasarkan kolom dropdown, yang nilainya sudah diserialisasi. Oleh karena itu, kolom ini hanya dapat menggunakan validator kolom, dan tidak memerlukan mutator.
Lihat halaman serialisasi untuk mengetahui informasi selengkapnya tentang kapan Anda memerlukan mutator dan kapan 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. Satu pasang hook berfungsi dengan sistem serialisasi JSON baru, dan pasang hook lainnya berfungsi dengan sistem serialisasi XML lama. Anda harus memberikan setidaknya satu pasangan ini.
saveExtraState dan loadExtraState
saveExtraState
dan loadExtraState
adalah hook serialisasi yang berfungsi dengan sistem serialisasi JSON baru. saveExtraState
menampilkan nilai yang dapat diserialisasi JSON
yang merepresentasikan status tambahan blok, dan loadExtraState
menerima nilai yang dapat diserialisasi 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 dalam status default saat diserialisasi, metode
saveExtraState
dapat menampilkan null
untuk menunjukkannya. Jika metode
saveExtraState
Anda menampilkan null
, tidak ada properti extraState
yang ditambahkan ke
JSON. Hal ini akan menjaga ukuran file penyimpanan Anda tetap kecil.
Serialisasi penuh dan data pendukung
saveExtraState
juga menerima parameter doFullSerialization
opsional. Hal ini
digunakan oleh blok yang mereferensikan status yang diserialisasi oleh
serializer yang berbeda (seperti model data pendukung). Parameter menandakan bahwa
status yang dirujuk tidak akan tersedia saat blok dideserialisasi, sehingga
blok harus menserialisasi semua status pendukungnya sendiri. Misalnya, hal ini
benar saat blok individual diserialisasi, atau saat blok disalin-tempel.
Dua kasus penggunaan umum untuk hal ini adalah:
- Saat blok individual dimuat ke ruang kerja yang tidak memiliki model data pendukung, blok tersebut memiliki informasi yang cukup dalam statusnya sendiri untuk membuat model data baru.
- Saat diblokir, salin dan tempel, selalu buat model data pendukung baru, bukan merujuk ke model yang sudah ada.
Beberapa blok yang menggunakan ini adalah blok
@blockly/block-shareable-procedures. Biasanya, mereka melakukan serialisasi referensi ke model data pendukung, yang menyimpan statusnya.
Namun, jika parameter doFullSerialization
benar, maka mereka akan melakukan serialisasi semua statusnya. Blok prosedur yang dapat dibagikan menggunakan ini untuk memastikan bahwa saat
disalin dan ditempel, blok tersebut membuat model data pendukung baru, bukan merujuk ke
model yang ada.
mutationToDom dan domToMutation
mutationToDom
dan domToMutation
adalah hook serialisasi yang berfungsi dengan sistem serialisasi XML lama. Gunakan hook ini hanya jika Anda harus melakukannya (misalnya, Anda sedang mengerjakan codebase lama yang belum dimigrasikan), jika tidak, gunakan saveExtraState
dan loadExtraState
.
mutationToDom
menampilkan node XML yang merepresentasikan status tambahan
blok, dan domToMutation
menerima node XML yang sama dan menerapkan status ke
blok.
// 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
Anda 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 UI "mutator" default ke blok Anda.
Anda tidak harus menggunakan UI ini jika ingin menambahkan serialisasi tambahan. Anda dapat menggunakan UI kustom, seperti yang disediakan oleh plugin blocks-plus-minus, atau tidak menggunakan UI sama sekali.
menyusun dan menguraikan
UI default mengandalkan fungsi compose
dan decompose
.
decompose
"meledakkan" blok menjadi sub-blok yang lebih kecil yang dapat dipindahkan, ditambahkan, dan dihapus. Fungsi ini harus menampilkan "blok teratas" yang merupakan
blok utama di ruang kerja mutator yang terhubung ke sub-blok.
compose
kemudian menafsirkan konfigurasi sub-blok dan menggunakannya untuk
memodifikasi blok utama. Fungsi ini harus menerima "blok atas" yang ditampilkan oleh decompose
sebagai parameter.
Perhatikan bahwa fungsi ini "dicampur" ke dalam blok yang "dimutasi" sehingga 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
Secara opsional, Anda juga dapat menentukan fungsi saveConnections
yang berfungsi dengan
UI default. Fungsi ini memberi Anda kesempatan untuk mengaitkan turunan dari
blok utama (yang ada di ruang kerja utama) dengan sub-blok yang ada di
ruang kerja mutator Anda. Kemudian, Anda dapat menggunakan data ini untuk memastikan fungsi compose
terhubung kembali dengan benar ke turunan blok utama saat sub-blok
Anda disusun ulang.
saveConnections
harus menerima "blok atas" yang ditampilkan oleh fungsi decompose
Anda 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 mixin khusus, sehingga juga harus didaftarkan sebelum Anda dapat menggunakannya dalam definisi JSON jenis blok.
// 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 untuk dikaitkan dengan mutator sehingga Anda dapat menggunakannya di JSON.mixinObj
: Objek yang berisi berbagai metode mutasi. Misalnya,saveExtraState
danloadExtraState
.opt_helperFn
: Fungsi helper opsional yang akan berjalan di blok setelah mixin dicampur.opt_blockList
: Array jenis blok opsional (sebagai string) yang akan ditambahkan ke flyout di UI pengubah default, jika metode UI juga ditentukan.
Perhatikan bahwa tidak seperti ekstensi, setiap jenis blok hanya dapat memiliki satu mutator.
{
//...
"mutator": "controls_if_mutator"
}
Fungsi bantuan
Bersama dengan mixin, mutator dapat mendaftarkan fungsi helper. Fungsi ini dijalankan pada setiap blok jenis tertentu setelah dibuat dan mixinObj
ditambahkan. Hal ini dapat digunakan untuk menambahkan pemicu atau efek tambahan ke mutasi.
Misalnya, Anda dapat menambahkan helper ke blok seperti daftar yang menetapkan jumlah awal item:
var helper = function() {
this.itemCount_ = 5;
this.updateShape();
}