Uma pergunta comum é como modificar a definição de um bloco. Por exemplo, você pode adicionar uma verificação de conexão ou mudar um campo para uma entrada de valor.
Em geral, não é possível modificar uma definição de bloco no lugar.
Como modificar uma definição
Se você quiser modificar a definição de um tipo de bloco existente:
- Faça uma cópia da definição atual, incluindo os geradores de código de bloco.
- Modifique a cópia e dê um novo nome ao tipo.
- Adicione a nova definição a
Blockly.Blocks
.
Por que não posso modificar diretamente uma definição?
Se você quer saber por que não é possível modificar uma definição, continue lendo. Vamos considerar algumas possibilidades.
Modificar uma definição diretamente
Há duas maneiras de modificar diretamente a definição de um bloco existente: monkeypatching e bifurcação do código. Não recomendamos nenhum dos dois, porque você corre o risco de quebrar o código que depende do código com monkeypatch ou bifurcado. Ambas as técnicas também dificultam a integração de atualizações e correções de bugs. Para mais informações, consulte E se monkeypatching? e Fork Blockly.
Criar uma subclasse de uma definição
Talvez você queira subclassificar uma definição existente. Infelizmente,
isso não é possível porque as definições de bloco não são classes, são mixins.
Por exemplo, não há como substituir uma propriedade de cor porque a
definição não tem uma propriedade de cor. Em vez disso, ele tem uma função init
que chama setColour
para definir a propriedade de cor no bloco. Como a chamada
está dentro de init
, não há como substituí-la sem substituir toda a
função init
.
Substituir uma função em uma definição
É possível substituir uma função em uma definição:
Blockly.Blocks['existing_block'].init = function() {/*new function*/};
Isso funciona, mas você precisa copiar e modificar a função existente. Não é possível substituir magicamente apenas uma linha. Isso tem vários problemas:
- Não é muito diferente de copiar e modificar toda a definição.
- Não é possível usá-lo para modificar a função
init
de blocos definidos em JSON, como os blocos integrados do Blockly. Isso ocorre porque não há uma funçãoinit
para copiar. Ela é gerada no momento da execução. - Ele exige que você defina o bloco usando JavaScript, o que pode causar problemas com a localização.
Substituir os resultados do init
Uma maneira de "substituir apenas uma linha" de uma função init
é substituir a
função init
por uma que chame a função init
original e, em seguida,
substitua o resultado dessa chamada. Por exemplo, o código a seguir muda a
cor do bloco logic_null
:
const originalInit = Blockly.Blocks['logic_null'].init;
Blockly.Blocks['logic_null'].init = function() {
originalInit.call(this);
this.setColour(300);
}
Infelizmente, isso é menos útil do que parece. Exemplo:
Ampliar as verificações de conexão ou aplicar um validador de campo menos restritivo pode invalidar as suposições feitas por geradores de código de bloco e manipuladores de eventos.
A substituição de um campo por uma entrada de valor vai interromper os geradores de código de bloco e os validadores de campo e pode interromper os manipuladores de eventos. Também pode ser extremamente difícil fazer isso para blocos localizados, porque localidades diferentes podem resultar em blocos com tipos e ordens diferentes de entradas e campos.
Substituir um par de chave-valor em uma definição JSON
Se o JSON de um bloco estiver disponível publicamente, talvez seja possível substituir valores JSON individuais. Exemplo:
// Block definition.
blockJson = {...};
Blockly.Blocks['my_block'] = {
init: function() {
initJson(blockJson); // Called when the block is created.
}
}
// Third-party code.
blockJson.colour = 100;
No entanto, isso só funciona se o objeto JSON estiver disponível publicamente, a
definição definir explicitamente a função init
e a função init
chamar
initJson
. Ele não funciona se o JSON for transmitido para defineBlocksWithJsonArray
ou createBlockDefinitionsFromJsonArray
porque o JSON é processado antes que um
terceiro tenha a chance de modificá-lo. Os blocos integrados do Blockly usam
createBlockDefinitionsFromJsonArray
.
Mas e se o JSON não estiver definido dessa maneira? Não seria possível
substituir as propriedades JSON? Não. A definição contém uma função init
(não JSON) e não há uma função para converter uma função init
em JSON.
// Doesn't work. There is no getJson() function.
const json = Blockly.Blocks['existing_block'].getJson();
json['message0'] = 'my new message0';
Blockly.Blocks['existing_block'].init = function () {
initJson(json);
};
Design para reutilização
Ao projetar seus próprios blocos personalizados, você pode projetá-los de maneiras que promovam a reutilização.
Reutilizar JSON
Se você tiver dois blocos substancialmente semelhantes, crie uma definição JSON mãe e reutilize-a nas definições filhas. Exemplo:
const parentJson = {
// shared properties
};
Blockly.Blocks['child_block_1'] = {
init: function() {
initJson({...parentJson, colour: 100})
}
}
Blockly.Blocks['child_block_2'] = {
init: function() {
initJson({...parentJson, colour: 200})
}
}
Outra alternativa é definir o JSON em um objeto disponível publicamente e
transmitir esse objeto para initJson
na função init
. Isso permite
que outras pessoas substituam propriedades individuais. Para mais informações, consulte
Substituir um par de chave-valor em uma definição
JSON.
Reutilizar funções
Os blocos podem definir várias funções padrão, como manipuladores de eventos no nível do bloco, dicas de ferramentas personalizadas, validadores de campo e as funções usadas por modificadores, além de funções que fornecem comportamento personalizado, como uma função que define valores de campo a partir de dados externos, como a posição atual do braço de um robô.
Talvez seja possível reutilizar essas funções em blocos.
Usar um campo de lista suspensa
Se você tiver um conjunto de blocos substancialmente iguais, exceto por um operador, poderá projetar um único bloco com um campo suspenso para o operador. Exemplo:
- O bloco
logic_operation
integrado usa um menu suspenso com os operadoresand
eor
. - O bloco
math_arithmetic
integrado usa um menu suspenso com os operadores+
,-
,×
,÷
e^
.
Criar geradores de código para esses blocos geralmente é um pouco mais complexo, mas ainda mais fácil do que escrever e manter vários blocos.
Usar um mutador
Se você tiver um conjunto de blocos que representem variações diferentes da mesma
estrutura de programação, será possível criar um único bloco que use um
mutador. Por exemplo, o
bloco controls_if
integrado pode representar várias variações de instruções
if-then-else
.