Blockly デベロッパー ツールでは、ブロックを使用してカスタム ブロックを作成できます。コア Blockly に付属しているフィールドに加え、プラグインとして公開されるフィールドがサポートされています。カスタム フィールドを作成した場合は、このガイドに沿ってそのサポートをブロック ファクトリに追加できます。カスタム フィールドは、サポートを追加する前に npm で公開されている必要があります。また、Blockly の変更に対応するためにフィールドの更新を確約する必要があります。そうしないと、将来、ブロック ファクトリからフィールドを削除する必要が生じる可能性があります。
Block Factory での開発
ブロック ファクトリのソースコードは、examples/developer-tools
ディレクトリの blockly-samples リポジトリにあります。
ブロックリー サンプルでデベロッパー ツールに変更を送信するには、ブロックリーサンプルで開発する際の一般的な手順に従う必要があります。ただし、プラグインを使用する場合とは異なり、npm
install
はブロックリー サンプルのルートレベルではなく、examples/developer-tools
ディレクトリから直接実行する必要があります。
プラグインをインストールする
ブロック ファクトリでカスタム フィールドをプレビューに表示するには、カスタム フィールドをインストールする必要があります。フィールドを、developer-tools の npm 依存関係として追加します。次に、その ID を登録するか、developer-tools/src/blocks/index.ts
で必要なその他の設定作業を行います。
フィールドのブロックを作成する
ブロック ファクトリではブロックを使用してカスタム ブロックを作成するため、カスタム フィールドを表すブロックが必要です。
ブロック定義を作成する
フィールドのブロックを設計する必要があります。メタを取得する場合は、Block Factory を使用して設計することもできます。このブロックでは、デフォルト値や名前など、フィールドに必要な設定をユーザーが構成できるようにする必要があります。このブロック定義を developer-tools/src/blocks/fields.ts
に追加し、developer-tools/src/blocks/index.ts
にインポートします。
ツールボックスにブロックを追加する
次に、このブロックをツールボックスの定義に追加して、ユーザーがアクセスできるようにします。ツールボックスの定義は developer-tools/src/toolbox.ts
にあります。ブロックが [項目]カテゴリに追加され
コード生成ツール
ブロック ファクトリは、Blockly ですでに使い慣れているコード生成システムを使用して動作します。各ブロックには、ブロック ファクトリによって生成された出力のタイプごとにブロックコード ジェネレータがあり、親ブロックは子ブロックのコードを正しい出力にアセンブルします。カスタム フィールドのサポートを追加するには、コード生成ツールのクラスごとにブロックコード ジェネレータ関数を追加する必要があります。
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})`;
};
ユーザーがブロック ファクトリ ツールボックスの [フィールド] カテゴリからドラッグしたアングル ブロックには、次の 2 つのフィールドがあります。
FIELDNAME
: ユーザーはカスタム ブロックにフィールドの名前を設定できます。ANGLE
: ユーザーはデフォルトの角度値を設定できます。
このブロックコード ジェネレータでは、デフォルトの角度値を取得し、それを唯一の引数として FieldAngle
コンストラクタに渡します。フィールド名は常に 2 番目の引数として 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 のインポートとスクリプトタグを切り替えられます。そのため、実際には 2 つの異なるジェネレータ インスタンス(ケースごとに 1 つずつ)があります。それぞれにブロックコードジェネレータを
追加する必要があります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 のフィールド レジストリにフィールドを登録する関数の呼び出しなどの作業が含まれます。
この 2 つのブロックコード ジェネレータでは、すべてのコードを addHeaderLine
の呼び出しによって追加する必要があります。この関数により、カスタム フィールド ブロックが 1 つのカスタム ブロックで複数回使用されている場合でも、各ヘッダー行が 1 回だけ表示されます。ブロックコード ジェネレータは空の文字列を返す必要があります。
Generator スタブ
最後は、フィールドの generator スタブを作成するジェネレータです。このブロックコード ジェネレータでは、コードを生成するコードを記述します。コード生成は、ユーザーによるコード生成を支援します。ご不明な点がある場合思ったより簡単です!
カスタム ブロックのジェネレータ スタブには、ブロックのすべてのフィールドを表す既製の変数が含まれています。次に、すべての変数をアセンブルして、カスタム ブロックが返す最終的なコード文字列にするために TODO
があります。つまり、通常、ブロックコード ジェネレータは、このカスタム変数を作成する行を返すだけで済みます。たとえば、キャンバスに太陽光を追加するカスタム ブロックを作成するとします。ブロックに angle フィールドを追加し、"SUN_DIRECTION"
という名前を付けます。このブロックのジェネレータ スタブには、const angle_sun_direction =
block.getFieldValue("SUN_DIRECTION");
という行が含まれます。angle フィールドのブロックコード ジェネレータは、次のコード行を返す必要があります。
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
を呼び出して、フィールドの型(angle
、number
など)とユーザーがフィールドに付けた名前を渡します。
テスト
これらをすべて記述したら、blockly-samples/examples/developer-tools
ディレクトリで npm start
を実行して、Block Factory を起動できるようになります。フィールド カテゴリからブロックをドラッグしてブロックの入力に追加し、出力の変化を確認できます。ブロックのプレビューが正しく表示されることと、各出力セクションのコードが正しいことを確認します。