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