Neuen Feldtyp erstellen

Bevor Sie einen neuen Feldtyp erstellen, sollten Sie überlegen, ob eine der anderen Methoden zum Anpassen von Feldern Ihren Anforderungen entspricht. Wenn Ihre Anwendung einen neuen Werttyp speichern muss oder Sie eine neue UI für einen vorhandenen Werttyp erstellen möchten, müssen Sie wahrscheinlich einen neuen Feldtyp erstellen.

So erstellen Sie ein neues Feld:

  1. Implementieren Sie einen Konstruktor.
  2. Registrieren Sie einen JSON-Schlüssel und implementieren Sie fromJson.
  3. Initialisiert die On-Block-UI und die Event-Listener.
  4. Handhabung der Entsorgung von Event-Listenern (die Entsorgung über die UI wird für Sie übernommen).
  5. Wertverarbeitung implementieren
  6. Fügen Sie aus Gründen der Barrierefreiheit eine Textdarstellung des Feldwerts hinzu.
  7. Zusätzliche Funktionen hinzufügen, z. B.:
  8. Konfigurieren Sie zusätzliche Aspekte des Felds, z. B.:

In diesem Abschnitt wird davon ausgegangen, dass Sie die Inhalte unter Aufbau eines Felds gelesen haben und mit diesen vertraut sind.

Ein Beispiel für ein benutzerdefiniertes Feld finden Sie in der Demo für benutzerdefinierte Felder.

Einen Konstruktor implementieren

Der Konstruktor des Felds ist für die Einrichtung des Anfangswerts des Felds und optional für die Einrichtung eines lokalen Validators verantwortlich. Der Konstruktor des benutzerdefinierten Felds wird während der Initialisierung des Quellblocks aufgerufen, unabhängig davon, ob der Quellblock in JSON oder JavaScript definiert ist. Das benutzerdefinierte Feld hat daher während der Erstellung keinen Zugriff auf den Quellblock.

Im folgenden Codebeispiel wird ein benutzerdefiniertes Feld mit dem Namen GenericField erstellt:

class GenericField extends Blockly.Field {
  constructor(value, validator) {
    super(value, validator);

    this.SERIALIZABLE = true;
  }
}

Methodensignatur

Feldkonstruktoren nehmen normalerweise einen Wert und eine lokale Validierung an. Der Wert ist optional. Wenn Sie einen Wert nicht oder einen Wert übergeben, der die Klassenvalidierung nicht besteht, wird der Standardwert der übergeordneten Klasse verwendet. Für die Standardklasse Field ist dieser Wert null. Wenn Sie diesen Standardwert nicht verwenden möchten, müssen Sie einen geeigneten Wert übergeben. Der Validator-Parameter ist nur für bearbeitbare Felder vorhanden und in der Regel als optional gekennzeichnet. Weitere Informationen zu Validatoren finden Sie in der Dokumentation zu Validatoren.

Struktur

Die Logik in Ihrem Konstruktor sollte diesem Ablauf folgen:

  1. Rufen Sie den übernommenen Super-Konstruktor auf, um den Wert ordnungsgemäß zu initialisieren und die lokale Validierung für Ihr Feld festzulegen. Alle benutzerdefinierten Felder sollten von Blockly.Field oder einer seiner Unterklassen übernommen werden.
  2. Wenn das Feld serialisierbar ist, legen Sie die entsprechende Property im Konstruktor fest. Bearbeitbare Felder müssen serialisierbar sein und Felder müssen standardmäßig bearbeitet werden können. Daher sollten Sie diese Property auf „true“ setzen, sofern Sie nicht wissen, dass sie nicht serialisierbar sein soll.
  3. Optional: Nehmen Sie zusätzliche Anpassungen vor. Mit Labelfeldern können Sie beispielsweise eine CSS-Klasse übergeben, die dann auf den Text angewendet wird.

JSON und Registrierung

In JSON-Blockdefinitionen werden Felder durch einen String beschrieben (z.B. field_number, field_textinput). Blockly verwaltet eine Zuordnung dieser Strings zu Feldobjekten und ruft bei der Konstruktion fromJson für das entsprechende Objekt auf.

Rufen Sie Blockly.fieldRegistry.register auf, um der Zuordnung Ihren Feldtyp hinzuzufügen. Dabei wird die Feldklasse als zweites Argument übergeben:

Blockly.fieldRegistry.register('field_generic', GenericField);

Außerdem müssen Sie die Funktion fromJson definieren. In der Implementierung sollte zuerst mit replaceMessageReferences auf alle Stringtabellen-Verweise dereferenziert und die Werte dann an den Konstruktor übergeben werden.

GenericField.fromJson = function(options) {
  const value = Blockly.utils.parsing.replaceMessageReferences(
      options['value']);
  return new CustomFields.GenericField(value);
};

Wird initialisiert

Wenn Ihr Feld erstellt wird, enthält es im Grunde nur einen Wert. Bei der Initialisierung wird das DOM und das Modell erstellt (sofern das Feld ein Modell enthält) und Ereignisse gebunden.

On-Block-Display

Während der Initialisierung sind Sie dafür verantwortlich, alles zu erstellen, was Sie für die Blockanzeige des Felds benötigen.

Standardeinstellungen, Hintergrund und Text

Die Standardfunktion initView erstellt ein helles rect-Element und ein text-Element. Wenn Ihr Feld beide sowie einige zusätzliche Extras enthalten soll, rufen Sie die Funktion initView der Basisklasse auf, bevor Sie die restlichen DOM-Elemente hinzufügen. Wenn das Feld nur ein Element, aber nicht beide Elemente enthalten soll, können Sie die Funktionen createBorderRect_ oder createTextElement_ verwenden.

DOM-Konstruktion anpassen

Wenn das Feld ein generisches Textfeld ist (z.B. Texteingabe), wird die DOM-Erstellung für Sie übernommen. Andernfalls müssen Sie die initView-Funktion überschreiben, um die DOM-Elemente zu erstellen, die Sie für das zukünftige Rendern des Felds benötigen.

Ein Drop-down-Feld kann beispielsweise sowohl Bilder als auch Text enthalten. In initView werden ein einzelnes Bildelement und ein einzelnes Textelement erstellt. Während render_ wird dann je nach Typ der ausgewählten Option das aktive Element angezeigt und das andere ausgeblendet.

DOM-Elemente können entweder mit der Methode Blockly.utils.dom.createSvgElement oder mit herkömmlichen Methoden zur DOM-Erstellung erstellt werden.

Für die Blockanzeige eines Felds gelten folgende Anforderungen:

  • Alle DOM-Elemente müssen dem fieldGroup_ des Felds untergeordnet sein. Die Feldgruppe wird automatisch erstellt.
  • Alle DOM-Elemente müssen innerhalb der gemeldeten Dimensionen des Felds bleiben.

Weitere Informationen zum Anpassen und Aktualisieren der Blockanzeige finden Sie im Abschnitt Rendering.

Textsymbole hinzufügen

Wenn Sie dem Text eines Felds Symbole hinzufügen möchten, z. B. das Gradsymbol des Felds Winkel, können Sie das Symbolelement (normalerweise in einem <tspan> enthalten) direkt an die textElement_ des Felds anhängen.

Eingabe-Ereignisse

Standardmäßig werden in den Feldern Kurzinfo- und Mousedown-Ereignisse registriert, die zum Einblenden von Bearbeitern verwendet werden können. Wenn Sie auf andere Arten von Ereignissen warten möchten (z.B. das Ziehen eines Feldes), sollten Sie die bindEvents_-Funktion des Felds überschreiben.

bindEvents_() {
  // Call the superclass function to preserve the default behavior as well.
  super.bindEvents_();

  // Then register your own additional event listeners.
  this.mouseDownWrapper_ =
  Blockly.browserEvents.conditionalBind(this.getClickTarget_(), 'mousedown', this,
      function(event) {
        this.originalMouseX_ = event.clientX;
        this.isMouseDown_ = true;
        this.originalValue_ = this.getValue();
        event.stopPropagation();
      }
  );
  this.mouseMoveWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mousemove', this,
      function(event) {
        if (!this.isMouseDown_) {
          return;
        }
        var delta = event.clientX - this.originalMouseX_;
        this.setValue(this.originalValue_ + delta);
      }
  );
  this.mouseUpWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mouseup', this,
      function(_event) {
        this.isMouseDown_ = false;
      }
  );
}

Für eine Bindung an ein Ereignis sollten Sie im Allgemeinen die Funktion Blockly.utils.browserEvents.conditionalBind verwenden. Mit dieser Methode zum Binden von Ereignissen werden sekundäre Berührungen während des Drag-Vorgangs herausgefiltert. Wenn der Handler auch während eines laufenden Drag noch ausgeführt werden soll, können Sie die Funktion Blockly.browserEvents.bind verwenden.

Entsorgung

Wenn Sie benutzerdefinierte Ereignis-Listener in der Funktion bindEvents_ des Felds registriert haben, müssen diese innerhalb der Funktion dispose abgemeldet werden.

Wenn Sie die Ansicht Ihres Felds richtig initialisiert haben, indem Sie alle DOM-Elemente an das fieldGroup_ angehängt haben, wird das DOM des Felds automatisch gelöscht.

Umgang mit Werten

→ Weitere Informationen zum Wert eines Felds im Vergleich zu seinem Text finden Sie unter Aufbau eines Felds.

Validierungsreihenfolge

Flussdiagramm mit Beschreibung der Reihenfolge, in der Validatoren ausgeführt werden

Klassenvalidierung implementieren

Felder dürfen nur bestimmte Werte annehmen. In Zahlenfeldern sollten beispielsweise nur Zahlen, in Farbfeldern nur Farben usw. akzeptiert werden. Dies wird durch Klassen- und lokale Validatoren sichergestellt. Die Klassenvalidierung folgt denselben Regeln wie lokale Validierungen, mit der Ausnahme, dass sie auch im Konstruktor ausgeführt wird und daher nicht auf den Quellblock verweisen sollte.

Wenn Sie den Klassenvalidator Ihres Felds implementieren möchten, überschreiben Sie die Funktion doClassValidation_.

doClassValidation_(newValue) {
  if (typeof newValue != 'string') {
    return null;
  }
  return newValue;
};

Umgang mit gültigen Werten

Wenn der an ein Feld mit setValue übergebene Wert gültig ist, erhalten Sie einen doValueUpdate_-Callback. Standardmäßig verwendet die Funktion doValueUpdate_:

  • Legt die Eigenschaft value_ auf newValue fest.
  • Legt die Property isDirty_ auf true fest.

Wenn Sie nur den Wert speichern müssen und keine benutzerdefinierte Verarbeitung vornehmen möchten, müssen Sie doValueUpdate_ nicht überschreiben.

Gehen Sie andernfalls so vor:

  • Benutzerdefinierter Speicher von newValue.
  • Andere Eigenschaften basierend auf newValue ändern.
  • Speichert, ob der aktuelle Wert gültig ist oder nicht.

Sie müssen doValueUpdate_ überschreiben:

doValueUpdate_(newValue) {
  super.doValueUpdate_(newValue);
  this.displayValue_ = newValue;
  this.isValueValid_ = true;
}

Umgang mit ungültigen Werten

Wenn der an das Feld mit setValue übergebene Wert ungültig ist, erhalten Sie einen doValueInvalid_-Callback. Standardmäßig führt die Funktion doValueInvalid_ nichts aus. Das bedeutet, dass standardmäßig keine ungültigen Werte angezeigt werden. Außerdem bedeutet dies, dass das Feld nicht neu gerendert wird, da das Attribut isDirty_ nicht festgelegt wird.

Wenn Sie ungültige Werte anzeigen möchten, müssen Sie doValueInvalid_ überschreiben. In den meisten Fällen sollten Sie ein displayValue_-Attribut auf den ungültigen Wert setzen, isDirty_ auf true setzen und render_überschreiben, damit die Anzeige im Block basierend auf displayValue_ und nicht anhand von value_ aktualisiert wird.

doValueInvalid_(newValue) {
  this.displayValue_ = newValue;
  this.isDirty_ = true;
  this.isValueValid_ = false;
}

Mehrteilige Werte

Wenn das Feld einen mehrteiligen Wert enthält (z.B. Listen, Vektoren, Objekte), möchten Sie die Teile möglicherweise wie einzelne Werte behandeln.

doClassValidation_(newValue) {
  if (FieldTurtle.PATTERNS.indexOf(newValue.pattern) == -1) {
    newValue.pattern = null;
  }

  if (FieldTurtle.HATS.indexOf(newValue.hat) == -1) {
    newValue.hat = null;
  }

  if (FieldTurtle.NAMES.indexOf(newValue.turtleName) == -1) {
    newValue.turtleName = null;
  }

  if (!newValue.pattern || !newValue.hat || !newValue.turtleName) {
    this.cachedValidatedValue_ = newValue;
    return null;
  }
  return newValue;
}

Im obigen Beispiel wird jedes Attribut von newValue einzeln validiert. Wenn am Ende der doClassValidation_-Funktion ein einzelnes Attribut ungültig ist, wird der Wert im Cache des Attributs cacheValidatedValue_ im Cache gespeichert, bevor null (ungültig) zurückgegeben wird. Wenn Sie das Objekt mit einzeln validierten Attributen im Cache speichern, kann die Funktion doValueInvalid_ diese getrennt durch eine !this.cacheValidatedValue_.property-Prüfung verarbeiten, anstatt jedes Attribut einzeln neu zu validieren.

Dieses Muster zur Validierung mehrteiliger Werte kann auch in lokalen Validatoren verwendet werden. Derzeit gibt es jedoch keine Möglichkeit, dieses Muster zu erzwingen.

isDirty_

isDirty_ ist ein Flag, das in der setValue-Funktion und in anderen Teilen des Felds verwendet wird, um zu ermitteln, ob das Feld neu gerendert werden muss. Wenn sich der Anzeigewert des Felds geändert hat, sollte isDirty_ normalerweise auf true festgelegt werden.

Text

→ Informationen dazu, wo der Text eines Felds verwendet wird und wie er sich vom Feldwert unterscheidet, finden Sie unter Aufbau eines Felds.

Wenn sich der Text des Felds vom Wert des Felds unterscheidet, müssen Sie die Funktion getText überschreiben, um den richtigen Text bereitzustellen.

getText() {
  let text = this.value_.turtleName + ' wearing a ' + this.value_.hat;
  if (this.value_.hat == 'Stovepipe' || this.value_.hat == 'Propeller') {
    text += ' hat';
  }
  return text;
}

Editor erstellen

Wenn Sie die Funktion showEditor_ definieren, wartet Blockly automatisch auf Klicks und ruft showEditor_ zum entsprechenden Zeitpunkt auf. Sie können beliebigen HTML-Code in Ihrem Editor anzeigen lassen, indem Sie ihn in zwei spezielle div-Elemente einfügen: DropDownDiv und WidgetDiv. Diese schweben über dem Rest der Blockly-Benutzeroberfläche.

Mit DropDownDiv werden Editoren bereitgestellt, die sich in einem mit einem Feld verbundenen Feld befinden. Es positioniert sich automatisch so, dass es in der Nähe des Feldes ist, aber innerhalb der sichtbaren Grenzen bleibt. Die Winkel- und Farbauswahl sind gute Beispiele für DropDownDiv.

Bild der Winkelauswahl

Mit WidgetDiv werden Editoren bereitgestellt, die sich nicht in einem Feld befinden. Zahlenfelder verwenden WidgetDiv, um das Feld mit einem HTML-Texteingabefeld abzudecken. DropDownDiv übernimmt die Positionierung für Sie, WidgetDiv hingegen nicht. Elemente müssen manuell positioniert werden. Das Koordinatensystem wird in Pixelkoordinaten relativ zur oberen linken Ecke des Fensters angegeben. Der Texteingabeeditor ist ein gutes Beispiel für WidgetDiv.

Bild des Texteditors für die Texteingabe

showEditor_() {
  // Create the widget HTML
  this.editor_ = this.dropdownCreate_();
  Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);

  // Set the dropdown's background colour.
  // This can be used to make it match the colour of the field.
  Blockly.DropDownDiv.setColour('white', 'silver');

  // Show it next to the field. Always pass a dispose function.
  Blockly.DropDownDiv.showPositionedByField(
      this, this.disposeWidget_.bind(this));
}

WidgetDiv-Beispielcode

showEditor_() {
  // Show the div. This automatically closes the dropdown if it is open.
  // Always pass a dispose function.
  Blockly.WidgetDiv.show(
    this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));

  // Create the widget HTML.
  var widget = this.createWidget_();
  Blockly.WidgetDiv.getDiv().appendChild(widget);
}

Bereinigen

Sowohl DropDownDiv als auch WidgetDiv sorgen dafür, dass die Widget-HTML-Elemente gelöscht werden. Sie müssen jedoch alle Ereignis-Listener, die Sie auf diese Elemente angewendet haben, manuell entsorgen.

widgetDispose_() {
  for (let i = this.editorListeners_.length, listener;
      listener = this.editorListeners_[i]; i--) {
    Blockly.browserEvents.unbind(listener);
    this.editorListeners_.pop();
  }
}

Die Funktion dispose wird in einem null-Kontext der DropDownDiv aufgerufen. Auf der WidgetDiv wird sie im Kontext von WidgetDiv aufgerufen. In beiden Fällen empfiehlt es sich, beim Übergeben einer Löschfunktion die Funktion bind zu verwenden, wie in den obigen Beispielen für DropDownDiv und WidgetDiv gezeigt.

→ Informationen zur Entsorgung, die nicht für das Löschen von Bearbeitern vorgesehen ist, finden Sie unter Entsorgen.

Bildschirmanzeige aktualisieren

Mit der Funktion render_ wird die Blockanzeige des Felds aktualisiert, damit sie mit dem internen Wert übereinstimmt.

Beispiele:

  • Text ändern (Drop-down-Menü)
  • Farbe (Farbe) ändern

Standardeinstellungen

Mit der Standardfunktion render_ wird als Anzeigetext das Ergebnis der Funktion getDisplayText_ festgelegt. Die Funktion getDisplayText_ gibt das Attribut value_ des Felds zurück, das in einen String umgewandelt wird, nachdem er unter Berücksichtigung der maximalen Textlänge abgeschnitten wurde.

Wenn Sie die standardmäßige On-Block-Anzeige verwenden und das Standardtextverhalten für Ihr Feld funktioniert, müssen Sie render_ nicht überschreiben.

Wenn das Standardtextverhalten für Ihr Feld funktioniert, die Blockanzeige des Felds aber zusätzliche statische Elemente enthält, können Sie die Standardfunktion render_ aufrufen. Sie müssen sie aber trotzdem überschreiben, um die Größe des Felds zu aktualisieren.

Wenn das Standardtextverhalten für das Feld nicht funktioniert oder die Blockanzeige des Felds zusätzliche dynamische Elemente enthält, müssen Sie die Funktion render_ anpassen.

Flussdiagramm, in dem beschrieben wird, wie entschieden wird, ob das Rendering überschrieben werden soll_

Rendering anpassen

Wenn das Standardverhalten für das Feld nicht funktioniert, müssen Sie ein benutzerdefiniertes Renderingverhalten definieren. Das kann alles Mögliche beinhalten, von der Festlegung von benutzerdefiniertem Anzeigetext über das Ändern von Bildelementen bis hin zum Aktualisieren von Hintergrundfarben.

Alle Änderungen an DOM-Attributen sind zulässig. Es müssen nur zwei Dinge beachtet werden:

  1. Die DOM-Erstellung sollte während der Initialisierung durchgeführt werden, da sie effizienter ist.
  2. Du solltest die Property size_ immer so aktualisieren, dass sie der Größe der Anzeige im Block entspricht.
render_() {
  switch(this.value_.hat) {
    case 'Stovepipe':
      this.stovepipe_.style.display = '';
      break;
    case 'Crown':
      this.crown_.style.display = '';
      break;
    case 'Mask':
      this.mask_.style.display = '';
      break;
    case 'Propeller':
      this.propeller_.style.display = '';
      break;
    case 'Fedora':
      this.fedora_.style.display = '';
      break;
  }

  switch(this.value_.pattern) {
    case 'Dots':
      this.shellPattern_.setAttribute('fill', 'url(#polkadots)');
      break;
    case 'Stripes':
      this.shellPattern_.setAttribute('fill', 'url(#stripes)');
      break;
    case 'Hexagons':
      this.shellPattern_.setAttribute('fill', 'url(#hexagons)');
      break;
  }

  this.textContent_.nodeValue = this.value_.turtleName;

  this.updateSize_();
}

Größe wird aktualisiert

Es ist sehr wichtig, das Attribut size_ eines Felds zu aktualisieren, da es dem Block-Renderingcode mitteilt, wie das Feld positioniert werden soll. Am besten experimentieren Sie, um herauszufinden, wie size_ genau aussehen sollte.

updateSize_() {
  const bbox = this.movableGroup_.getBBox();
  let width = bbox.width;
  let height = bbox.height;
  if (this.borderRect_) {
    width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    this.borderRect_.setAttribute('width', width);
    this.borderRect_.setAttribute('height', height);
  }
  // Note how both the width and the height can be dynamic.
  this.size_.width = width;
  this.size_.height = height;
}

Übereinstimmende Blockfarben

Wenn Sie möchten, dass die Elemente Ihres Felds mit den Farben des Blocks übereinstimmen, an den sie angehängt sind, müssen Sie die Methode applyColour überschreiben. Der Zugriff auf die Farbe erfolgt über die Stileigenschaft des Blocks.

applyColour() {
  const sourceBlock = this.sourceBlock_;
  if (sourceBlock.isShadow()) {
    this.arrow_.style.fill = sourceBlock.style.colourSecondary;
  } else {
    this.arrow_.style.fill = sourceBlock.style.colourPrimary;
  }
}

Bearbeitbarkeit wird aktualisiert

Mit der Funktion updateEditable können Sie die Darstellung des Felds ändern, je nachdem, ob es bearbeitbar ist oder nicht. Die Standardfunktion sorgt dafür, dass der Hintergrund eine Hover-Antwort (Rahmen) hat bzw. nicht hat, wenn er bearbeitbar ist bzw. nicht bearbeitet werden kann. Die Größe der Anzeige im Block sollte sich nicht je nach Bearbeitbarkeit ändern, alle anderen Änderungen sind jedoch zulässig.

updateEditable() {
  if (!this.fieldGroup_) {
    // Not initialized yet.
    return;
  }
  super.updateEditable();

  const group = this.getClickTarget_();
  if (!this.isCurrentlyEditable()) {
    group.style.cursor = 'not-allowed';
  } else {
    group.style.cursor = this.CURSOR;
  }
}

Serialisierung

Bei der Serialisierung geht es darum, den Status Ihres Felds zu speichern, damit es später in den Arbeitsbereich neu geladen werden kann.

Der Status des Arbeitsbereichs enthält immer den Feldwert, kann aber auch einen anderen Status enthalten, z. B. den Status der Feld-UI. Wenn Ihr Feld beispielsweise eine zoombare Karte war, auf der Nutzer Länder auswählen konnten, könnten Sie auch die Zoomstufe serialisieren.

Wenn das Feld serialisierbar ist, müssen Sie das Attribut SERIALIZABLE auf true festlegen.

Blockly stellt zwei Gruppen von Serialisierungs-Hooks für Felder bereit. Ein Hook-Paar funktioniert mit dem neuen JSON-Serialisierungssystem und das andere mit dem alten XML-Serialisierungssystem.

saveState und loadState

saveState und loadState sind Serialisierungs-Hooks, die mit dem neuen JSON-Serialisierungssystem funktionieren.

In einigen Fällen müssen Sie diese nicht angeben, da die Standardimplementierungen funktionieren. Wenn (1) das Feld eine direkte Unterklasse der Basisklasse Blockly.Field ist, (2) Ihr Wert ein serialisierbarer JSON-Typ ist und (3) Sie nur den Wert serialisieren müssen, funktioniert die Standardimplementierung problemlos.

Andernfalls sollte die Funktion saveState ein JSON-serialisierbares Objekt oder einen Wert zurückgeben, der den Status des Felds darstellt. Die Funktion loadState sollte dasselbe JSON-serialisierbare Objekt bzw. denselben Wert akzeptieren und auf das Feld anwenden.

saveState() {
  return {
    'country': this.getValue(),  // Value state
    'zoom': this.getZoomLevel(), // UI state
  };
}

loadState(state) {
  this.setValue(state['country']);
  this.setZoomLevel(state['zoom']);
}

Vollständige Serialisierung und Sicherung von Daten

saveState empfängt außerdem den optionalen Parameter doFullSerialization. Dies wird von Feldern verwendet, die normalerweise auf Status verweisen, die von einem anderen Serializer serialisiert wurden (wie Sicherungsdatenmodelle). Der Parameter signalisiert, dass der referenzierte Zustand nicht verfügbar ist, wenn der Block deserialisiert wird. Daher sollte das Feld die gesamte Serialisierung selbst übernehmen. Dies gilt beispielsweise, wenn ein einzelner Block serialisiert oder ein Block kopiert und eingefügt wird.

Zwei häufige Anwendungsfälle sind:

  • Wenn ein einzelner Block in einen Arbeitsbereich geladen wird, in dem das unterstützende Datenmodell nicht vorhanden ist, verfügt das Feld über genügend Informationen in seinem eigenen Zustand, um ein neues Datenmodell zu erstellen.
  • Wenn ein Block kopiert und eingefügt wird, wird mit dem Feld immer ein neues unterstützendes Datenmodell erstellt, anstatt auf ein vorhandenes Modell zu verweisen.

Ein Feld, das dieses Feld verwendet, ist das Feld der integrierten Variablen. Normalerweise wird die ID der Variablen, auf die sie verweist, serialisiert. Wenn doFullSerialization jedoch auf „true“ gesetzt ist, wird der gesamte Status serialisiert.

saveState(doFullSerialization) {
  const state = {'id': this.variable_.getId()};
  if (doFullSerialization) {
    state['name'] = this.variable_.name;
    state['type'] = this.variable_.type;
  }
  return state;
}

loadState(state) {
  const variable = Blockly.Variables.getOrCreateVariablePackage(
      this.getSourceBlock().workspace,
      state['id'],
      state['name'],   // May not exist.
      state['type']);  // May not exist.
  this.setValue(variable.getId());
}

Das sorgt dafür, dass beim Laden in einen Arbeitsbereich, in dem keine Variable vorhanden ist, eine neue Variable erstellt werden kann, auf die verwiesen werden kann.

toXml und fromXml

toXml und fromXml sind Serialisierungs-Hooks, die mit dem alten XML-Serialisierungssystem funktionieren. Verwenden Sie diese Hooks nur bei Bedarf (z. B. wenn Sie mit einer alten Codebasis arbeiten, die noch nicht migriert wurde). Andernfalls verwenden Sie saveState und loadState.

Die Funktion toXml sollte einen XML-Knoten zurückgeben, der den Status des Felds darstellt. Die Funktion fromXml sollte denselben XML-Knoten akzeptieren und auf das Feld anwenden.

toXml(fieldElement) {
  fieldElement.textContent = this.getValue();
  fieldElement.setAttribute('zoom', this.getZoomLevel());
  return fieldElement;
}

fromXml(fieldElement) {
  this.setValue(fieldElement.textContent);
  this.setZoomLevel(fieldElement.getAttribute('zoom'));
}

Bearbeitbare und serialisierbare Eigenschaften

Mit dem Attribut EDITABLE wird festgelegt, ob das Feld eine UI haben soll, die angibt, dass mit ihm interagiert werden kann. Der Standardwert ist true.

Das Attribut SERIALIZABLE bestimmt, ob das Feld serialisiert werden soll. Der Standardwert ist false. Wenn dieses Attribut true ist, müssen Sie möglicherweise Serialisierungs- und Deserialisierungsfunktionen bereitstellen (siehe Serialisierung).

Cursor anpassen

Das Attribut CURSOR bestimmt den Cursor, den Nutzer sehen, wenn sie den Mauszeiger auf das Feld bewegen. Es sollte sich um einen gültigen CSS-Cursorstring handeln. Die Standardeinstellung ist der Cursor, der durch .blocklyDraggable definiert ist. Das ist der Grab-Cursor.