向 Block Factory 添加插件字段

Blockly 开发者工具可让您使用代码块创建自定义代码块!除了核心 Blockly 附带的字段之外,它还支持以插件形式发布的字段。如果您已创建自定义字段,可以按照本指南中的说明向 Block Factory 添加对该字段的支持。自定义字段必须先发布到 npm,然后才能添加对它的支持。您还需要承诺更新您的字段,以跟上 Blockly 的变化,否则我们未来可能需要从 Block Factory 中移除该字段。

在 Block Factory 上开发

Block Factory 的源代码位于 blockly-samples 代码库中的 examples/developer-tools 目录中。

如需提交对 blockly-samples 中开发者工具的更改,您需要遵循在 blockly-samples 中进行开发的典型步骤。不过,与使用插件不同的是,您需要直接从 examples/developer-tools 目录运行 npm install,而不是在 blockly-samples 的根级别运行。

安装插件

为了让 Block Factory 在预览中显示您的自定义字段,它需要安装该自定义字段。将您的字段添加为 developer-tools 的 npm 依赖项。然后,在 developer-tools/src/blocks/index.ts 中注册该服务或执行任何其他必要的设置工作。

为字段创建块

由于 Block Factory 使用代码块来创建自定义代码块,因此您需要一个表示自定义字段的代码块。

创建块定义

您需要为自己的字段设计块;如果您想获取元数据,甚至可以使用 Block Factory 来设计块!该块应允许用户配置字段所需的设置,例如默认值和名称。将此块定义添加到 developer-tools/src/blocks/fields.ts,并在 developer-tools/src/blocks/index.ts 中导入。

向工具箱添加块

接下来,您需要将此块添加到工具箱定义中,以便用户可以访问它。工具箱定义位于 developer-tools/src/toolbox.ts 中。您的块应添加到“字段”类别中。

代码生成器

Block Factory 通过使用您已从 Blockly 中熟悉的 Code Generator 系统来运行。每个块都有一个块代码生成器,用于生成块工厂生成的每种类型的输出,而父块会将子块的代码组装成正确的输出。如需添加对自定义字段的支持,您需要为每个代码生成器类添加块代码生成器函数。

output-generators/fields 目录中为您的字段块创建一个文件。您将为以下每个生成器向此文件添加块代码生成器。在 blocks/index.ts 文件中导入此文件,以便将块代码生成器函数加载到应用中。

JavaScript 定义

javascriptDefinitionGenerator 会创建将包含在包含自定义字段的块的 JavaScript 定义中的代码。通常,这意味着块代码生成器应返回类似于 .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName') 的代码行。请注意,此行代码包含分号,因为包含多个字段的输入将有多个串联在一起的 appendField 调用。构造函数中的实参是从用户在字段块中设置的值中提取的。以下是 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})`;
};

用户从 Block Factory 工具箱的“字段”类别中拖出的角度代码块包含两个字段:

  • FIELDNAME:用户可以在自定义块中设置字段的名称
  • ANGLE:用户可以设置默认角度值

在此代码块生成器中,我们获取默认角度值,并将其作为唯一实参传递给 FieldAngle 构造函数。字段名称始终作为 appendField 的第二个实参传递。

JSON 定义

jsonDefinitionGenerator 与之类似,但它会输出与您的字段对应的 JSON 块定义部分。此代码通常是一个 JSON 对象,包含以下内容:

  • type:与 Blockly 字段注册表中的字段名称相对应
  • name:用户可以在自定义块中设置字段的名称
  • 字段的 JSON 初始化方法所需的任何其他自定义属性。

下面是 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);
};

代码标头

代码标头生成器会创建块工厂中显示的代码标头输出。此输出可以在 esmodule 导入和脚本标记之间切换,具体取决于用户希望如何加载代码,因此实际上有两个不同的生成器实例:每种情况各一个。您需要为每个块添加块代码生成器。以下是 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 '';
};

这些生成器有一个名为 addHeaderLine 的方法,可让您指定在代码中使用字段之前应调用的代码行。通常,这包括导入字段或通过脚本标记加载字段等工作,可能还包括调用将字段注册到 Blockly 字段注册表中的函数。

对于这两个块代码生成器,所有代码都应通过对 addHeaderLine 的调用来添加。此函数可确保每个标题行仅显示一次,即使您的自定义字段块在一个自定义块中使用了多次也是如此。块代码生成器应返回空字符串。

生成器桩

最后,我们有一个生成器,用于为字段创建生成器桩。在这个块代码生成器中,您将编写代码来生成代码,以帮助用户编写代码来生成代码。有点混乱了?比您想象的要简单得多!

自定义块的生成器桩包含一个预制变量,用于表示块上的每个字段。然后,用户必须完成 TODO,才能将所有这些变量组装成自定义代码块将返回的最终代码字符串。这意味着,通常情况下,代码块生成器只需返回创建此自定义变量的行即可。假设用户正在制作一个自定义块,该块会将阳光添加到画布中。它们向代码块添加一个角度字段,并将其命名为 "SUN_DIRECTION"。相应块的生成器桩会包含 const angle_sun_direction = block.getFieldValue("SUN_DIRECTION"); 行。这是角度字段的块代码生成器需要返回的代码行:

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

如需获取变量的标准化名称,您可以调用 generator.createVariableName 并传入字段的类型(例如 anglenumber 等)以及用户为字段指定的名称。

测试应用

编写完所有这些内容后,您应该能够在 blockly-samples/examples/developer-tools 目录中运行 npm start 来启动 Block Factory。您应该能够从字段类别中拖动代码块,将其添加到代码块的输入中,并观察输出的变化。检查块的预览效果是否正确,以及每个输出部分的相应代码是否正确。