Adicionar um campo de plug-in ao Block Factory

O Blockly Developer Tools permite criar blocos personalizados usando blocos. Ele é compatível com campos publicados como plug-ins, além dos campos que acompanham o Blockly. Se você criou um campo personalizado, siga este guia para adicionar suporte à Block Factory. O campo personalizado precisa ser publicado no npm antes de você adicionar suporte a ele. Você também precisa se comprometer a atualizar seu campo para acompanhar as alterações no Blockly. Caso contrário, poderemos removê-lo do Block Factory no futuro.

Desenvolvimento na Block Factory

O código-fonte do Block Factory está localizado no repositório blockly-samples no diretório examples/developer-tools.

Para enviar uma mudança nas Ferramentas para desenvolvedores em amostras de bloco, é necessário seguir as etapas comuns para o desenvolvimento em amostras em bloco. No entanto, diferentemente de trabalhar com plug-ins, será necessário executar npm install diretamente no diretório examples/developer-tools, em vez de no nível raiz dos exemplos de bloco.

Instalar o plug-in

Para que o Block Factory mostre seu campo personalizado na visualização, é necessário instalar o campo personalizado. Adicione seu campo como uma dependência npm das developer-tools. Em seguida, registre-o ou faça qualquer outro trabalho de configuração necessário em developer-tools/src/blocks/index.ts.

Criar um bloco para o campo

Como o Block Factory usa blocos para criar blocos personalizados, você precisará de um bloco que represente seu campo personalizado.

Criar a definição do bloco

É necessário projetar o bloco do campo. Se você quiser usar a meta, pode até projetá-lo usando o Block Factory. O bloco precisa permitir que o usuário defina a configuração exigida pelo campo, como valores padrão e um nome. Adicione essa definição de bloco a developer-tools/src/blocks/fields.ts e importe-a em developer-tools/src/blocks/index.ts.

Adicionar bloco à caixa de ferramentas

Em seguida, você precisa adicionar esse bloco à definição da caixa de ferramentas para torná-lo acessível aos usuários. A definição da caixa de ferramentas está localizada em developer-tools/src/toolbox.ts. Seu bloco deve ser adicionado à categoria "Campos".

Geradores de código

A Block Factory funciona usando o sistema gerador de código que você já conhece da Blockly. Cada bloco tem um gerador de código de bloco para cada tipo de saída gerado pela Block Factory, e os blocos pais montam o código dos blocos filhos na saída correta. Para adicionar suporte a um campo personalizado, é necessário incluir funções do gerador de código de bloco para cada uma das classes do gerador de código.

Crie um arquivo para seu bloco de campo no diretório output-generators/fields. Você vai adicionar os geradores de código de bloco para cada um dos geradores a seguir ao arquivo. Importe esse arquivo no arquivo blocks/index.ts para que as funções do gerador de código de bloco sejam carregadas no aplicativo.

Definição de JavaScript

O javascriptDefinitionGenerator cria o código que será incluído na definição JavaScript de um bloco que inclui seu campo personalizado. Normalmente, isso significa que o gerador de código de bloco precisa retornar uma linha de código parecida com .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName'). Observe que essa linha de código não inclui um ponto e vírgula, porque uma entrada que contém vários campos terá várias chamadas para appendField encadeadas. Os argumentos no construtor são extraídos dos valores definidos pelo usuário no bloco de campo. Confira um exemplo desse gerador de código de bloco para FieldAngle:

javascriptDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JavascriptDefinitionGenerator,
): string {
  const name = generator.quote_(block.getFieldValue('FIELDNAME'));
  const angle = block.getFieldValue('ANGLE');
  return `.appendField(new FieldAngle(${angle}), ${name})`;
};

O bloco de ângulo que o usuário arrastou da categoria "Campos" da caixa de ferramentas Block Factory tem dois campos:

  • FIELDNAME: o usuário pode definir o nome do campo no bloco personalizado.
  • ANGLE: o usuário pode definir o valor do ângulo padrão

Nesse gerador de código de bloco, recebemos o valor do ângulo padrão e o transmitimos como o único argumento para o construtor FieldAngle. O nome do campo é sempre transmitido como o segundo argumento para appendField.

Definição de JSON

O jsonDefinitionGenerator é semelhante, mas gera a parte da definição do bloco JSON que corresponde ao seu campo. Normalmente, esse código é um objeto JSON que inclui:

  • type: corresponde ao nome do seu campo no registro de campo do Blockly.
  • name: o usuário pode definir o nome do campo no bloco personalizado.
  • as outras propriedades personalizadas necessárias para o método de inicialização JSON do seu campo.

Confira um exemplo do FieldAngle novamente:

jsonDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JsonDefinitionGenerator,
): string {
  const code = {
    type: 'field_angle',
    name: block.getFieldValue('FIELDNAME'),
    angle: block.getFieldValue('ANGLE'),
  };
  return JSON.stringify(code);
};

Cabeçalhos de código

O Code Header Generator cria a saída Code Headers mostrada na Block Factory. Essa saída pode ser alternada entre importações de esmodule e tags de script, dependendo de como o usuário quer carregar o código. Portanto, há duas instâncias diferentes de gerador: uma para cada caso. Você precisa adicionar um gerador de código de blocos para cada um. Veja um exemplo para FieldAngle:

importHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `import {registerFieldAngle, FieldAngle} from '@blockly/field-angle';`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};

scriptHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `<script src="https://unpkg.com/@blockly/field-angle"></script>`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};

Esses geradores têm um método chamado addHeaderLine, que permite especificar uma linha de código que precisa ser chamada antes que o campo seja usado no código. Normalmente, isso inclui trabalhos como importar o campo ou carregá-lo com uma tag de script e talvez chamar uma função que registre o campo com o registro de campo do Blockly.

Para esses dois geradores de código de bloco, todo o código precisa ser adicionado com chamadas para addHeaderLine. Essa função garante que cada linha de cabeçalho seja mostrada apenas uma vez, mesmo que o bloco de campo personalizado seja usado várias vezes em um bloco personalizado. O gerador de código de bloco precisa retornar a string vazia.

stub de gerador

Por fim, temos o gerador que cria o stub do gerador para o campo. Neste gerador de código de bloco, você vai criar um código que ajuda o usuário a escrever o código que gera o código. Já se confundiu? É mais fácil do que parece!

O stub de gerador para um bloco personalizado inclui uma variável predefinida que representa todos os campos no bloco. Há também um TODO que o usuário precisa finalizar para reunir todas essas variáveis na string de código final que o bloco personalizado vai retornar. Isso significa que, normalmente, tudo o que seu gerador de código de blocos precisa fazer é retornar a linha que cria essa variável personalizada. Digamos que o usuário esteja criando um bloco personalizado que vai adicionar raios de luz solar à tela. Ele adiciona um campo de ângulo ao bloco e o nomeia como "SUN_DIRECTION". O stub de gerador para esse bloco incluiria a linha const angle_sun_direction = block.getFieldValue("SUN_DIRECTION");. Essa é a linha de código que nosso gerador de código de blocos para o campo "angle" precisa retornar:

generatorStubGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: GeneratorStubGenerator,
): string {
  const name = block.getFieldValue('FIELDNAME');
  const fieldVar = generator.createVariableName('angle', name);
  return `const ${fieldVar} = block.getFieldValue(${generator.quote_(
    name,
  )});\n`;
};

Para conseguir um nome padronizado para a variável, chame generator.createVariableName e transmita o tipo do seu campo (como angle, number etc.) com o nome que o usuário nomeou para o campo.

Realizar o teste

Depois de escrever todas essas partes, você poderá iniciar a Block Factory executando npm start no diretório blockly-samples/examples/developer-tools. Você deve conseguir arrastar seu bloco da categoria de campo, adicioná-lo a uma entrada em um bloco e observar a mudança do resultado. Verifique se a visualização do bloco está correta e se o código de cada uma das seções de saída está correto.