Agrega un campo de complemento a Block Factory

Blockly Developer Tools te permite crear bloques personalizados con bloques. Admite campos que se publican como complementos, además de los campos que se incluyen en el núcleo de Blockly. Si creaste un campo personalizado, puedes agregar compatibilidad con él en Block Factory siguiendo esta guía. El campo personalizado debe publicarse en npm antes de que puedas agregar compatibilidad con él. También debes comprometerte a actualizar tu campo para mantenerte al día con los cambios en Blockly. De lo contrario, es posible que debamos quitarlo de Block Factory en el futuro.

Desarrollo en Block Factory

El código fuente de Block Factory se encuentra en el repositorio de blockly-samples, en el directorio examples/developer-tools.

Para enviar un cambio a las Herramientas para desarrolladores en blockly-samples, deberás seguir los pasos típicos para desarrollar en blockly-samples. Sin embargo, a diferencia de cuando trabajas con complementos, deberás ejecutar npm install directamente desde el directorio examples/developer-tools, en lugar de hacerlo en el nivel raíz de blockly-samples.

Instala el complemento

Para que Block Factory muestre tu campo personalizado en la vista previa, debe instalarlo. Agrega tu campo como una dependencia de npm de developer-tools. Luego, regístralo o realiza cualquier otro trabajo de configuración necesario en developer-tools/src/blocks/index.ts.

Crea un bloque para el campo

Dado que Block Factory usa bloques para crear bloques personalizados, necesitarás un bloque que represente tu campo personalizado.

Crea la definición del bloque

Debes diseñar el bloque para tu campo. Si quieres ir más allá, puedes diseñarlo con Block Factory. El bloque debe permitir que el usuario configure los parámetros necesarios para tu campo, como los valores predeterminados y un nombre. Agrega esta definición de bloque a developer-tools/src/blocks/fields.ts y, luego, impórtala en developer-tools/src/blocks/index.ts.

Agregar un bloque a la caja de herramientas

A continuación, debes agregar este bloque a la definición de la caja de herramientas para que los usuarios puedan acceder a él. La definición de la colección de herramientas se encuentra en developer-tools/src/toolbox.ts. Tu bloque se debería agregar a la categoría "Campos".

Generadores de código

Block Factory funciona con el sistema de Code Generator que ya conoces de Blockly. Cada bloque tiene un generador de código de bloque para cada tipo de salida que genera Block Factory, y los bloques principales ensamblan el código de los bloques secundarios en la salida correcta. Para agregar compatibilidad con un campo personalizado, deberás agregar funciones de generador de código de bloque para cada una de las clases de Code Generator.

Crea un archivo para tu bloque de campo en el directorio output-generators/fields. Agregarás los generadores de código de bloques para cada uno de los siguientes generadores a este archivo. Importa este archivo en el archivo blocks/index.ts para que las funciones del generador de código en bloques se carguen en la aplicación.

Definición de JavaScript

El javascriptDefinitionGenerator crea el código que se incluirá en la definición de JavaScript para un bloque que incluya tu campo personalizado. Por lo general, esto significa que el generador de código en bloque debe devolver una línea de código que se vea como .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName'). Ten en cuenta que esta línea de código no incluye un punto y coma, ya que una entrada que contiene varios campos tendrá varias llamadas a appendField encadenadas. Los argumentos del constructor se extraen de los valores que el usuario establece en el bloque de campo. Este es un ejemplo del generador de código en bloques 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})`;
};

El bloque de ángulo que el usuario arrastró desde la categoría "Campos" de la caja de herramientas de Block Factory tiene dos campos:

  • FIELDNAME: El usuario puede establecer el nombre del campo en su bloque personalizado.
  • ANGLE: El usuario puede establecer el valor del ángulo predeterminado.

En este generador de código en bloques, obtenemos el valor del ángulo predeterminado y lo pasamos como el único argumento al constructor FieldAngle. El nombre del campo siempre se pasa como el segundo argumento a appendField.

Definición de JSON

El comando jsonDefinitionGenerator es similar, pero genera la parte de la definición del bloque JSON que corresponde a tu campo. Por lo general, este código es un objeto JSON que incluye lo siguiente:

  • type: Corresponde al nombre de tu campo en el registro de campos de Blockly.
  • name: El usuario puede establecer el nombre del campo en su bloque personalizado.
  • Cualquier otra propiedad personalizada que necesite el método de inicialización JSON de tu campo.

Aquí tienes otro ejemplo de FieldAngle:

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);
};

Encabezados de código

El generador de encabezados de código crea el resultado de encabezados de código que se muestra en Block Factory. Este resultado se puede alternar entre las importaciones de esmodule y las etiquetas de secuencia de comandos, según cómo el usuario desee cargar el código, por lo que en realidad hay dos instancias de generador diferentes: una para cada caso. Debes agregar un generador de código de bloques para cada uno de ellos. Este es un ejemplo 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 '';
};

Estos generadores tienen un método llamado addHeaderLine que te permite especificar una línea de código que se debe llamar antes de que se use tu campo en el código. Por lo general, esto incluye tareas como importar el campo o cargarlo a través de una etiqueta de secuencia de comandos y, tal vez, llamar a una función que registrará el campo en el registro de campos de Blockly.

En el caso de estos dos generadores de código en bloque, todo el código se debe agregar a través de llamadas a addHeaderLine. Esta función garantizará que cada línea de encabezado solo se muestre una vez, incluso si tu bloque de campos personalizados se usa varias veces en un bloque personalizado. El generador de código de bloques debería devolver la cadena vacía.

Stub del generador

Por último, tenemos el generador que crea el código auxiliar del generador para el campo. En este generador de código de bloques, escribirás código que genera código que ayuda al usuario a escribir código que genera código. ¿Ya te confundiste? Es más fácil de lo que parece.

El código auxiliar del generador para un bloque personalizado incluye una variable prediseñada que representa cada campo del bloque. Luego, hay un TODO que el usuario debe completar para ensamblar todas estas variables en la cadena de código final que devolverá su bloque personalizado. Esto significa que, por lo general, todo lo que debe hacer tu generador de código en bloques es devolver la línea que crea esta variable personalizada. Supongamos que el usuario está creando un bloque personalizado que agregará rayos de luz solar a su lienzo. Agregan un campo de ángulo al bloque y lo llaman "SUN_DIRECTION". El código auxiliar del generador para este bloque incluiría la línea const angle_sun_direction = block.getFieldValue("SUN_DIRECTION");. Esa es la línea de código que nuestro generador de código en bloques para el campo de ángulo debe devolver:

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 obtener un nombre estandarizado para la variable, puedes llamar a generator.createVariableName y pasar el tipo de tu campo (como angle, number, etcétera) junto con el nombre que el usuario le asignó a su campo.

Pruébalo

Después de escribir todas estas partes, deberías poder iniciar Block Factory ejecutando npm start en el directorio blockly-samples/examples/developer-tools. Deberías poder arrastrar tu bloque desde la categoría de campo, agregarlo a una entrada en un bloque y observar cómo cambia el resultado. Verifica que la vista previa del bloque se vea bien y que el código de cada una de las secciones de salida sea correcto.