Le estensioni sono funzioni che vengono eseguite su ciascun blocco di un determinato tipo è stato creato. Spesso aggiungono comportamenti o configurazioni personalizzati a un blocco.
Un mutatore è un tipo speciale di estensione che aggiunge la serie personalizzata, e a volte nell'interfaccia utente.
Estensioni
Le estensioni sono funzioni che vengono eseguite su ciascun blocco di un determinato tipo è stato creato. Può aggiungere una configurazione personalizzata (ad es. impostare la descrizione comando del blocco) oppure un comportamento personalizzato (ad es. l'aggiunta di un listener di eventi al blocco).
// 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;
});
});
Le estensioni devono essere "registrate" in modo che possano essere associate a una stringa
chiave. Poi puoi assegnare questa chiave stringa alla proprietà extensions
del tuo
JSON del tipo di blocco
per applicare
al blocco.
{
//...,
"extensions": ["parent_tooltip_extension",]
}
Puoi anche aggiungere più estensioni contemporaneamente. Tieni presente che extensions
deve essere un array, anche se applichi una sola estensione.
{
//...,
"extensions": ["parent_tooltip_extension", "break_warning_extension"],
}
Mixin
Blockly offre anche un metodo pratico per le situazioni in cui vuoi aggiungere proprietà/funzioni helper in un blocco, ma non eseguirle immediatamente. Questo ti permette di registrare un mixin contenente tutti i tuoi metodi/proprietà aggiuntivi. L'oggetto mixin viene poi aggregato in una funzione che applica il mixin ogni volta che un'istanza viene creato il tipo di blocco specificato.
Blockly.Extensions.registerMixin('my_mixin', {
someProperty: 'a cool value',
someMethod: function() {
// Do something cool!
}
))`
È possibile fare riferimento alle chiavi stringa associate ai mixin in JSON come qualsiasi altro .
{
//...,
"extensions": ["my_mixin"],
}
Mutatori
Un mutatore è un tipo speciale di estensione che aggiunge un'ulteriore serializzazione (extra
che viene salvato e caricato) in un blocco. Ad esempio, lo strumento
I blocchi controls_if
e list_create_with
richiedono una serializzazione aggiuntiva per
possono salvare quanti input hanno.
Tieni presente che cambiare la forma del blocco non significa necessariamente che
un'ulteriore serializzazione. Ad esempio, il blocco math_number_property
cambia
di forma, ma lo fa in base a un campo a discesa, il cui valore viene già
serializzato. Di conseguenza, può utilizzare solo un campo
strumento di convalida e non
serve un mutatore.
Consulta la serializzazione per maggiori informazioni su quando e quando è necessario un mutatore.
I mutatori forniscono inoltre una UI integrata che permette agli utenti di cambiare la forma dei blocchi se fornisci alcuni metodi facoltativi.
Hook di serializzazione
I mutatori hanno due coppie di hook di serializzazione con cui funzionano. Un paio di ganci funziona con il nuovo sistema di serializzazione JSON, mentre l'altra coppia funziona con un vecchio sistema di serializzazione XML. Devi fornire almeno una di queste coppie.
salvaExtraState e loadExtraState
saveExtraState
e loadExtraState
sono hook di serializzazione che funzionano con
nuovo sistema di serializzazione JSON. saveExtraState
restituisce un file JSON serializzabile
che rappresenta lo stato aggiuntivo del blocco e loadExtraState
accetta lo stesso valore serializzabile JSON e lo applica al blocco.
// 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_();
},
Il risultato JSON sarà simile a questo:
{
"type": "lists_create_with",
"extraState": {
"itemCount": 3 // or whatever the count is
}
}
Nessuno stato
Se il blocco è nello stato predefinito quando è serializzato,
Il metodo saveExtraState
può restituire null
per indicarlo. Se le tue
Il metodo saveExtraState
restituisce null
, quindi nessuna proprietà extraState
viene aggiunta a
il file JSON. In questo modo le dimensioni del file salvato saranno ridotte.
Serializzazione e backup completi dei dati
saveExtraState
riceve anche un parametro doFullSerialization
facoltativo. Questo
è utilizzato da blocchi che fanno riferimento allo stato serializzato da un
serializzatore (come i modelli dei dati di backup). Il parametro segnala che
lo stato di riferimento non sarà disponibile quando il blocco viene deserializzato, quindi
deve serializzare tutto lo stato di supporto. Ad esempio,
true quando un singolo blocco viene serializzato o quando un blocco viene copiato e incollato.
Due casi d'uso comuni sono:
- Quando un singolo blocco viene caricato in un'area di lavoro in cui i dati di supporto modello non esiste, ha informazioni sufficienti nel proprio stato per per creare un nuovo modello dei dati.
- Quando un blocco viene copiato e incollato, viene sempre creato un nuovo supporto del modello dei dati, invece di farvi riferimento a uno esistente.
Alcuni blocchi che utilizzano questo metodo
Blocchi @blockly/block-shareable-procedures. Normalmente
serializzano un riferimento a un modello dei dati di supporto, che archivia il loro stato.
Se invece il parametro doFullSerialization
è true, serializzano tutti
il proprio stato. I blocchi di procedura condivisibili lo utilizzano per garantire che,
vengono copiati e incollati creano un nuovo modello dei dati di supporto, anziché fare riferimento a un
un modello esistente.
mutationToDom e domToMutation
mutationToDom
e domToMutation
sono hook di serializzazione che funzionano con
un vecchio sistema di serializzazione XML. Usa questi ganci solo se necessario (ad es. se devi
lavorare su un vecchio codebase di cui non è stata ancora eseguita la migrazione), altrimenti usa
saveExtraState
e loadExtraState
.
mutationToDom
restituisce un nodo XML che rappresenta lo stato aggiuntivo del
bloccare e domToMutation
accetta lo stesso nodo XML e applica lo stato a
bloccare il blocco.
// 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_();
},
Il codice XML risultante avrà il seguente aspetto:
<block type="lists_create_with">
<mutation items="3"></mutation>
</block>
Se la funzione mutationToDom
restituisce un valore nullo, non sarà presente nessun elemento aggiuntivo.
aggiunti al file XML.
Hook UI
Se fornisci determinate funzioni come parte del mutatore, Blockly aggiungerà un "mutatore" predefinito interfaccia utente per il tuo blocco.
Non è necessario utilizzare questa UI se vuoi aggiungere un'ulteriore serializzazione. Potresti usano una UI personalizzata, come blocchi-più-meno plug-in o non potresti utilizzare alcuna UI.
comporre e scomporre
La UI predefinita si basa sulle funzioni compose
e decompose
.
decompose
"esplode" il blocco in blocchi secondari più piccoli che possono essere spostati
aggiunti ed eliminati. Questa funzione dovrebbe restituire un "blocco superiore" ovvero
il blocco principale nell'area di lavoro del mutatore a cui si connettono i sottoblocchi.
compose
interpreta quindi la configurazione dei sottoblocchi e li utilizza per
modificare il blocco principale. Questa funzione deve accettare il "blocco superiore" che era
restituito da decompose
come parametro.
Tieni presente che queste funzioni vengono "combinate" al blocco che viene "mutato" quindi this
può essere utilizzato per fare riferimento a quel blocco.
// 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
Se vuoi, puoi anche definire una funzione saveConnections
che funziona con
l'interfaccia utente predefinita. Questa funzione ti offre la possibilità di associare i tuoi figli
principale (che esiste nell'area di lavoro principale) con blocchi secondari esistenti
nell'area di lavoro del mutatore. Puoi quindi utilizzare questi dati per verificare che compose
funzioni correttamente ricollega gli elementi secondari del blocco principale quando
vengono riorganizzati.
saveConnections
deve accettare il "blocco superiore" restituito da decompose
come parametro. Se la funzione saveConnections
è definita, Blockly
lo chiamerà prima di chiamare il numero 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();
}
},
In fase di registrazione
I mutatori sono solo un particolare tipo di estensione, quindi devono essere registrati prima che tu possa utilizzarli in JSON del tuo tipo di blocco definizione.
// 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
: una stringa da associare al mutatore per poterla utilizzare in JSON.mixinObj
: un oggetto contenente i vari metodi di mutazione. Ad es.saveExtraState
eloadExtraState
.opt_helperFn
: una funzione helper facoltativa che devi eseguire sul blocco dopo aver mixato il mix.opt_blockList
: un array facoltativo di tipi di blocchi (come stringhe) che verranno aggiunti al riquadro a comparsa nell'interfaccia utente del mutatore predefinito, se anche i metodi UI sono definito.
Tieni presente che, a differenza delle estensioni, ogni tipo di blocco può avere un solo mutatore.
{
//...
"mutator": "controls_if_mutator"
}
Funzione helper
Insieme al mixin, un mutatore può registrare una funzione aiutante. Questa funzione è viene eseguito su ciascun blocco del tipo specificato dopo la sua creazione e il mixinObj aggiunto. Può essere usato per aggiungere ulteriori trigger o effetti a una mutazione.
Ad esempio, potresti aggiungere un elemento di supporto al blocco simile a un elenco che imposti numero iniziale di elementi:
var helper = function() {
this.itemCount_ = 5;
this.updateShape();
}