Champs de menu déroulant

Le champ déroulant stocke une chaîne en tant que valeur et une chaîne en tant que texte. La est une clé indépendante du langage qui sera utilisée pour accéder au texte n'est pas traduit lorsque vous changez de langue avec Blockly. Le texte est une chaîne lisible qui sera présentée à l'utilisateur.

Création

Le constructeur de menu déroulant utilise un générateur de menu et un programme de validation. Le générateur de menu a beaucoup de la flexibilité, mais il s'agit essentiellement d'un tableau d'options, chacune contenant une une partie lisible par l'humain et une chaîne indépendante du langage.

Menus déroulants contenant du texte simple

Ouvrir le menu déroulant avec deux options de texte

JSON

{
  "type": "example_dropdown",
  "message0": "drop down: %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FIELDNAME",
      "options": [
        [ "first item", "ITEM1" ],
        [ "second item", "ITEM2" ]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['example_dropdown'] = {
  init: function() {
    this.appendDummyInput()
        .appendField('drop down:')
        .appendField(new Blockly.FieldDropdown([
            ['first item', 'ITEM1'],
            ['second item', 'ITEM2']
        ]), 'FIELDNAME');
  }
};

Séparer les informations lisibles par l'humain de la clé neutre en termes de langue permet de conserver les paramètres du menu déroulant d'une langue à l'autre. Pour instance Une version anglaise d'un bloc peut définir [['left', 'LEFT'], ['right', 'RIGHT]] tandis qu'une version allemande du même bloc définirait [['links', 'LEFT'], ['rechts', 'RIGHT]].

Menus déroulants d'images

Les options d'un menu déroulant peuvent également être des images au lieu de texte. Les objets image sont spécifié avec les propriétés src, width, height et alt.

Remarque : bien qu'un menu déroulant puisse contenir à la fois des options de texte et d'image, une option individuelle ne peut pas contenir à la fois une image et du texte.

Champ déroulant contenant des images et du texte

JSON

{
  "type": "image_dropdown",
  "message0": "flag %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FLAG",
      "options": [
        ["none", "NONE"],
        [{"src": "canada.png", "width": 50, "height": 25, "alt": "Canada"}, "CANADA"],
        [{"src": "usa.png", "width": 50, "height": 25, "alt": "USA"}, "USA"],
        [{"src": "mexico.png", "width": 50, "height": 25, "alt": "Mexico"}, "MEXICO"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['image_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
        .appendField('flag');
    var options = [
        ['none', 'NONE'],
        [{'src': 'canada.png', 'width': 50, 'height': 25, 'alt': 'Canada'}, 'CANADA'],
        [{'src': 'usa.png', 'width': 50, 'height': 25, 'alt': 'USA'}, 'USA'],
        [{'src': 'mexico.png', 'width': 50, 'height': 25, 'alt': 'Mexico'}, 'MEXICO']
    ];
    input.appendField(new Blockly.FieldDropdown(options), 'FLAG');
  }
};

Menus déroulants dynamiques

Menu déroulant avec les jours de la semaine

JSON

{
  "type": "dynamic_dropdown",
  "message0": "day %1",
  "args0": [
    {
      "type": "input_dummy",
      "name": "INPUT"
    }
  ],
  "extensions": ["dynamic_menu_extension"]
}
Blockly.Extensions.register('dynamic_menu_extension',
  function() {
    this.getInput('INPUT')
      .appendField(new Blockly.FieldDropdown(
        function() {
          var options = [];
          var now = Date.now();
          for(var i = 0; i < 7; i++) {
            var dateString = String(new Date(now)).substring(0, 3);
            options.push([dateString, dateString.toUpperCase()]);
            now += 24 * 60 * 60 * 1000;
          }
          return options;
        }), 'DAY');
  });

Pour ce faire, vous devez utiliser un fichier extension.

JavaScript

Blockly.Blocks['dynamic_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
      .appendField('day')
      .appendField(new Blockly.FieldDropdown(
        this.generateOptions), 'DAY');
  },

  generateOptions: function() {
    var options = [];
    var now = Date.now();
    for(var i = 0; i < 7; i++) {
      var dateString = String(new Date(now)).substring(0, 3);
      options.push([dateString, dateString.toUpperCase()]);
      now += 24 * 60 * 60 * 1000;
    }
    return options;
  }
};

Un menu déroulant peut également être fourni avec une fonction au lieu d'une liste d'éléments statiques ce qui leur permet d'être dynamiques. La fonction doit renvoyer une tableau d'options dans le même [human-readable-value, language-neutral-key] en tant qu'options statiques. Chaque fois que l'utilisateur clique sur le menu déroulant, et les options sont recalculées.

Sérialisation

JSON

Le JSON d'un champ de liste déroulante se présente comme suit:

{
  "fields": {
    "FIELDNAME": "LANGUAGE-NEUTRAL-KEY"
  }
}

FIELDNAME est une chaîne faisant référence à un champ de liste déroulante, et où la valeur est celle à appliquer au champ. Cette valeur doit être une la clé d'option neutre de la langue cible.

XML

Le code XML d'un champ de liste déroulante se présente comme suit:

<field name="FIELDNAME">LANGUAGE-NEUTRAL-KEY</field>

Où l'attribut name du champ contient une chaîne faisant référence à un menu déroulant et le texte interne est la valeur à appliquer au champ. L'intérieur le texte doit être une clé d'option neutre et valide.

Personnalisation

La propriété Blockly.FieldDropdown.ARROW_CHAR permet de modifier caractère Unicode représentant la flèche de la liste déroulante.

Champ déroulant avec une flèche personnalisée

Par défaut, la propriété ARROW_CHAR est définie sur \u25BC (▼) sur Android et \u25BE (▾) sinon.

Comme il s'agit d'une propriété globale, tous les champs de la liste déroulante sont modifiés lorsqu'ils sont définis.

La propriété Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH permet de modifier la hauteur maximale du menu. Il s'agit d'un pourcentage de la fenêtre d'affichage la hauteur, la fenêtre d'affichage étant la fenêtre.

La propriété MAX_MENU_HEIGHT_VH est définie par défaut sur 0,45.

Comme il s'agit d'une propriété globale, tous les champs de la liste déroulante sont modifiés lorsqu'ils sont définis.

Correspondance de préfixe/suffixe

Si toutes les options du menu déroulant partagent un préfixe et/ou un suffixe communs les mots sont automatiquement pris en compte et insérés sous forme de texte statique. Par exemple, voici deux façons de créer le même bloc (la première, sans indication de suffixe, et la deuxième par):

Sans correspondance de suffixe:

JSON

{
  "type": "dropdown_no_matching",
  "message0": "hello %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["world", "WORLD"],
        ["computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_no_matching'] = {
  init: function() {
    var options = [
      ['world', 'WORLD'],
      ['computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField('hello')
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

Avec correspondance de suffixe:

JSON

{
  "type": "dropdown_with_matching",
  "message0": "%1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["hello world", "WORLD"],
        ["hello computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_with_matching'] = {
  init: function() {
    var options = [
      ['hello world', 'WORLD'],
      ['hello computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

Menu déroulant avec

L'un des avantages de cette approche est que le bloc est plus facile à traduire dans d'autres langues. Le code précédent contient les chaînes 'hello', 'world' et 'computer', alors que le code révisé contient les chaînes 'hello world' et 'hello computer' Les traducteurs ont plus de facilité à traduire des expressions les mots de manière isolée.

Un autre avantage de cette approche est que l'ordre des mots change souvent langues. Imaginez un langage qui utilise 'world hello' et 'computer hello'. L'algorithme de mise en correspondance des suffixes détecte le 'hello' courant et l'affiche après le menu déroulant.

Cependant, il arrive que la correspondance du préfixe/suffixe échoue. Dans certains cas, deux mots doivent toujours aller ensemble et le préfixe ne doit pas être exclu. Par exemple, 'drive red car' et 'drive red truck' ne devraient normalement ont été exclus de 'drive', et non de 'drive red'. Le caractère insécable d'Unicode l'espace '\u00A0' peut être utilisé à la place d'un espace normal pour supprimer le un outil de mise en correspondance des préfixes/suffixes. Ainsi, l'exemple ci-dessus peut être corrigé avec 'drive red\u00A0car' et 'drive red\u00A0truck'.

La mise en correspondance des préfixes/suffixes peut également échouer dans les langues qui ne séparez les mots individuels par des espaces. Le chinois en est un bon exemple. La chaîne '訪問中國' signifie 'visit China' (notez le manque d'espaces entre les mots). Collectivement, les deux derniers caractères ('中國') correspondent au mot 'China', mais s'il s'agit d'une division, ils signifient respectivement 'centre' et 'country'. Pour la correspondance de préfixe/suffixe fonctionne dans des langues telles que le chinois, il suffit d'insérer un espace à l'emplacement du saut. Par exemple, '訪問 中國' et '訪問 美國' donnerait "visit [China/USA]", tandis que '訪問 中 國' et '訪問 美 國' générerait "visit [centre/beautiful] country".

Créer un validateur de liste déroulante

La valeur d'un champ déroulant est une chaîne neutre en termes de langue. Par conséquent, tous les validateurs accepter une chaîne et renvoyer une chaîne qui est une option disponible, null ou undefined

Si votre programme de validation renvoie un autre élément, le comportement de Blockly n'est pas défini et votre programme peut planter.

Par exemple, vous pouvez définir un champ déroulant avec trois options et une propriété programme de validation comme suit:

validate: function(newValue) {
  this.getSourceBlock().updateConnections(newValue);
  return newValue;
},

init: function() {
  var options = [
   ['has neither', 'NEITHER'],
   ['has statement', 'STATEMENT'],
   ['has value', 'VALUE'],
  ];

  this.appendDummyInput()
  // Pass the field constructor the options list, the validator, and the name.
      .appendField(new Blockly.FieldDropdown(options, this.validate), 'MODE');
}

validate renvoie toujours la valeur transmise, mais appelle l'application auxiliaire. updateConnection, qui ajoute ou supprime des entrées en fonction du menu déroulant :

updateConnections: function(newValue) {
  this.removeInput('STATEMENT', /* no error */ true);
  this.removeInput('VALUE', /* no error */ true);
  if (newValue == 'STATEMENT') {
    this.appendStatementInput('STATEMENT');
  } else if (newValue == 'VALUE') {
    this.appendValueInput('VALUE');
  }
}