Création d'un type de champ

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 autre type de champ.

Pour créer un champ, procédez comme suit:

  1. Implémenter un constructeur
  2. Enregistrez une clé JSON et implémentez fromJson.
  3. Gérer l'initialisation de l'interface utilisateur sur le bloc et des écouteurs d'événements.
  4. Gérer la suppression des écouteurs d'événements (la suppression de l'UI est gérée automatiquement)
  5. Implémenter la gestion de la valeur
  6. Ajoutez une représentation textuelle de la valeur de votre champ, pour l'accessibilité.
  7. Ajoutez des fonctionnalités supplémentaires, par exemple :
  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 l'article Anatomie d'un champ.

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

Implémenter un constructeur

Le constructeur du champ est chargé de configurer la valeur initiale du champ et éventuellement de configurer un programme de validation local. Le constructeur du champ personnalisé est appelé lors de l'initialisation du bloc source, que celui-ci soit défini au format JSON ou JavaScript. Ainsi, le champ personnalisé n'a pas accès au bloc source pendant 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 utilisent généralement une valeur et un validateur local. Cette valeur est facultative. Si vous ne transmettez pas de valeur (ou si vous transmettez une valeur qui échoue à la validation de la classe), la valeur par défaut de la super-classe est utilisée. Pour la classe Field par défaut, cette valeur est null. Si vous ne voulez pas utiliser cette valeur par défaut, veillez à transmettre une valeur appropriée. Le paramètre de validation n'est disponible 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.

Structurer

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

  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 de 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, et les champs sont modifiables par défaut. Vous devez donc probablement définir cette propriété sur "true", sauf si vous savez qu'il ne doit pas être sérialisable.
  3. Facultatif: appliquez des personnalisations supplémentaires (par exemple, l'option Champs de libellé permet 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 un mappage entre ces chaînes et des objets de champ, et appelle fromJson sur l'objet approprié lors de la construction.

Appelez Blockly.fieldRegistry.register pour ajouter votre type de champ à ce mappage, 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 de table de chaînes à 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 essentiellement qu'une valeur. L'initialisation désigne l'endroit où le DOM est compilé, le modèle (si le champ en possède un) et les événements sont liés.

Écran On Block

Lors de l'initialisation, vous devez créer tout ce dont vous avez besoin pour l'affichage dans le 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 contienne ces deux éléments, ainsi que d'autres avantages, appelez la fonction de super-classe initView avant d'ajouter les autres éléments DOM. Si vous souhaitez que votre champ comporte un seul de ces éléments, mais pas les deux, vous pouvez utiliser les fonctions createBorderRect_ ou createTextElement_.

Personnaliser la construction DOM

Si votre champ est un champ de texte générique (par exemple, Entrée de texte), la construction DOM est assurée automatiquement. Sinon, vous devrez remplacer la fonction initView afin de créer les éléments DOM dont vous aurez besoin lors du rendu ultérieur de votre champ.

Par exemple, un champ 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 de l'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 traditionnelles de création DOM.

Voici les conditions requises pour l'affichage sur le bloc d'un champ:

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

Consultez la section Rendu pour découvrir comment personnaliser et mettre à jour l'affichage dans le bloc.

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 de défilement du curseur (à 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 sur 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 créer une liaison avec un événement, vous devez généralement utiliser la fonction Blockly.utils.browserEvents.conditionalBind. Cette méthode d'association des événements filtre les gestes 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.

Mise au rebut

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 est supprimé automatiquement.

Gestion de la valeur

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

Ordre de validation

Organigramme décrivant l&#39;ordre d&#39;exécution des programmes de validation

Implémenter un validateur de classe

Les champs ne doivent accepter que certaines valeurs. Par exemple, les champs numériques ne doivent accepter que les chiffres, les champs de couleur ne doivent accepter que les couleurs, etc. Ce processus est garanti par des programmes de validation 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, par conséquent, il ne doit pas référencer le 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_:

  • Définit la propriété value_ sur newValue.
  • Il définit la propriété isDirty_ sur true.

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

Sinon, si vous souhaitez effectuer les opérations suivantes:

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

Vous devez remplacer doValueUpdate_:

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

Traiter les valeurs non valides

Si la valeur transmise dans le champ avec setValue n'est pas valide, vous recevrez un rappel doValueInvalid_. Par défaut, la fonction doValueInvalid_ n'a aucun effet. Cela signifie que, par défaut, les valeurs non valides ne sont pas affichées. Cela signifie également que le champ ne sera pas à nouveau affiché, car la propriété isDirty_ n'est 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 remplacer render_ pour que l'affichage sur le bloc se mette à 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, des objets), vous pouvez souhaiter que ces 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 programmes de validation 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 déterminer si le champ doit être à nouveau affiché. Si la valeur d'affichage 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 la section 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 écoute automatiquement les clics et appelle showEditor_ au moment approprié. Vous pouvez afficher n'importe quel code HTML dans votre éditeur en l'encapsulant dans l'un des deux div spéciaux, appelés DropDownDiv et WidgetDiv, qui flottent au-dessus du reste de l'interface utilisateur de Blockly.

DropDownDiv permet de fournir des éditeurs qui résident dans une zone connectée à un champ. Il se positionne automatiquement pour être à proximité du champ tout en respectant 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 permet de fournir des éditeurs qui ne se trouvent pas à l'intérieur d'une zone. Les champs numériques utilisent la classe WidgetDiv pour couvrir le champ avec une zone de saisie de texte HTML. Contrairement à DropDownDiv, qui 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 en pixels par rapport à l'angle 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

DropDownDiv et WidgetDiv gèrent tous deux 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, elle est appelée dans le contexte de WidgetDiv. Dans les deux cas, il est préférable d'utiliser la fonction bind lors de la transmission d'une fonction de suppression, comme indiqué dans les exemples DropDownDiv et WidgetDiv ci-dessus.

→ Pour en savoir plus sur la suppression des éditeurs, consultez la section Suppression.

Mettre à jour l'écran de blocage

La fonction render_ permet de mettre à jour l'affichage du champ dans le bloc pour qu'il corresponde à sa valeur interne.

Voici quelques exemples courants :

  • Modifier le texte (liste déroulante)
  • Modifier la couleur

Valeurs par défaut

La fonction render_ par défaut définit le texte d'affichage sur le résultat de la fonction getDisplayText_. La fonction getDisplayText_ renvoie la propriété value_ du champ convertie en chaîne, une fois que celle-ci a été tronquée afin de 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 le bloc de votre champ contient 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 s&#39;il faut remplacer l&#39;affichage

Personnaliser le rendu

Si le comportement de rendu par défaut ne fonctionne pas pour votre champ, vous devez définir un comportement d'affichage personnalisé. Il peut s'agir de définir un texte d'affichage personnalisé, de modifier des éléments d'image ou encore de modifier les couleurs d'arrière-plan.

Toutes les modifications d'attributs DOM sont légales. Les deux seuls points à retenir sont les suivants:

  1. La création DOM doit être gérée lors de l'initialisation, car elle est plus efficace.
  2. Vous devez toujours mettre à jour la propriété size_ pour qu'elle corresponde à la taille de l'écran dans le 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. Le meilleur moyen de déterminer exactement quel devrait être size_ est d'effectuer des tests.

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

Couleurs de bloc correspondantes

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

Mise à jour de la possibilité de modification...

La fonction updateEditable permet de modifier l'apparence d'un champ selon qu'il est modifiable ou non. Avec la fonction par défaut, l'arrière-plan présente ou n'a pas de réponse de survol (bordure) s'il est/n'est pas modifiable. La taille de l'écran d'un bloc ne doit pas changer en fonction de sa possibilité 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 du champ afin de pouvoir l'actualiser 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 un autre état, tel que l'état de l'interface utilisateur du champ. Par exemple, si votre champ était une carte avec possibilité de zoom permettant à l'utilisateur de sélectionner des pays, vous pouvez é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 Blockly.Field de base, (2) votre valeur est un type sérialisable JSON et (3) vous devez seulement sérialiser la valeur, l'implémentation par défaut fonctionnera parfaitement.

Sinon, votre fonction saveState doit renvoyer un objet ou une valeur JSON sérialisable qui représente l'état du champ. De plus, votre fonction loadState doit accepter le même objet/valeur JSON sérialisable 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 sauvegarde des données

saveState reçoit également un paramètre facultatif doFullSerialization. Elle est utilisée par les champs qui font normalement référence à un état sérialisé par un autre sérialiseur (comme les modèles de données de sauvegarde). Le paramètre indique que l'état référencé n'est pas disponible lorsque le bloc est désérialisé. Le champ doit donc effectuer l'intégralité de la sérialisation. C'est le cas 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 de sauvegarde 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é-collé, le champ crée toujours un modèle de données de sauvegarde au lieu de référencer un modèle existant.

Un champ qui l'utilise est le champ de variable intégrée. Normalement, elle sérialise l'ID de la variable à laquelle elle fait référence, mais si doFullSerialization est défini sur "true", il sérialise l'ensemble de 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, si elle est chargée dans un espace de travail où sa variable n'existe pas, il peut créer une 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 le devez (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. De plus, 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 comporter une UI pour indiquer qu'il est possible d'interagir avec. 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 la section Sérialisation).

Personnaliser le curseur

La propriété CURSOR détermine le curseur que les utilisateurs voient lorsqu'ils passent la souris sur votre champ. Il doit s'agir d'une chaîne de curseur CSS valide. La valeur par défaut est le curseur défini par .blocklyDraggable, qui est le curseur de saisie.