Plug-in-Feld zu Block Factory hinzufügen

Mit den Blockly Developer Tools können Sie benutzerdefinierte Blöcke mithilfe von Blöcken erstellen. Zusätzlich zu den in Blockly enthaltenen Feldern werden Felder unterstützt, die als Plug-ins veröffentlicht werden. Wenn Sie ein benutzerdefiniertes Feld erstellt haben, können Sie der Block Factory Unterstützung dafür hinzufügen. Folgen Sie dazu dieser Anleitung. Das benutzerdefinierte Feld muss auf npm veröffentlicht werden, bevor es unterstützt werden kann. Sie müssen sich außerdem verpflichten, Ihr Feld zu aktualisieren, um mit den Änderungen in Blockly Schritt zu halten. Andernfalls müssen wir es möglicherweise in Zukunft aus Block Factory entfernen.

Entwicklung in der Block Factory

Der Quellcode für die Block Factory befindet sich im Repository „Blockly-Samples“ im Verzeichnis examples/developer-tools.

Um eine Änderung an den Entwicklertools in Blockly-Beispielen einzureichen, folgen Sie den typischen Schritten für die Entwicklung in Blockly-Beispielen. Anders als bei Plug-ins müssen Sie npm install jedoch direkt über das Verzeichnis examples/developer-tools und nicht auf der Stammebene der Blockly-Samples ausführen.

Plug-in installieren

Damit die Block Factory Ihr benutzerdefiniertes Feld in der Vorschau anzeigen kann, muss das benutzerdefinierte Feld installiert werden. Füge das Feld als npm-Abhängigkeit von „developer-tools“ hinzu. Registrieren Sie es dann oder führen Sie andere erforderliche Schritte zur Einrichtung in developer-tools/src/blocks/index.ts aus.

Block für das Feld erstellen

Da die Block Factory Blöcke zum Erstellen benutzerdefinierter Blöcke verwendet, benötigen Sie einen Block, der Ihr benutzerdefiniertes Feld darstellt.

Blockdefinition erstellen

Sie müssen den Block für Ihr Feld entwerfen. Wenn Sie Meta abrufen möchten, können Sie ihn sogar mit Block Factory entwerfen. Der Block sollte es dem Nutzer ermöglichen, die für Ihr Feld erforderliche Einrichtung zu konfigurieren, z. B. Standardwerte und einen Namen. Fügen Sie diese Blockdefinition zu developer-tools/src/blocks/fields.ts hinzu und importieren Sie sie in developer-tools/src/blocks/index.ts.

Block zu Toolbox hinzufügen

Als Nächstes müssen Sie diesen Block der Toolbox-Definition hinzufügen, um ihn für Nutzer zugänglich zu machen. Die Toolbox-Definition befindet sich unter developer-tools/src/toolbox.ts. Der Block sollte der Kategorie „Felder“ hinzugefügt werden.

Code-Generatoren

Die Block Factory funktioniert mit dem Code-Generator-System, mit dem Sie bereits von Blockly vertraut sind. Jeder Block verfügt über einen Blockcode-Generator für jeden Ausgabetyp, der von der Block Factory generiert wird. Die übergeordneten Blöcke stellen den Code für die untergeordneten Blöcke in der richtigen Ausgabe zusammen. Damit ein benutzerdefiniertes Feld unterstützt wird, müssen Sie für jede der Codegenerator-Klassen Blockcode-Generatorfunktionen hinzufügen.

Erstellen Sie eine Datei für den Feldblock im Verzeichnis output-generators/fields. Sie fügen dieser Datei die Blockcode-Generatoren für jeden der folgenden Generatoren hinzu. Importieren Sie diese Datei in die Datei blocks/index.ts, damit die Blockcode-Generatorfunktionen in die Anwendung geladen werden.

JavaScript-Definition

Mit javascriptDefinitionGenerator wird der Code erstellt, der in die JavaScript-Definition für einen Block eingefügt wird, der Ihr benutzerdefiniertes Feld enthält. Normalerweise bedeutet das, dass der Blockcode-Generator eine Codezeile in folgendem Format zurückgeben sollte: .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName'). Diese Codezeile enthält kein Semikolon, da eine Eingabe mit mehreren Feldern mehrere verkettete Aufrufe von appendField enthält. Die Argumente im Konstruktor werden aus den Werten abgerufen, die der Nutzer für den Feldblock festgelegt hat. Hier ein Beispiel dieses Blockcode-Generators für 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})`;
};

Der Winkelblock, den der Nutzer aus der Kategorie "Fields" der Block Factory-Toolbox gezogen hat, enthält zwei Felder:

  • FIELDNAME: Der Nutzer kann den Namen des Felds für seinen benutzerdefinierten Block festlegen
  • ANGLE: Der Nutzer kann den Standardwinkelwert festlegen

In diesem Blockcode-Generator rufen wir den Standardwinkelwert ab und übergeben ihn als einziges Argument an den Konstruktor FieldAngle. Der Feldname wird immer als zweites Argument an appendField übergeben.

JSON-Definition

jsonDefinitionGenerator ist ähnlich, aber damit wird der Teil der JSON-Blockdefinition ausgegeben, der Ihrem Feld entspricht. In der Regel ist dieser Code ein JSON-Objekt, das Folgendes enthält:

  • type: entspricht dem Namen des Felds in der Blockly-Feldregistrierung
  • name: Der Nutzer kann den Namen des Felds für seinen benutzerdefinierten Block festlegen
  • Alle anderen benutzerdefinierten Attribute, die für die JSON-Initialisierungsmethode Ihres Felds erforderlich sind.

Hier noch einmal ein Beispiel aus 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);
};

Code-Header

Der Code-Header-Generator erstellt die Code-Header-Ausgabe, die in der Block-Factory angezeigt werden. Diese Ausgabe kann zwischen esmodule-Importen und Script-Tags umgeschaltet werden, je nachdem, wie der Nutzer den Code laden möchte. Es gibt also zwei verschiedene Generatorinstanzen: eine für jeden Fall. Sie müssen für jede einen Blockcode-Generator hinzufügen. Hier ein Beispiel für 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 '';
};

Diese Generatoren haben eine Methode namens addHeaderLine, mit der Sie eine Codezeile angeben können, die aufgerufen werden sollte, bevor das Feld im Code verwendet wird. Dazu gehören häufig das Importieren des Felds oder das Laden über ein Skript-Tag und möglicherweise das Aufrufen einer Funktion, die das Feld bei der Feld-Registry von Blockly registriert.

Für diese beiden Blockcode-Generatoren sollte der gesamte Code über Aufrufe von addHeaderLine hinzugefügt werden. Diese Funktion sorgt dafür, dass jede Headerzeile nur einmal angezeigt wird, auch wenn der Block mit benutzerdefinierten Feldern mehrmals in einem benutzerdefinierten Block verwendet wird. Der Blockcode-Generator sollte den leeren String zurückgeben.

Generator-Stub

Schließlich haben wir noch den Generator, der den Generator-Stub für das Feld erstellt. In diesem Blockcode-Generator schreiben Sie Code, der Code generiert, der dem Nutzer hilft, Code zu schreiben, der den Code generiert. Unklar? Es ist einfacher, als es klingt!

Der Generator-Stub für einen benutzerdefinierten Block enthält eine vordefinierte Variable, die jedes Feld im Block darstellt. Dann gibt es einen TODO, den der Nutzer beenden muss, um alle diese Variablen zu dem endgültigen Codestring zusammenzufassen, den der benutzerdefinierte Block zurückgibt. Ihr Blockcode-Generator muss also normalerweise nur die Zeile zurückgeben, in der diese benutzerdefinierte Variable erstellt wird. Angenommen, Nutzende erstellen einen benutzerdefinierten Block, der Sonnenstrahlen auf ihrem Canvas hinzufügt. Sie fügen dem Block ein Winkelfeld mit dem Namen "SUN_DIRECTION" hinzu. Der Generator-Stub für diesen Block würde die Zeile const angle_sun_direction = block.getFieldValue("SUN_DIRECTION"); enthalten. Das ist die Codezeile, die unser Blockcode-Generator für das Winkelfeld zurückgeben muss:

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

Um einen standardisierten Namen für die Variable zu erhalten, können Sie generator.createVariableName aufrufen und den Feldtyp (z. B. angle, number usw.) zusammen mit dem Namen des Nutzers für das Feld übergeben.

Testen

Nachdem Sie alle diese Teile geschrieben haben, sollten Sie die Block-Factory starten können. Führen Sie dazu npm start im Verzeichnis blockly-samples/examples/developer-tools aus. Sie sollten Ihren Block aus der Feldkategorie ziehen, ihn einer Eingabe in einem Block hinzufügen und beobachten können, wie sich die Ausgabe ändert. Prüfen Sie, ob die Vorschau des Blocks korrekt aussieht und ob der Code für jeden der Ausgabeabschnitte korrekt ist.