Erweiterungen und Mutators

Erweiterungen sind Funktionen, die in jedem Block eines bestimmten Typs ausgeführt werden, wenn der Block erstellt. Dadurch werden häufig benutzerdefinierte Konfigurationen oder Funktionsweisen zu einem Block hinzugefügt.

Ein Mutator ist eine spezielle Erweiterung, die eine benutzerdefinierte Serialisierung hinzufügt. bis hin zu einem Block.

Erweiterungen

Erweiterungen sind Funktionen, die in jedem Block eines bestimmten Typs ausgeführt werden, wenn der Block erstellt. Sie können eine benutzerdefinierte Konfiguration hinzufügen (z.B. durch Festlegen der Kurzinfo der Blockierung) oder benutzerdefiniertes Verhalten (z.B. Hinzufügen eines Event-Listeners zum Block).

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

Erweiterungen müssen „registriert“ sein damit sie mit einem String . Dann können Sie diesen Stringschlüssel dem Attribut extensions Ihres JSON des Blocktyps die Definition für die Erweiterung hinzu.

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

Sie können auch mehrere Erweiterungen gleichzeitig hinzufügen. Beachten Sie, dass die extensions Property muss ein Array sein, auch wenn Sie nur eine Erweiterung anwenden.

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

Mixins

Blockly bietet auch eine praktische Methode, wenn Sie einige Eigenschaften/Hilfsfunktionen zu einem Block hinzufügen, aber nicht sofort ausführen. Dieses ermöglicht die Registrierung eines Mixin -Objekt, das all Ihre zusätzlichen Eigenschaften/Methoden enthält. Das Mixin-Objekt wird dann in eine Funktion eingeschlossen, die das Mixin jedes Mal anwendet, wenn eine Instanz von der angegebene Blocktyp erstellt wird.

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

Auf Stringschlüssel, die mit Mixins verknüpft sind, kann in JSON genau wie auf jeden anderen String verwiesen werden .

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

Mutatoren

Ein Mutator ist eine spezielle Erweiterung, die eine zusätzliche Serialisierung (zusätzliche gespeichert und geladen) in einen Block. Zum Beispiel die integrierte Die Blöcke controls_if und list_create_with benötigen eine zusätzliche Serialisierung, damit wie viele Eingaben sie speichern können.

Wenn Sie die Form eines Blocks ändern, bedeutet das nicht unbedingt, dass zusätzliche Serialisierung. Beispielsweise ändert sich der math_number_property-Block und zwar mithilfe eines Dropdown-Felds, dessen Wert bereits serialisiert. Daher kann einfach ein Feld Validator und nicht brauchen einen Mutator.

Weitere Informationen finden Sie im Abschnitt zur Serialisierung für wann Sie einen Mutator benötigen und wann nicht.

Mutatoren bieten auch eine integrierte Benutzeroberfläche, über die Nutzende die Form von Blöcken ändern können, wenn stellen Sie einige optionale Methoden bereit.

Serialisierungs-Hooks

Mutatoren haben zwei Serialisierungs-Hook-Paare, mit denen sie arbeiten. Ein Paar Haken funktioniert mit dem neuen JSON-Serialisierungssystem, während das andere Paar mit dem ein altes XML-Serialisierungssystem. Sie müssen mindestens eines dieser Paare angeben.

„saveExtraState“ und „loadExtraState“

saveExtraState und loadExtraState sind Serialisierungs-Hooks, die mit dem ein neues JSON-Serialisierungssystem. saveExtraState gibt eine serialisierbare JSON-Datei zurück. Wert, der den zusätzlichen Status des Blocks darstellt, und loadExtraState akzeptiert denselben serialisierbaren JSON-Wert und wendet ihn auf den Block an.

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Die resultierende JSON-Datei sieht so aus:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
Kein Status

Befindet sich Ihr Block bei der Serialisierung im Standardstatus, Die Methode saveExtraState kann dazu null zurückgeben. Wenn Ihr Die Methode saveExtraState gibt null zurück. Dann wird kein extraState-Attribut hinzugefügt. das JSON-Format. Dadurch wird die Größe der gespeicherten Datei klein gehalten.

Vollständige Serialisierung und Sicherungsdaten

saveExtraState empfängt auch einen optionalen doFullSerialization-Parameter. Dieses wird von Blöcken verwendet, die auf einen Zustand verweisen, der von einem anderen Serializer (wie unterstützende Datenmodelle). Der Parameter signalisiert, Der referenzierte Zustand ist nicht verfügbar, wenn der Block deserialisiert wird, sodass der Block sollte alle Sicherungsstatus selbst serialisieren. Das ist zum Beispiel true, wenn ein einzelner Block serialisiert oder wenn ein Block kopiert und eingefügt wird.

Zwei häufige Anwendungsfälle hierfür sind:

  • Wenn ein einzelner Block in einen Arbeitsbereich geladen wird, in dem die unterstützenden Daten nicht vorhanden ist, verfügt es über genügend Informationen im eigenen Zustand, um um ein neues Datenmodell zu erstellen.
  • Beim Kopieren und Einfügen eines Blocks wird immer eine neue Sicherung erstellt. Datenmodell zu verwenden, anstatt auf ein vorhandenes Modell zu verweisen.

Einige Blöcke, die dies verwenden, sind @blockly/block-shareable-procedures-Blöcken. Normal Sie serialisieren einen Verweis auf ein unterstützendes Datenmodell, das ihren Status speichert. Ist der Parameter doFullSerialization jedoch "true", werden alle den jeweiligen Bundesstaat. Die teilbaren Prozedurblöcke nutzen dies, um sicherzustellen, erstellt ein neues Datenmodell, anstatt auf ein des vorhandenen Modells.

mutationToDom und domToMutation

mutationToDom und domToMutation sind Serialisierungs-Hooks, die mit dem ein altes XML-Serialisierungssystem. Verwenden Sie diese Aufhänger nur, wenn es unbedingt erforderlich ist (z.B. wenn Sie auf einer alten Codebasis arbeiten, die noch nicht migriert wurde). Andernfalls verwenden Sie saveExtraState und loadExtraState.

mutationToDom gibt einen XML-Knoten zurück, der den zusätzlichen Status des block, und domToMutation akzeptiert denselben XML-Knoten und wendet den Status auf des Blocks an.

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Die resultierende XML-Datei sieht so aus:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

Wenn die mutationToDom-Funktion null zurückgibt, wird kein zusätzliches Element hinzugefügt.

UI-Hooks

Wenn Sie als Teil Ihres Mutators bestimmte Funktionen bereitstellen, fügt Blockly ein Standard-„Mutator“ UI zu Ihrem Block.

Sie müssen diese UI nicht verwenden, wenn Sie eine zusätzliche Serialisierung hinzufügen möchten. Sie könnten eine benutzerdefinierte UI wie blocks-plus-minus Plug-in oder Sie könnten gar keine Benutzeroberfläche verwenden!

Zusammenfassen und zerlegen

Die Standard-UI stützt sich auf die Funktionen compose und decompose.

decompose „explodiert“ werden in kleinere Unterblöcke unterteilt, die Sie hinzugefügt und gelöscht haben. Diese Funktion sollte einen "oberen Block" zurückgeben Dieser lautet Hauptblock im Mutator-Arbeitsbereich, mit dem die Unterblöcke verbunden sind.

compose interpretiert dann die Konfiguration der Unterblöcke und verwendet sie, um Hauptblock ändern. Diese Funktion sollte den "oberen Block" akzeptieren. Das war werden von decompose als Parameter zurückgegeben.

Beachten Sie, dass diese Funktionen zu „mutierenden“ Block also this auf diesen Block verweisen.

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

Optional können Sie auch eine saveConnections-Funktion definieren, die mit die Standardbenutzeroberfläche. Diese Funktion gibt Ihnen die Möglichkeit, untergeordnete Elemente Ihres Hauptblock (im Hauptarbeitsbereich vorhanden) mit Unterblöcken, die in Ihrem Mutator-Arbeitsbereich. Anhand dieser Daten können Sie dann dafür sorgen, dass Ihr compose stellt die Verbindung der untergeordneten Elemente des Hauptblocks her, werden die Unterblöcke neu angeordnet.

saveConnections sollte den "oberen" Block akzeptieren von Ihrem Gerät (decompose) zurückgegeben als Parameter verwendet werden. Wenn die Funktion saveConnections definiert ist, vor compose aufgerufen wird.

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

Wird registriert

Mutatoren sind eine spezielle Erweiterung. Sie müssen also auch registriert, bevor Sie sie im JSON-Format Ihres Blocktyps verwenden können. Definition.

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name: Ein String, der mit dem Mutator verknüpft werden soll, damit Sie ihn in JSON verwenden können.
  • mixinObj: Ein Objekt, das die verschiedenen Mutationsmethoden enthält. Beispiel: saveExtraState und loadExtraState.
  • opt_helperFn: Eine optionale Hilfsfunktion, die nachdem das Mixin vermischt wurde.
  • opt_blockList: Ein optionales Array von Blocktypen (als Strings), die zum Flyout in der Standard-Mutator-Benutzeroberfläche hinzugefügt, wenn die UI-Methoden ebenfalls definiert.

Im Gegensatz zu Erweiterungen darf jeder Blocktyp nur einen Mutator haben.

{
  //...
  "mutator": "controls_if_mutator"
}

Hilfsfunktion

Zusammen mit dem Mixin kann ein Mutator eine Hilfsfunktion registrieren. Diese Funktion ist nach seiner Erstellung für jeden Block des angegebenen Typs ausgeführt. hinzugefügt. Damit können einer Mutation zusätzliche Trigger oder Effekte hinzugefügt werden.

Beispielsweise können Sie Ihrem listenähnlichen Block ein Hilfsprogramm hinzufügen, mit dem anfängliche Anzahl von Elementen:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}