Créer un champ personnalisé

Avant de créer un type de champ, déterminez si l'une des autres méthodes de personnalisation des champs répond à vos besoins. Si votre application doit stocker un nouveau type de valeur ou si vous souhaitez créer une interface utilisateur pour un type de valeur existant, vous devrez probablement créer un type de champ.

Pour créer un champ :

  1. Implémenter un constructeur
  2. Enregistrez une clé JSON et implémentez fromJson.
  3. Gérez l'initialisation de l'UI et des écouteurs d'événements sur le bloc.
  4. Gérez la suppression des écouteurs d'événements (la suppression de l'UI est gérée pour vous).
  5. Implémentez la gestion des valeurs.
  6. Ajoutez une représentation textuelle de la valeur de votre champ pour l'accessibilité.
  7. Ajoutez des fonctionnalités supplémentaires, telles que :
  8. Configurez d'autres aspects de votre champ, tels que :

Dans cette section, nous partons du principe que vous avez lu et que vous connaissez le contenu de la section Anatomie d'un champ.

Pour obtenir un exemple de champ personnalisé, consultez la démonstration des champs personnalisés.

Implémenter un constructeur

Le constructeur du champ est responsable de la configuration de la valeur initiale du champ et, éventuellement, de la configuration d'un validateur local. Le constructeur du champ personnalisé est appelé lors de l'initialisation du bloc source, que le bloc source soit défini en JSON ou en JavaScript. Le champ personnalisé n'a donc pas accès au bloc source lors de la construction.

L'exemple de code suivant crée un champ personnalisé nommé GenericField :

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

    this.SERIALIZABLE = true;
  }
}

Signature de la méthode

Les constructeurs de champs acceptent généralement une valeur et un validateur local. La valeur est facultative. Si vous n'en transmettez pas (ou si vous transmettez une valeur qui ne valide pas la classe), la valeur par défaut de la superclasse sera utilisée. Pour la classe Field par défaut, cette valeur est null. Si vous ne souhaitez pas utiliser cette valeur par défaut, veillez à transmettre une valeur appropriée. Le paramètre de validation n'est présent que pour les champs modifiables et est généralement marqué comme facultatif. Pour en savoir plus sur les validateurs, consultez la documentation sur les validateurs.

Structure

La logique à l'intérieur de votre constructeur doit suivre ce flux :

  1. Appelez le super constructeur hérité (tous les champs personnalisés doivent hériter de Blockly.Field ou de l'une de ses sous-classes) pour initialiser correctement la valeur et définir le validateur local pour votre champ.
  2. Si votre champ est sérialisable, définissez la propriété correspondante dans le constructeur. Les champs modifiables doivent être sérialisables. Les champs sont modifiables par défaut. Vous devez donc probablement définir cette propriété sur "true", sauf si vous savez qu'elle ne doit pas être sérialisable.
  3. Facultatif : Appliquez une personnalisation supplémentaire (par exemple, les champs de libellé permettent de transmettre une classe CSS, qui est ensuite appliquée au texte).

JSON et enregistrement

Dans les définitions de blocs JSON, les champs sont décrits par une chaîne (par exemple, field_number, field_textinput). Blockly conserve une carte de ces chaînes vers les objets de champ et appelle fromJson sur l'objet approprié lors de la construction.

Appelez Blockly.fieldRegistry.register pour ajouter votre type de champ à cette carte, en transmettant la classe de champ comme deuxième argument :

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

Vous devez également définir votre fonction fromJson. Votre implémentation doit d'abord déréférencer toutes les références aux jetons de localisation à l'aide de replaceMessageReferences, puis transmettre les valeurs au constructeur.

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

Initialisation…

Lorsque votre champ est construit, il ne contient qu'une valeur. L'initialisation est l'étape où le DOM est créé, le modèle est créé (si le champ possède un modèle) et les événements sont liés.

Affichage sur le bloc

Lors de l'initialisation, vous êtes responsable de la création de tout ce dont vous aurez besoin pour l'affichage sur bloc du champ.

Valeurs par défaut, arrière-plan et texte

La fonction initView par défaut crée un élément rect de couleur claire et un élément text. Si vous souhaitez que votre champ comporte ces deux éléments, ainsi que d'autres, appelez la fonction initView de la superclasse avant d'ajouter le reste de vos éléments DOM. Si vous souhaitez que votre champ comporte l'un de ces éléments, mais pas les deux, vous pouvez utiliser les fonctions createBorderRect_ ou createTextElement_.

Personnaliser la construction du DOM

Si votre champ est un champ de texte générique (par exemple, Text Input), la construction du DOM sera gérée pour vous. Sinon, vous devrez remplacer la fonction initView pour créer les éléments DOM dont vous aurez besoin lors du futur rendu de votre champ.

Par exemple, un champ de menu déroulant peut contenir à la fois des images et du texte. Dans initView, il crée un seul élément image et un seul élément de texte. Ensuite, pendant render_, il affiche l'élément actif et masque l'autre, en fonction du type d'option sélectionnée.

Vous pouvez créer des éléments DOM à l'aide de la méthode Blockly.utils.dom.createSvgElement ou des méthodes de création DOM traditionnelles.

Voici les exigences concernant l'affichage sur le bloc d'un champ :

  • Tous les éléments DOM doivent être des enfants de l'élément fieldGroup_ du champ. Le groupe de champs est créé automatiquement.
  • Tous les éléments DOM doivent rester dans les dimensions signalées du champ.

Pour en savoir plus sur la personnalisation et la mise à jour de l'affichage sur le bloc, consultez la section Rendu.

Ajouter des symboles de texte

Si vous souhaitez ajouter des symboles au texte d'un champ (comme le symbole de degré du champ Angle), vous pouvez ajouter l'élément de symbole (généralement contenu dans un <tspan>) directement au textElement_ du champ.

Événements de saisie

Par défaut, les champs enregistrent les événements d'info-bulle et les événements mousedown (à utiliser pour afficher les éditeurs). Si vous souhaitez écouter d'autres types d'événements (par exemple, si vous souhaitez gérer le déplacement d'un champ), vous devez remplacer la fonction bindEvents_ du champ.

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

Pour associer un événement, vous devez généralement utiliser la fonction Blockly.utils.browserEvents.conditionalBind. Cette méthode de liaison des événements filtre les contacts secondaires lors des déplacements. Si vous souhaitez que votre gestionnaire s'exécute même au milieu d'un déplacement en cours, vous pouvez utiliser la fonction Blockly.browserEvents.bind.

Élimination

Si vous avez enregistré des écouteurs d'événements personnalisés dans la fonction bindEvents_ du champ, vous devrez les désenregistrer dans la fonction dispose.

Si vous avez correctement initialisé la vue de votre champ (en ajoutant tous les éléments DOM à fieldGroup_), le DOM du champ sera supprimé automatiquement.

Gestion des valeurs

→ Pour en savoir plus sur la valeur d'un champ par rapport à son texte, consultez Anatomie d'un champ.

Ordre de validation

Organigramme décrivant l&#39;ordre d&#39;exécution des validateurs

Implémenter un validateur de classe

Les champs ne doivent accepter que certaines valeurs. Par exemple, les champs numériques ne doivent accepter que des nombres, les champs de couleur ne doivent accepter que des couleurs, etc. Cela est garanti par les validateurs de classe et locaux. Le validateur de classe suit les mêmes règles que les validateurs locaux, sauf qu'il est également exécuté dans le constructeur et, à ce titre, il ne doit pas faire référence au bloc source.

Pour implémenter le validateur de classe de votre champ, remplacez la fonction doClassValidation_.

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

Gérer les valeurs valides

Si la valeur transmise à un champ avec setValue est valide, vous recevrez un rappel doValueUpdate_. Par défaut, la fonction doValueUpdate_ :

  • La propriété value_ est définie sur newValue.
  • Définit la propriété isDirty_ sur true.

Si vous avez simplement besoin de stocker la valeur et que vous ne souhaitez pas effectuer de traitement personnalisé, vous n'avez pas besoin de remplacer doValueUpdate_.

Sinon, si vous souhaitez effectuer des actions telles que :

  • Espace de stockage personnalisé de newValue.
  • Modifiez d'autres propriétés en fonction de newValue.
  • Enregistrez si la valeur actuelle est valide ou non.

Vous devrez remplacer doValueUpdate_ :

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

Gérer les valeurs non valides

Si la valeur transmise au champ avec setValue n'est pas valide, vous recevrez un rappel doValueInvalid_. Par défaut, la fonction doValueInvalid_ ne fait rien. Cela signifie que les valeurs non valides ne s'affichent pas par défaut. Cela signifie également que le champ ne sera pas réaffiché, car la propriété isDirty_ ne sera pas définie.

Si vous souhaitez afficher des valeurs non valides, vous devez remplacer doValueInvalid_. Dans la plupart des cas, vous devez définir une propriété displayValue_ sur la valeur non valide, définir isDirty_ sur true et override render_ pour que l'affichage sur le bloc soit mis à jour en fonction de displayValue_ au lieu de value_.

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

Valeurs en plusieurs parties

Lorsque votre champ contient une valeur en plusieurs parties (par exemple, des listes, des vecteurs ou des objets), vous pouvez souhaiter que les parties soient traitées comme des valeurs individuelles.

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

Dans l'exemple ci-dessus, chaque propriété de newValue est validée individuellement. Ensuite, à la fin de la fonction doClassValidation_, si une propriété individuelle n'est pas valide, la valeur est mise en cache dans la propriété cacheValidatedValue_ avant de renvoyer null (non valide). La mise en cache de l'objet avec des propriétés validées individuellement permet à la fonction doValueInvalid_ de les gérer séparément, simplement en effectuant une vérification !this.cacheValidatedValue_.property, au lieu de revalider chaque propriété individuellement.

Ce modèle de validation des valeurs en plusieurs parties peut également être utilisé dans les validateurs locaux, mais il n'existe actuellement aucun moyen de l'appliquer.

isDirty_

isDirty_ est un indicateur utilisé dans la fonction setValue, ainsi que dans d'autres parties du champ, pour indiquer si le champ doit être rendu à nouveau. Si la valeur affichée du champ a changé, isDirty_ doit généralement être défini sur true.

Texte

→ Pour savoir où le texte d'un champ est utilisé et en quoi il diffère de la valeur du champ, consultez Anatomie d'un champ.

Si le texte de votre champ est différent de sa valeur, vous devez remplacer la fonction getText pour fournir le texte correct.

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

Créer un éditeur

Si vous définissez la fonction showEditor_, Blockly écoutera automatiquement les clics et appellera showEditor_ au moment opportun. Vous pouvez afficher n'importe quel code HTML dans votre éditeur en l'encapsulant dans l'une des deux divs spéciales, appelées DropDownDiv et WidgetDiv, qui flottent au-dessus du reste de l'UI de Blockly.

DropDownDiv est utilisé pour fournir des éditeurs qui se trouvent dans une boîte connectée à un champ. Il se positionne automatiquement à proximité du champ tout en restant dans les limites visibles. Le sélecteur d'angle et le sélecteur de couleur sont de bons exemples de DropDownDiv.

Image du sélecteur d&#39;angle

WidgetDiv est utilisé pour fournir des éditeurs qui ne se trouvent pas dans une boîte. Les champs numériques utilisent WidgetDiv pour couvrir le champ avec une zone de saisie de texte HTML. Bien que DropDownDiv gère le positionnement pour vous, WidgetDiv ne le fait pas. Les éléments devront être positionnés manuellement. Le système de coordonnées est exprimé en coordonnées de pixels par rapport au coin supérieur gauche de la fenêtre. L'éditeur de saisie de texte est un bon exemple de WidgetDiv.

Image de l&#39;éditeur de saisie de texte

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

Exemple de code WidgetDiv

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

Nettoyer

Les éléments DropDownDiv et WidgetDiv gèrent la destruction des éléments HTML du widget, mais vous devez supprimer manuellement tous les écouteurs d'événements que vous avez appliqués à ces éléments.

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

La fonction dispose est appelée dans un contexte null sur DropDownDiv. Sur WidgetDiv, il est appelé dans le contexte de WidgetDiv. Dans les deux cas, il est préférable d'utiliser la fonction bind lorsque vous transmettez une fonction de suppression, comme illustré dans les exemples DropDownDiv et WidgetDiv ci-dessus.

→ Pour en savoir plus sur la suppression d'éléments qui ne sont pas spécifiques à la suppression d'éditeurs, consultez Suppression.

Mettre à jour l'affichage sur le bloc

La fonction render_ est utilisée pour mettre à jour l'affichage sur le bloc du champ afin qu'il corresponde à sa valeur interne.

Voici quelques exemples courants :

  • Modifier le texte (menu déroulant)
  • Modifier la couleur (color)

Valeurs par défaut

La fonction render_ par défaut définit le texte à afficher sur le résultat de la fonction getDisplayText_. La fonction getDisplayText_ renvoie la propriété value_ du champ convertie en chaîne, après avoir été tronquée pour respecter la longueur maximale du texte.

Si vous utilisez l'affichage par défaut sur le bloc et que le comportement de texte par défaut fonctionne pour votre champ, vous n'avez pas besoin de remplacer render_.

Si le comportement de texte par défaut fonctionne pour votre champ, mais que l'affichage sur bloc de votre champ comporte des éléments statiques supplémentaires, vous pouvez appeler la fonction render_ par défaut, mais vous devrez toujours la remplacer pour mettre à jour la taille du champ.

Si le comportement de texte par défaut ne fonctionne pas pour votre champ ou si l'affichage sur le bloc de votre champ comporte des éléments dynamiques supplémentaires, vous devrez personnaliser la fonction render_.

Organigramme décrivant comment décider de remplacer ou non render_

Personnaliser l'affichage

Si le comportement de rendu par défaut ne fonctionne pas pour votre champ, vous devrez définir un comportement de rendu personnalisé. Cela peut impliquer de définir un texte à afficher personnalisé, de modifier des éléments d'image ou de mettre à jour les couleurs d'arrière-plan.

Toutes les modifications apportées aux attributs DOM sont légales. Les deux seules choses à retenir sont les suivantes :

  1. La création du DOM doit être gérée lors de l'initialisation, car c'est plus efficace.
  2. Vous devez toujours mettre à jour la propriété size_ pour qu'elle corresponde à la taille de l'annonce display sur bloc.
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_();
}

Mise à jour de la taille

Il est très important de mettre à jour la propriété size_ d'un champ, car elle indique au code de rendu du bloc comment positionner le champ. La meilleure façon de déterminer exactement ce que doit être size_ est d'expérimenter.

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

Assortir les couleurs des blocs

Si vous souhaitez que les éléments de votre champ correspondent aux couleurs du bloc auquel ils sont associés, vous devez remplacer la méthode applyColour. Vous devrez accéder à la couleur via la propriété de style du bloc.

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

Mettre à jour la possibilité de modification

La fonction updateEditable peut être utilisée pour modifier l'apparence de votre champ selon qu'il est modifiable ou non. La fonction par défaut permet au fond d'avoir ou non une réponse au survol (bordure) s'il est modifiable ou non. La taille de l'affichage dans le bloc ne doit pas changer en fonction de sa capacité de modification, mais toutes les autres modifications sont autorisées.

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

Sérialisation

La sérialisation consiste à enregistrer l'état de votre champ afin qu'il puisse être rechargé ultérieurement dans l'espace de travail.

L'état de votre espace de travail inclut toujours la valeur du champ, mais il peut également inclure d'autres états, tels que l'état de l'UI de votre champ. Par exemple, si votre champ était une carte zoomable permettant à l'utilisateur de sélectionner des pays, vous pourriez également sérialiser le niveau de zoom.

Si votre champ est sérialisable, vous devez définir la propriété SERIALIZABLE sur true.

Blockly fournit deux ensembles de hooks de sérialisation pour les champs. Une paire de hooks fonctionne avec le nouveau système de sérialisation JSON, et l'autre paire fonctionne avec l'ancien système de sérialisation XML.

saveState et loadState

saveState et loadState sont des hooks de sérialisation qui fonctionnent avec le nouveau système de sérialisation JSON.

Dans certains cas, vous n'avez pas besoin de les fournir, car les implémentations par défaut fonctionneront. Si (1) votre champ est une sous-classe directe de la classe de base Blockly.Field, (2) votre valeur est un type sérialisable JSON et (3) vous n'avez besoin que de sérialiser la valeur, l'implémentation par défaut fonctionnera parfaitement.

Sinon, votre fonction saveState doit renvoyer un objet/une valeur sérialisable JSON qui représente l'état du champ. Votre fonction loadState doit accepter le même objet/valeur sérialisable JSON et l'appliquer au champ.

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

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

Sérialisation complète et données de sauvegarde

saveState reçoit également un paramètre facultatif doFullSerialization. Cette option est utilisée par les champs qui font normalement référence à un état sérialisé par un sérialiseur différent (comme les modèles de données de sauvegarde). Le paramètre indique que l'état référencé ne sera pas disponible lorsque le bloc sera désérialisé. Le champ doit donc effectuer lui-même toute la sérialisation. Par exemple, cela est vrai lorsqu'un bloc individuel est sérialisé ou lorsqu'un bloc est copié et collé.

Voici deux cas d'utilisation courants :

  • Lorsqu'un bloc individuel est chargé dans un espace de travail où le modèle de données sous-jacent n'existe pas, le champ dispose de suffisamment d'informations dans son propre état pour créer un modèle de données.
  • Lorsqu'un bloc est copié et collé, le champ crée toujours un nouveau modèle de données sous-jacent au lieu de faire référence à un modèle existant.

Le champ de variable intégré en est un exemple. Normalement, il sérialise l'ID de la variable à laquelle il fait référence, mais si doFullSerialization est défini sur "true", il sérialise tout son état.

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());
}

Le champ de variable permet de s'assurer que, s'il est chargé dans un espace de travail où sa variable n'existe pas, il peut créer une nouvelle variable à référencer.

toXml et fromXml

toXml et fromXml sont des hooks de sérialisation qui fonctionnent avec l'ancien système de sérialisation XML. N'utilisez ces hooks que si vous y êtes obligé (par exemple, si vous travaillez sur un ancien codebase qui n'a pas encore été migré). Sinon, utilisez saveState et loadState.

Votre fonction toXml doit renvoyer un nœud XML qui représente l'état du champ. Votre fonction fromXml doit accepter le même nœud XML et l'appliquer au champ.

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

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

Propriétés modifiables et sérialisables

La propriété EDITABLE détermine si le champ doit disposer d'une interface utilisateur pour indiquer qu'il peut être utilisé. Sa valeur par défaut est true.

La propriété SERIALIZABLE détermine si le champ doit être sérialisé. La valeur par défaut est false. Si cette propriété est true, vous devrez peut-être fournir des fonctions de sérialisation et de désérialisation (voir Sérialisation).

Personnaliser avec CSS

Vous pouvez personnaliser votre champ avec CSS. Dans la méthode initView, ajoutez une classe personnalisée au fieldGroup_ de votre champ, puis référencez cette classe dans votre CSS.

Par exemple, pour utiliser un autre curseur :

initView() {
  ...

  // Add a custom CSS class.
  if (this.fieldGroup_) {
    Blockly.utils.dom.addClass(this.fieldGroup_, 'myCustomField');
  }
}
.myCustomField {
  cursor: cell;
}

Personnaliser le curseur

Par défaut, les classes qui étendent FieldInput utilisent un curseur text lorsqu'un utilisateur pointe sur le champ, les champs en cours de déplacement utilisent un curseur grabbing et tous les autres champs utilisent un curseur default. Si vous souhaitez utiliser un autre curseur, définissez-le à l'aide du CSS.