Ajouter un champ de plug-in à Block Factory

Les outils pour les développeurs Blockly vous permettent de créer des blocs personnalisés à l'aide de blocs. Elle est compatible avec les champs publiés en tant que plug-ins, en plus de ceux fournis avec la version de base de Blockly. Si vous avez créé un champ personnalisé, vous pouvez le prendre en charge dans Block Factory en suivant ce guide. Le champ personnalisé doit être publié sur npm pour que vous puissiez le rendre compatible. Vous devez également vous engager à mettre à jour votre champ pour suivre les modifications apportées à Blockly. Sinon, nous devrons peut-être le supprimer de Block Factory à l'avenir.

Développement sur Block Factory

Le code source de Block Factory se trouve dans le dépôt blockly-samples du répertoire examples/developer-tools.

Pour envoyer une modification aux outils de développement dans des échantillons par blocs, vous devez suivre les étapes habituelles de développement dans des échantillons par blocs. Toutefois, contrairement à l'utilisation de plug-ins, vous devez exécuter npm install directement à partir du répertoire examples/developer-tools, plutôt qu'au niveau racine des exemples blockly.

Installer le plug-in

Pour que la fabrique de blocs affiche votre champ personnalisé dans l'aperçu, vous devez l'installer. Ajoutez votre champ en tant que dépendance npm de developer-tools. Ensuite, enregistrez-le ou effectuez toute autre tâche de configuration nécessaire dans developer-tools/src/blocks/index.ts.

Créer un bloc pour le champ

Étant donné que la fabrique de blocs utilise des blocs pour créer des blocs personnalisés, vous aurez besoin d'un bloc qui représente votre champ personnalisé.

Créer la définition de bloc

Vous devez concevoir le bloc pour votre champ. Si vous souhaitez obtenir des métadonnées, vous pouvez même le concevoir à l'aide de Block Factory. Le bloc doit permettre à l'utilisateur de configurer la configuration requise par votre champ, comme les valeurs par défaut et un nom. Ajoutez cette définition de bloc à developer-tools/src/blocks/fields.ts, puis importez-la dans developer-tools/src/blocks/index.ts.

Ajouter un bloc à la boîte à outils

Vous devez ensuite ajouter ce bloc à la définition de la boîte à outils pour le rendre accessible aux utilisateurs. La définition de la boîte à outils se trouve dans developer-tools/src/toolbox.ts. Votre bloc doit être ajouté à la catégorie "Champs".

Générateurs de code

La fabrique de blocs fonctionne avec le générateur de code que vous connaissez déjà de Blockly. Chaque bloc dispose d'un générateur de code de bloc pour chaque type de sortie généré par la fabrique de blocs, et les blocs parents assemblent le code des blocs enfants dans la sortie appropriée. Pour permettre l'utilisation d'un champ personnalisé, vous devez ajouter des fonctions de générateur de code de bloc pour chacune des classes du générateur de code.

Créez un fichier pour votre bloc "field" dans le répertoire output-generators/fields. Vous allez ajouter les générateurs de code de bloc de chacun des générateurs suivants à ce fichier. Importez ce fichier dans le fichier blocks/index.ts afin de charger les fonctions du générateur de code de bloc dans l'application.

Définition JavaScript

javascriptDefinitionGenerator crée le code qui sera inclus dans la définition JavaScript d'un bloc qui inclut votre champ personnalisé. En général, cela signifie que le générateur de code de bloc doit renvoyer une ligne de code semblable à .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName'). Notez que cette ligne de code n'inclut pas de point-virgule, car une entrée contenant plusieurs champs comportera plusieurs appels à appendField chaînés ensemble. Les arguments du constructeur sont extraits des valeurs que l'utilisateur a définies dans le bloc "field". Voici un exemple de ce générateur de code de bloc pour 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})`;
};

Le bloc d'angle que l'utilisateur a fait glisser depuis la catégorie "Champs" de la boîte à outils de la fabrique de blocs comporte deux champs:

  • FIELDNAME: l'utilisateur peut définir le nom du champ dans son bloc personnalisé.
  • ANGLE: l'utilisateur peut définir la valeur d'angle par défaut

Dans ce générateur de code de bloc, nous obtenons la valeur d'angle par défaut et la transmettons en tant que seul argument au constructeur FieldAngle. Le nom du champ est toujours transmis en tant que deuxième argument à appendField.

Définition JSON

La valeur jsonDefinitionGenerator est semblable, mais génère la partie de la définition de bloc JSON qui correspond à votre champ. En règle générale, ce code est un objet JSON qui inclut les éléments suivants:

  • type: correspond au nom de votre champ dans le registre de champs Blockly
  • name: l'utilisateur peut définir le nom du champ dans son bloc personnalisé.
  • toute autre propriété personnalisée requise par la méthode d'initialisation JSON de votre champ.

Voici un autre exemple issu 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);
};

En-têtes de code

Le générateur d'en-têtes de code crée la sortie des en-têtes de code affichée dans la fabrique de blocs. Ce résultat peut être basculé entre les importations d'esmodules et les tags de script, selon la manière dont l'utilisateur souhaite charger le code. Il existe donc deux instances de générateur différentes: une pour chaque cas. Vous devez ajouter un générateur de code de bloc à chacun d'eux. Voici un exemple pour 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 '';
};

Ces générateurs disposent d'une méthode appelée addHeaderLine qui vous permet de spécifier une ligne de code à appeler avant d'utiliser votre champ dans le code. En général, cela inclut des tâches telles que l'importation ou le chargement du champ via un tag de script, et éventuellement l'appel d'une fonction qui enregistre le champ dans le registre de champs de Blockly.

Pour ces deux générateurs de code de bloc, tout le code doit être ajouté via des appels à addHeaderLine. Cette fonction garantit que chaque ligne d'en-tête ne s'affiche qu'une seule fois, même si votre bloc de champ personnalisé est utilisé plusieurs fois dans un même bloc personnalisé. Le générateur de code de bloc doit renvoyer une chaîne vide.

Bouchon de générateur

Enfin, nous avons le générateur qui crée le bouchon de générateur pour le champ. Dans ce générateur de code de bloc, vous allez écrire du code qui génère du code qui aide l'utilisateur à écrire du code. Vous vous sentez un peu perdu ? C'est plus facile qu'il n'y paraît !

Le bouchon du générateur d'un bloc personnalisé comprend une variable prédéfinie représentant chaque champ du bloc. Il y a ensuite un TODO que l'utilisateur doit terminer pour assembler toutes ces variables dans la chaîne de code finale que son bloc personnalisé renverra. Cela signifie que votre générateur de code de bloc doit généralement renvoyer la ligne qui crée cette variable personnalisée. Supposons que l'utilisateur crée un bloc personnalisé qui ajoutera des rayons du soleil à son canevas. Ils ajoutent un champ d'angle au bloc et le nomment "SUN_DIRECTION". Le bouchon de générateur pour ce bloc inclurait la ligne const angle_sun_direction = block.getFieldValue("SUN_DIRECTION");. C'est la ligne de code que notre générateur de code de bloc pour le champ d'angle doit renvoyer:

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

Pour obtenir un nom standardisé pour la variable, vous pouvez appeler generator.createVariableName et transmettre le type de votre champ (par exemple, angle, number, etc.) ainsi que le nom donné par l'utilisateur.

Tester

Une fois que vous avez écrit tous ces éléments, vous devriez pouvoir démarrer la fabrique de blocs en exécutant npm start dans le répertoire blockly-samples/examples/developer-tools. Vous devriez pouvoir faire glisser votre bloc depuis la catégorie de champ, l'ajouter à une entrée d'un bloc et observer l'évolution du résultat. Vérifiez que l'aperçu du bloc est correct et que le code de chacune des sections de sortie est correct.