Agrega un campo de complemento a Block Factory

Las Herramientas para desarrolladores de Blockly te permiten crear bloques personalizados con bloques. Es compatible con los campos que se publican como complementos, además de los campos que vienen con las funciones principales de Blockly. Si creaste un campo personalizado, puedes seguir esta guía para agregarle compatibilidad con la fábrica de bloques. El campo personalizado debe publicarse en npm para que puedas agregarle compatibilidad. 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 la fábrica de bloques

El código fuente de la fábrica de bloques se encuentra en el repositorio de muestras en bloque del directorio examples/developer-tools.

Si quieres enviar un cambio a las Herramientas para desarrolladores en muestras en bloque, deberás seguir los pasos típicos para desarrollar en muestras en bloque. Sin embargo, a diferencia de lo que sucede 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 las muestras en bloque.

Instala el complemento

Para que la fábrica de bloques muestre tu campo personalizado en la vista previa, es necesario que lo instales. Agrega tu campo como una dependencia de npm de las herramientas para desarrolladores. 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 la fábrica de bloques 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 obtener meta, incluso puedes diseñarlo con Block Factory. El bloque debería permitir que el usuario establezca la configuración requerida por el 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 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 caja de herramientas se encuentra en developer-tools/src/toolbox.ts. El bloque debería agregarse a la categoría "Campos".

Generadores de código

La fábrica de bloques funciona con el sistema generador de código con el que ya estás familiarizado de Blockly. Cada bloque tiene un generador de código de bloque para cada tipo de salida que genera la fábrica de bloques, y los bloques superiores ensamblan el código de los bloques secundarios en la salida correcta. Para agregar compatibilidad con un campo personalizado, deberás agregar funciones del generador de código de bloque para cada una de las clases de Generador de código.

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

Definición de JavaScript

javascriptDefinitionGenerator crea el código que se incluirá en la definición de JavaScript para un bloque que incluye tu campo personalizado. Por lo general, esto significa que el generador de código de bloque debería mostrar una línea de código similar a .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 estableció en el bloque de campo. El siguiente es un ejemplo de este generador de código de bloque 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 fábrica de bloques tiene dos campos:

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

En este generador de código de bloque, obtenemos el valor de á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

jsonDefinitionGenerator es similar, pero esto 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.

A continuación, se muestra un 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 la fábrica de bloques. Este resultado se puede alternar entre importaciones de esmodule y etiquetas de secuencia de comandos, según cómo el usuario quiera 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 bloque para cada uno de ellos. Este es un ejemplo de 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 a la 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 registre el campo con el registro de campo de Blockly.

Para estos dos generadores de código de bloque, todo el código se debe agregar a través de llamadas a addHeaderLine. Esta función garantiza que cada línea de encabezado se muestre solo una vez, incluso si tu bloque de campo personalizado se usa varias veces en un bloque de este tipo. El generador de código de bloque debería mostrar la cadena vacía.

stub de generador

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

El stub de generador de un bloque personalizado incluye una variable prediseñada que representa cada campo del bloque. Luego, hay un TODO que el usuario debe terminar para ensamblar todas estas variables en la cadena de código final que mostrará su bloque personalizado. Eso significa que, por lo general, todo lo que debe hacer el generador de código de bloque es mostrar la línea que crea la variable personalizada. Supongamos que el usuario está creando un bloque personalizado que agregará rayos de luz solar a su lienzo. Agrega un campo de ángulo al bloque y le asigna el nombre "SUN_DIRECTION". El stub de 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 debe mostrar el generador de código de bloque para el campo de ángulo:

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.) junto con el nombre que el usuario le asignó.

Pruébalo

Después de haber escrito todos estos fragmentos, deberías poder iniciar la fábrica de bloques con la ejecución de npm start en el directorio blockly-samples/examples/developer-tools. Deberías poder arrastrar tu bloque de la categoría de campo, agregarlo a una entrada en un bloque y observar el cambio de salida. Comprueba que la vista previa del bloque se vea bien y que el código para cada una de las secciones del resultado sea correcto.