Blockierungen definieren

Blockdefinitionen beschreiben, wie ein Block aussieht und sich verhält, einschließlich Text, Farbe, Form und mit welchen anderen Blöcken er verbunden werden kann.

JSON-Format und JavaScript API im Vergleich

Blockly bietet zwei Möglichkeiten zum Definieren von Blöcken: JSON-Objekte und JavaScript-Funktionen. Das JSON-Format vereinfacht den Lokalisierungsprozess bei der Entwicklung für Sprachen mit unterschiedlichen Wortreihenfolgen. Die bevorzugte Methode zum Definieren von Blöcken ist das JSON-Format.

Mit dem JSON-Format können jedoch erweiterte Funktionen wie Mutatoren oder Validatoren nicht direkt definiert werden. Diese müssen in JavaScript geschrieben sein, in der Regel als Erweiterungen.

Apps, die die ursprüngliche JavaScript-Implementierung von Blockly verwenden, können Blockdefinitionen auch direkt in die untergeordneten Blockly API-Funktionsaufrufe schreiben, wie in den verschiedenen JavaScript-Beispielen unten dargestellt.

JSON

Blockly.defineBlocksWithJsonArray([{
  "type": "string_length",
  "message0": 'length of %1',
  "args0": [
    {
      "type": "input_value",
      "name": "VALUE",
      "check": "String"
    }
  ],
  "output": "Number",
  "colour": 160,
  "tooltip": "Returns number of letters in the provided text.",
  "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
}]);

JavaScript

Blockly.Blocks['string_length'] = {
  init: function() {
    this.appendValueInput('VALUE')
        .setCheck('String')
        .appendField('length of');
    this.setOutput(true, 'Number');
    this.setColour(160);
    this.setTooltip('Returns number of letters in the provided text.');
    this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp');
  }
};

Mit der Funktion init wird die Form des Blocks erstellt. Im Kontext dieser Funktion ist das Schlüsselwort this der tatsächliche Block, der erstellt wird.

In beiden Beispielen wird derselbe „string_length“-Block geladen.

Im Web wird das JSON-Format mit der Funktion initJson geladen. Dies ermöglicht auch die Kombination der beiden Formate auf Blockly-Webseiten. Definieren Sie den Block nach Möglichkeit mit JSON und verwenden Sie JavaScript nur für Teile von Blockdefinitionen, die von JSON nicht unterstützt werden.

Im Folgenden finden Sie ein Beispiel für einen Block, der hauptsächlich mit JSON definiert ist, aber mit der JavaScript API um eine dynamische Kurzinfo erweitert wird.

JavaScript

var mathChangeJson = {
  "message0": "change %1 by %2",
  "args0": [
    {"type": "field_variable", "name": "VAR", "variable": "item", "variableTypes": [""]},
    {"type": "input_value", "name": "DELTA", "check": "Number"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 230
};

Blockly.Blocks['math_change'] = {
  init: function() {
    this.jsonInit(mathChangeJson);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "%1".'.replace('%1',
          thisBlock.getFieldValue('VAR'));
    });
  }
};

Blockfarbe

Die Primärfarbe eines Blocks wird durch das JSON-Attribut colour, die Funktion block.setColour(..) oder durch die Verwendung von Designs und das Definieren eines Blockstils definiert.

JSON

{
  // ...,
  "colour": 160,
}

JavaScript

init: function() {
  // ...
  this.setColour(160);
}

Weitere Informationen finden Sie in der Übersicht zu den Farben für Blöcke.

Verbindungen für Anweisungen

Nutzer können mit den Connectors nextStatement und previousStatement Sequenzen von Blöcken erstellen. Im Standardlayout von Blockly befinden sich diese Verbindungen oben und unten, die Blöcke sind vertikal gestapelt.

Ein Block mit einem früheren Connector kann keinen Ausgabe-Connector haben und umgekehrt. Der Begriff Anweisungsblock bezieht sich auf einen Block ohne Wertausgabe. Ein Anweisungsblock enthält normalerweise eine vorherige und eine nächste Verbindung.

nextStatement- und previousStatement-Verbindungen können typisiert werden, aber diese Funktion wird von Standardblöcken nicht verwendet.

Nächste Verbindung

Erstellt am unteren Rand des Blocks einen Punkt, sodass weitere Anweisungen darunter gestapelt werden können. Ein Block mit einer nächsten Verbindung, aber ohne vorherige Verbindung stellt normalerweise ein Ereignis dar und kann so konfiguriert werden, dass er mit einem Hut gerendert wird.

JSON

Ohne Eingabe:

{
  ...,
  "nextStatement": null,
}

Eingegeben (selten):

{
  "nextStatement": "Action",
  ...
}

JavaScript

Ohne Eingabe:

this.setNextStatement(true);  // false implies no next connector, the default

Eingegeben (selten):

this.setNextStatement(true, 'Action');

Vorherige Verbindung

Erstellt oben im Block eine Aussparung, sodass er als Stapel von Anweisungen verbunden werden kann.

Blöcke mit einer vorherigen Verbindung können keine Ausgabeverbindung haben.

JSON

Ohne Eingabe:

{
  ...,
  "previousStatement": null,
}

Eingegeben (selten):

{
  "previousStatement": "Action",
  ...
}

JavaScript

Ohne Eingabe:

this.setPreviousStatement(true);  // false implies no previous connector, the default

Eingegeben (selten):

this.setPreviousStatement(true, 'Action');

Blockausgabe

Ein Block kann einen einzelnen Ausgang haben, der als Stecker an der Vorderseite des Anschlusses dargestellt wird. Ausgaben sind mit Werteingaben verbunden. Blöcke mit einer Ausgabe werden in der Regel als Wertblöcke bezeichnet.

JSON

Ohne Eingabe:

{
  // ...,
  "output": null,
}

Eingegeben:

{
  // ...,
  "output": "Number",
}

JavaScript

Ohne Eingabe:

init: function() {
  // ...
  this.setOutput(true);
}

Eingegeben:

init: function() {
  // ...
  this.setOutput(true, 'Number');
}

Blöcke mit einem Ausgabeanschluss dürfen keine frühere Anweisungskerbe haben.

Eingänge blockieren

Ein Block hat eine oder mehrere Eingaben, wobei jede Eingabe eine Folge von Feldern hat und mit einer Verbindung enden kann. Es gibt mehrere Arten von integrierten Eingaben.

  • Werteingabe: Stellt eine Verbindung zu einer Ausgabeverbindung eines Werteblocks her. Ein math_arithmetic-Block (Addition, Subtraktion) ist ein Beispiel für einen Block mit zwei Werteingaben.
  • Anweisungseingabe: Stellt eine Verbindung zu einer vorherigen Verbindung eines Anweisungsblocks her. Der verschachtelte Abschnitt einer while-Schleife ist ein Beispiel für eine Anweisungseingabe.
  • Dummy-Eingabe: Hat keine Blockverbindung. Fungiert wie ein Zeilenumbruch, wenn der Block für die Verwendung externer Werteingaben konfiguriert ist.
  • Eingabe der letzten Zeile: Hat keine Blockverbindung und fungiert immer wie eine neue Zeile.

Sie können auch eine benutzerdefinierte Eingabe erstellen, um benutzerdefiniertes Rendering zu unterstützen.

Das JSON-Format und die JavaScript API verwenden etwas unterschiedliche Modelle zur Beschreibung ihrer Eingaben.

Eingaben und Felder in JSON

Definierte JSON-Blöcke sind als Folge interpolierter Nachrichtenstrings ( message0, message1, ...) strukturiert. Dabei ist jedes Interpolationstoken (%1, %2, ...) ein Feld oder ein Eingabeende (wobei der Eingabe-Connector innerhalb der Nachricht gerendert wird) im übereinstimmenden JSON-argsN-Array. Dieses Format soll die Internationalisierung vereinfachen.

JSON

{
  "message0": "set %1 to %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

Die Interpolationstokens müssen vollständig mit dem args0-Array übereinstimmen: keine Duplikate, keine Auslassungen. Tokens können in beliebiger Reihenfolge vorliegen, sodass verschiedene Sprachen das Layout des Blocks ändern können.

Der Text auf beiden Seiten eines Interpolationstokens ist durch Leerzeichen geschnitten. In Text mit dem Zeichen % (z.B. wenn es sich um einen Prozentsatz handelt) sollte %% verwendet werden, damit er nicht als Interpolationstoken interpretiert wird.

Die Reihenfolge der Argumente und der Argumenttypen definieren die Form des Blocks. Wenn Sie einen dieser Strings ändern, kann das Layout des Blocks komplett geändert werden. Dies ist insbesondere in Sprachen wichtig, die eine andere Wortreihenfolge als Englisch haben. Betrachten Sie eine hypothetische Sprache, bei der "set %1 to %2" (wie im obigen Beispiel verwendet) umgekehrt werden muss, um "put %2 in %1" zu sagen. Wenn Sie diesen einen String ändern und den Rest der JSON-Datei unverändert lassen, ergibt sich der folgende Block:

Blockly hat automatisch die Reihenfolge der Felder geändert, eine Dummy-Eingabe erstellt und von externen zu internen Eingaben gewechselt.

Blockly ersetzt außerdem automatisch jedes Zeilenumbruchzeichen (\n) im Nachrichtenstring durch eine Eingabe am Ende der Zeile.

JSON

{
  "message0": "set %1\nto %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

Args

Jeder Nachrichtenstring wird mit einem args-Array derselben Zahl gekoppelt. Beispiel: message0 gehört zu args0. Die Interpolationstokens (%1, %2, ...) beziehen sich auf die Elemente des args-Arrays. Jedes Objekt hat einen type-String. Die übrigen Parameter variieren je nach Typ:

Sie können auch eigene benutzerdefinierte Felder und benutzerdefinierte Eingaben definieren und als Argumente übergeben.

Jedes Objekt kann auch ein alt-Feld haben. Falls Blockly das type des Objekts nicht erkennt, wird stattdessen das alt-Objekt verwendet. Wenn beispielsweise ein neues Feld namens field_time zu Blockly hinzugefügt wird, können Blöcke, die dieses Feld verwenden, alt verwenden, um ein field_input-Fallback für ältere Versionen von Blockly zu definieren:

JSON

{
  "message0": "sound alarm at %1",
  "args0": [
    {
      "type": "field_time",
      "name": "TEMPO",
      "hour": 9,
      "minutes": 0,
      "alt":
        {
          "type": "field_input",
          "name": "TEMPOTEXT",
          "text": "9:00"
        }
    }
  ]
}

Ein alt-Objekt kann ein eigenes alt-Objekt haben, das eine Verkettung ermöglicht. Wenn Blockly kein Objekt im Array args0 erstellen kann (nach dem Versuch, alt-Objekte zu erstellen), wird dieses Objekt einfach übersprungen.

Eine Dummy-Eingabe wird automatisch am Ende des Blocks hinzugefügt, wenn der message-String mit Text oder Feldern endet, die nicht in einer Eingabe enthalten sind. Wenn also die letzte Eingabe in einem Block eine Dummy-Eingabe ist, kann sie im Array args weggelassen werden und erfordert keine Interpolation in message. Durch das automatische Hinzufügen einer Tailing-Dummy-Eingabe können Übersetzer message ändern, ohne den Rest des JSON-Codes ändern zu müssen. Sehen Sie sich das Beispiel für "set %1 to %2" (keine Testeingabe) und "put %2 in %1" (Dummy-Eingabe hinzugefügt) weiter oben auf dieser Seite an.

implicitAlign0

In seltenen Fällen muss die automatisch erstellte nachgestellte Dummy-Eingabe an "RIGHT" oder "CENTRE" ausgerichtet werden. Wenn nicht angegeben, ist der Standardwert "LEFT".

Im folgenden Beispiel ist message0 "send email to %1 subject %2 secure %3" und Blockly fügt automatisch eine Dummy-Eingabe für die dritte Zeile hinzu. Wenn Sie implicitAlign0 auf "RIGHT" festlegen, wird diese Zeile rechtsbündig ausgerichtet. Diese Ausrichtung gilt für alle Eingaben, die nicht explizit in der JSON-Blockdefinition definiert sind, einschließlich Eingaben für die Endzeile, die Zeilenumbrüche ('\n') in der Nachricht ersetzen. Außerdem gibt es das eingestellte Attribut lastDummyAlign0, das dasselbe Verhalten wie implicitAlign0 aufweist.

Beim Entwerfen von Blöcken für RTL (Arabisch und Hebräisch) werden links und rechts umgekehrt. Daher würde "RIGHT" Felder linksbündig ausrichten.

message1, args1, implicitAlign1

Einige Blöcke sind normalerweise in zwei oder mehr separate Teile unterteilt. Sehen Sie sich diesen Wiederholungsblock mit zwei Zeilen an:

Wenn dieser Block mit einer einzelnen Nachricht beschrieben wird, wäre das Attribut message0 "repeat %1 times %2 do %3". Dieser String ist für Übersetzer umständlich. Es lässt sich nur schwer erklären, was die Substitution %2 bedeutet. Die Dummy-Eingabe für %2 ist in einigen Sprachen eventuell gar nicht erwünscht. Und es können mehrere Blöcke vorhanden sein, in denen der Text der zweiten Zeile geteilt werden soll. Ein besserer Ansatz ist, wenn JSON mehr als eine Nachrichten- und Argument-Property verwendet:

JSON

{
  "type": "controls_repeat_ext",
  "message0": "repeat %1 times",
  "args0": [
    {"type": "input_value", "name": "TIMES", "check": "Number"}
  ],
  "message1": "do %1",
  "args1": [
    {"type": "input_statement", "name": "DO"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 120
}

Es kann eine beliebige Anzahl von message-, args- und implicitAlign-Attributen im JSON-Format definiert werden, beginnend mit 0, die schrittweise erhöht werden. Beachten Sie, dass die Block Factory Nachrichten nicht in mehrere Teile aufteilen kann. Manuell ist dies jedoch unkompliziert.

Eingaben und Felder in JavaScript

Die JavaScript API beinhaltet für jeden Eingabetyp eine append-Methode:

JavaScript

this.appendEndRowInput()
    .appendField('for each')
    .appendField('item')
    .appendField(new Blockly.FieldVariable());
this.appendValueInput('LIST')
    .setCheck('Array')
    .setAlign(Blockly.inputs.Align.RIGHT)
    .appendField('in list');
this.appendStatementInput('DO')
    .appendField('do');
this.appendDummyInput()
    .appendField('end');

Jede Anfügemethode kann einen Kennungsstring verwenden, der von Codegeneratoren verwendet wird. Dummy- und Endzeileneingaben müssen selten referenziert werden und die Kennzeichnung wird normalerweise nicht festgelegt.

Die JavaScript API enthält auch eine generische appendInput-Methode zum Anfügen benutzerdefinierter Eingaben. In diesem Fall sollte die ID direkt an den Konstruktor Ihrer benutzerdefinierten Eingabe übergeben werden.

JavaScript

this.appendInput(new MyCustomInput('INPUT_NAME'))
    .appendField('an example label')

Alle appendInput-Methoden (sowohl allgemeine als auch nicht allgemeine) geben das Eingabeobjekt zurück, sodass sie durch Methodenverkettung weiter konfiguriert werden können. Es gibt drei integrierte Methoden zum Konfigurieren von Eingaben.

setCheck

JavaScript

input.setCheck('Number');

Diese optionale Funktion wird zur Typprüfung verbundener Eingaben verwendet. Wenn das Argument null (Standardwert) angegeben ist, kann diese Eingabe mit einem beliebigen Block verbunden werden. Weitere Informationen finden Sie unter Typprüfungen.

setAlign

JavaScript

input.setAlign(Blockly.inputs.Align.RIGHT);

Diese optionale Funktion wird verwendet, um die Felder auszurichten (siehe unten). Es gibt drei selbstbeschreibende Werte, die als Argument an diese Funktion übergeben werden können: Blockly.inputs.Align.LEFT, Blockly.inputs.Align.RIGHT und Blockly.inputs.Align.CENTER.

Beim Entwerfen von Blöcken für RTL (Arabisch und Hebräisch) werden links und rechts umgekehrt. Daher würde Blockly.inputs.Align.RIGHT Felder linksbündig ausrichten.

appendField

Sobald eine Eingabe erstellt und mit appendInput an einen Block angehängt wurde, kann optional eine beliebige Anzahl von Feldern an die Eingabe angehängt werden. Diese Felder werden häufig als Labels verwendet, um zu beschreiben, wofür die einzelnen Eingaben gedacht sind.

JavaScript

input.appendField('hello');

Das einfachste Feldelement ist Text. Die Konvention von Blockly besteht darin, nur Kleinbuchstaben zu verwenden, mit Ausnahme von Eigennamen (z.B. Google, SQL).

Eine Eingabezeile kann eine beliebige Anzahl von Feldelementen enthalten. Mehrere appendField-Aufrufe können verkettet werden, um einer Eingabezeile effizient mehrere Felder hinzuzufügen.

JavaScript

input.appendField('hello')
     .appendField(new Blockly.FieldLabel('Neil', 'person'));

Der appendField('hello')-Aufruf ist eigentlich eine Verknüpfung zur Verwendung eines expliziten FieldLabel-Konstruktors: appendField(new Blockly.FieldLabel('hello')). Der Konstruktor sollte nur bei der Angabe eines Klassennamens verwendet werden, damit der Text mithilfe einer CSS-Regel formatiert werden kann.

Inline vs. extern

Blockeingaben können entweder als extern oder intern gerendert werden.

In der Blockdefinition kann ein optionaler boolescher Wert angegeben werden, der steuert, ob Eingaben inline erfolgen oder nicht. Bei false sind alle Werteingaben extern (z. B. der linke Block). Bei true erfolgen alle Werteingaben (z. B. der rechte Block oben).

JSON

{
  // ...,
  "inputsInline": true
}

JavaScript

init: function() {
  // ...
  this.setInputsInline(true);
}

Wenn nicht definiert, verwendet Blockly einige Heuristiken, um zu erraten, welcher Modus der beste ist. Wenn Blockly die richtige Wahl trifft, ist es vorzuziehen, dieses Feld undefiniert zu lassen, da Übersetzungen in verschiedene Sprachen automatisch unterschiedliche Modi haben können. Sehen Sie sich das JSON-Beispiel für "set %1 to %2" (externe Eingaben) und "put %2 in %1" (Inline-Eingaben) weiter oben auf dieser Seite an.

Verwenden Sie Inline-Eingaben, wenn ein Block wahrscheinlich kleine Eingaben wie Zahlen enthält. Der Nutzer kann diese Option über das Kontextmenü aktivieren oder deaktivieren, wenn die collapse-Konfiguration aktiviert ist (standardmäßig „true“, wenn die Toolbox Kategorien hat).

Felder

Felder definieren die meisten UI-Elemente innerhalb eines Blocks. Dazu gehören die Stringlabels, Bilder und Eingaben für Literaldaten wie Strings und Zahlen. Das einfachste Beispiel ist der math_number-Block. Hier wird field_input verwendet, damit der Nutzer eine Zahl eingeben kann.

Felder werden mithilfe von appendField an den Block angehängt.

Blockly bietet eine Reihe von integrierten Feldern, einschließlich Texteingaben, Farbauswahl und Bilder. Sie können auch eigene Felder erstellen.

→ Weitere Informationen zu integrierten Feldern.

→ Weitere Informationen zum Erstellen benutzerdefinierter Felder

Symbole

Symbole definieren UI-Elemente auf einem Block, die „Meta“-Informationen zum Block liefern.

Symbole werden mithilfe von addIcon an den Block angehängt.

Blockly bietet eine Reihe von integrierten Symbolen, darunter Kommentar- und Warnsymbole. Sie können auch eigene Symbole erstellen.

→ Weitere Informationen zum Erstellen benutzerdefinierter Symbole

Kurzinfos

Kurzinfos bieten sofortige Hilfe, wenn der Nutzer den Mauszeiger auf den Block bewegt. Wenn der Text lang ist, wird er automatisch umgebrochen.

JSON

{
  // ...,
  "tooltip": "Tooltip text."
}

JavaScript

init: function() {
  this.setTooltip("Tooltip text.");
}

In der JavaScript API können Kurzinfos auch als Funktion statt als statischer String definiert werden. Dies ermöglicht eine dynamische Hilfe. Unter math_arithmetic finden Sie ein Beispiel für eine Kurzinfo, die sich je nach ausgewählter Drop-down-Option ändert.

JavaScript

Blockly.Blocks['math_arithmetic'] = {
  init: function() {
    // ...

    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var mode = thisBlock.getFieldValue('OP');
      var TOOLTIPS = {
        'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
        'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
        'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
        'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
        'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
      };
      return TOOLTIPS[mode];
    });
  }
};

Mit der JavaScript API kann für Blöcke eine Funktion anstelle eines statischen Strings angegeben werden, der einen String für die Kurzinfo zurückgibt. Dies ermöglicht dynamische Kurzinfos. Ein Beispiel findest du unter math_arithmetic.

Anpassen

Sie können das Aussehen Ihrer Kurzinfos auch anpassen, indem Sie eine benutzerdefinierte Rendering-Funktion bereitstellen. Erstellen Sie eine Funktion, die zwei Parameter akzeptiert:

  • zuerst ein <div>-Element, in dem Sie den Inhalt rendern
  • zweitens das Element, über das der Mauszeiger bewegt wird und das die Kurzinfo für

Im Hauptteil der Funktion können Sie beliebigen Inhalt in das div-Element rendern. Um den Kurzinfo-String zu erhalten, der für den Block definiert ist, auf den das Mouseover bewegt wird, können Sie Blockly.Tooltip.getTooltipOfObject(element); aufrufen, wobei element der zweite Parameter oben ist.

Registrieren Sie abschließend diese Funktion, damit Blockly sie zur richtigen Zeit aufrufen kann:

Blockly.Tooltip.setCustomTooltip(yourFnHere);

Ein Beispiel finden Sie in der Demo für benutzerdefinierte Kurzinfos.

Hilfe-URL

Mit Blockierungen kann eine Hilfeseite verknüpft sein. Dies steht den Nutzern von Blockly for Web zur Verfügung, indem sie mit der rechten Maustaste auf den Block klicken und im Kontextmenü „Help“ (Hilfe) auswählen. Wenn dieser Wert null lautet, ist das Menü ausgegraut.

JSON

{
  // ...,
  "helpUrl": "https://en.wikipedia.org/wiki/For_loop"
}

JavaScript

init: function() {
  // ...
  this.setHelpUrl('https://en.wikipedia.org/wiki/For_loop');
}

Mithilfe der JavaScript API kann für Blöcke eine Funktion anstelle eines statischen Strings angegeben werden, der einen URL-String zurückgibt. Dies ermöglicht dynamische Hilfen.

Listener und Validatoren ändern

Blöcke können Änderungs-Listener-Funktionen enthalten, die bei jeder Änderung am Arbeitsbereich aufgerufen werden. Dies gilt auch für Änderungen, die nichts mit dem Block zu tun haben. Sie werden hauptsächlich verwendet, um den Warntext des Blocks oder ähnliche Nutzerbenachrichtigungen außerhalb des Arbeitsbereichs festzulegen.

Die Funktion wird durch Aufrufen von setOnChange mit einer Funktion hinzugefügt. Dies kann während der Initialisierung oder über eine JSON-Erweiterung erfolgen, wenn Sie sie auf allen Plattformen verwenden möchten.

JSON

{
  // ...,
  "extensions":["warning_on_change"],
}

Blockly.Extensions.register('warning_on_change', function() {
  // Example validation upon block change:
  this.setOnChange(function(changeEvent) {
    if (this.getInput('NUM').connection.targetBlock()) {
      this.setWarningText(null);
    } else {
      this.setWarningText('Must have an input block.');
    }
  });
});

JavaScript

Blockly.Blocks['block_type'] = {
  init: function() {
    // Example validation upon block change:
    this.setOnChange(function(changeEvent) {
      if (this.getInput('NUM').connection.targetBlock()) {
        this.setWarningText(null);
      } else {
        this.setWarningText('Must have an input block.');
      }
    });
  }
}

Das System ruft die Funktion auf und übergibt das Änderungsereignis. Innerhalb der Funktion bezieht sich this auf die Blockinstanz.

Da die Funktion bei jeder Änderung aufgerufen wird, sollten Entwickler darauf achten, dass der Listener schnell ausgeführt wird. Seien Sie auch bei Änderungen am Arbeitsbereich vorsichtig, die eine Kaskadierung oder Schleifenfunktion beim Listener zur Folge haben könnten.

Beispiele finden Sie in den Blöcken controls_flow_statements, logic_compare und procedures_ifreturn.

Beachten Sie, dass bearbeitbare Felder ihre eigenen Event-Listener für die Eingabevalidierung haben und Nebenwirkungen verursachen.

Mutator

Mit Mutators können erweiterte Blöcke ihre Form ändern, insbesondere wenn Nutzer ein Dialogfeld öffnen, um Komponenten hinzuzufügen, zu entfernen oder neu anzuordnen. Mutatoren können über JSON mit dem Schlüssel mutator hinzugefügt werden.

JSON

{
  // ...,
  "mutator":"if_else_mutator"
}

Konfiguration pro Block

Blockinstanzen haben eine Reihe von Eigenschaften, die das Verhalten der Nutzer gegenüber konfigurieren. Sie können verwendet werden, um den Arbeitsbereich einzuschränken, um bestimmte Attribute der Domain widerzuspiegeln (z.B. es gibt genau ein Startereignis) oder um den Fokus des Nutzers zu fokussieren (z.B. eine Anleitung).

Löschbarer Status

block.setDeletable(false);

Ist die Richtlinie auf „false“ gesetzt, kann der Nutzer die Blockierung nicht löschen. Blöcke können standardmäßig in einem bearbeitbaren Arbeitsbereich gelöscht werden.

Jeder Block (auch nicht löschbare) kann programmatisch gelöscht werden:

block.dispose();

Bearbeitbarer Status

block.setEditable(false);

Wenn dieser Wert auf „false“ gesetzt ist, kann der Nutzer die Felder des Blocks (z.B. Drop-down-Menüs und Texteingaben) nicht ändern. Blöcke sind standardmäßig in einem bearbeitbaren Arbeitsbereich bearbeitbar.

Beweglicher Zustand

block.setMovable(false);

Ist die Richtlinie auf „false“ gesetzt, kann der Nutzer den Block nicht direkt verschieben. Ein immobiler Block, der einem anderen Block untergeordnet ist, kann nicht von diesem Block getrennt werden. Wird der übergeordnete Block jedoch verschoben, wird er mit seinem übergeordneten Block verschoben. Blöcke sind standardmäßig in einem bearbeitbaren Arbeitsbereich verschiebbar.

Jeder Block (auch unbewegliche) kann programmatisch verschoben werden, sobald er sich in einem Arbeitsbereich befindet.

block.moveBy(dx, dy)

Die Startposition für einen Block in einem Arbeitsbereich ist standardmäßig (0, 0).

Daten blockieren

this.data = '16dcb3a4-bd39-11e4-8dfc-aa07a5b093db';

Daten sind eine optionale und beliebige Zeichenfolge, die an den Block angehängt wird. Bei der Serialisierung des Blocks wird der Datenstring damit serialisiert. Dies gilt auch für das Duplizieren oder Kopieren und Einfügen des Blocks.

Dies wird häufig verwendet, um einen Block einer externen Ressource zuzuordnen.

Bei der Serialisierung in JSON werden die Daten als übergeordnetes Attribut im Block gespeichert:

{
  "type": "my_block",
  "data": "16dcb3a4-bd39-11e4-8dfc-aa07a5b093db",
  // etc..
}

Bei der Serialisierung in XML (das alte Icebox-Serialisierungssystem) wird der Datenstring in einem <data></data>-Tag innerhalb des Blocks gespeichert:

<block type="my_block">
  <data>16dcb3a4-bd39-11e4-8dfc-aa07a5b093db</data>
  <!-- etc... -->
</block>

Zerstörung

Blöcke haben einen destroy-Hook, der beim Löschen aus dem Arbeitsbereich aufgerufen wird. Damit können alle unterstützenden Datenmodelle/externe Ressourcen, die mit dem Block verknüpft sind und nicht mehr benötigt werden, gelöscht werden.

JSON

{
  // ...,
  "extensions":["destroy"],
}

Blockly.Extensions.registerMixin('destroy', {
  destroy: function() {
    this.myResource.dispose();
  }
});

JavaScript

Blockly.Blocks['block_type'] = {
  destroy: function() {
    this.myResource.dispose();
  }
}

Die Methode destroy wird aufgerufen, nachdem das übergeordnete Element des Blocks, aber bevor seine untergeordneten Elemente oder Felder verworfen wurden, aufgerufen.

Kontextmenüs

Standardmäßig haben Blöcke ein Kontextmenü, über das Nutzer Kommentare hinzufügen oder Blöcke duplizieren können.

So deaktivieren Sie das Kontextmenü eines einzelnen Blocks:

block.contextMenu = false;

Sie können auch die Optionen anpassen, die im Menü angezeigt werden. Informationen zum Anpassen des Menüs für alle Blöcke finden Sie in der Dokumentation zu Kontextmenüs. Wenn Sie das Menü für einen einzelnen Block anpassen möchten, können Sie customContextMenu implementieren. Diese Funktion übernimmt ein Array von Menüoptionen und ändert es an Ort und Stelle, sodass Sie sowohl Elemente hinzufügen als auch entfernen können.

Jede Menüoption ist ein Objekt mit drei Eigenschaften:

  • text ist der Anzeigetext.
  • enabled ist ein boolescher Wert. Wenn diese Option deaktiviert ist, wird sie mit grauem Text angezeigt.
  • callback ist die Funktion, die beim Klicken auf die Option aufgerufen werden soll.