Campi del menu a discesa

Il campo a discesa memorizza una stringa come valore e una stringa come testo. Il valore è una chiave indipendente dalla lingua che verrà utilizzata per accedere al testo e non verrà tradotta quando Blockly passa da una lingua all'altra. Il testo è una stringa leggibile che verrà mostrata all'utente.

Creazione

Il costruttore del menu a discesa include un generatore di menu e uno validator facoltativo. Il generatore di menu offre molta flessibilità, ma è essenzialmente un array di opzioni, ciascuna delle quali contiene una parte leggibile e una stringa indipendente dal linguaggio.

Semplici menu a discesa di testo

Apri menu a discesa con due opzioni di testo

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

Mantenere le informazioni leggibili dalle persone separate dalla chiave neutra per la lingua consente di mantenere l'impostazione del menu a discesa da una lingua all'altra. Ad esempio, una versione inglese di un blocco potrebbe definire [['left', 'LEFT'], ['right', 'RIGHT]], mentre una versione tedesca dello stesso blocco potrebbe definire [['links', 'LEFT'], ['rechts', 'RIGHT]].

Menu a discesa con immagini

Le opzioni di un menu a discesa possono anche essere immagini anziché testo. Gli oggetti immagine sono specificati con le proprietà src, width, height e alt.

Tieni presente che, sebbene un menu a discesa possa avere una combinazione di opzioni per il testo e le opzioni immagine, una singola opzione al momento non può contenere sia un'immagine che un testo.

Campo a discesa contenente immagini e testo

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

Menu a discesa dinamici

Campo a discesa con i giorni della settimana

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

Per farlo, usa un'estensione JSON.

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

È possibile anche fornire un menu a discesa con una funzione anziché con un elenco di opzioni statiche, in modo che le opzioni siano dinamiche. La funzione deve restituire un array di opzioni nello stesso formato [human-readable-value, language-neutral-key] delle opzioni statiche. Ogni volta che si fa clic sul menu a discesa, la funzione viene eseguita e le opzioni vengono ricalcolate.

Serializzazione

JSON

Il codice JSON per un campo a discesa ha il seguente aspetto:

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

Dove FIELDNAME è una stringa che fa riferimento a un campo a discesa e il valore è il valore da applicare al campo. Il valore dovrebbe essere una chiave di opzione neutrale.

XML

L'XML per un campo a discesa ha il seguente aspetto:

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

In cui l'attributo name del campo contiene una stringa che fa riferimento a un campo a discesa e il testo interno è il valore da applicare al campo. Il testo interno deve essere una chiave di opzione valida e indipendente dalla lingua.

Funzionalità di

La proprietà Blockly.FieldDropdown.ARROW_CHAR può essere utilizzata per modificare il carattere Unicode che rappresenta la freccia del menu a discesa.

Campo a discesa con freccia personalizzata

Per impostazione predefinita, la proprietà ARROW_CHAR è \u25BC (▼) su Android e \u25BE (▾).

Si tratta di una proprietà globale, quindi modificherà tutti i campi del menu a discesa, se impostati.

La proprietà Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH può essere utilizzata per modificare l'altezza massima del menu. Viene definita come percentuale dell'altezza dell'area visibile, in cui l'area visibile è la finestra.

Il valore predefinito della proprietà MAX_MENU_HEIGHT_VH è 0,45.

Si tratta di una proprietà globale, quindi modificherà tutti i campi del menu a discesa, se impostati.

Corrispondenza prefisso/suffisso

Se tutte le opzioni del menu a discesa condividono parole con prefissi e/o suffissi comuni, queste parole vengono automaticamente escluse e inserite come testo statico. Ad esempio, ecco due modi per creare lo stesso blocco (il primo senza corrispondenza del suffisso e il secondo con):

Senza corrispondenza del suffisso:

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

Con corrispondenza del suffisso:

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

Campo a discesa con

Un vantaggio di questo approccio è che il blocco è più facile da tradurre in altre lingue. Il codice precedente ha le stringhe 'hello', 'world' e 'computer', mentre il codice rivisto ha le stringhe 'hello world' e 'hello computer'. Per i traduttori è molto più facile tradurre frasi che parole da sole.

Un altro vantaggio di questo approccio è che l'ordine delle parole cambia spesso da una lingua all'altra. Immagina una lingua che utilizza 'world hello' e 'computer hello'. L'algoritmo di corrispondenza dei suffissi rileverà il valore 'hello' comune e lo mostrerà dopo il menu a discesa.

Tuttavia, a volte la corrispondenza del prefisso/suffisso non va a buon fine. In alcuni casi, due parole devono sempre essere inserite insieme e il prefisso non deve essere ignorato. Ad esempio, 'drive red car' e 'drive red truck' dovrebbero essere esclusi solo 'drive', non 'drive red'. Lo spazio unificatore Unicode '\u00A0' può essere utilizzato al posto di uno spazio normale per sopprimere il matcher prefisso/suffisso. Pertanto, l'esempio riportato sopra può essere corretto con 'drive red\u00A0car' e 'drive red\u00A0truck'.

Un altro caso in cui la corrispondenza di prefisso/suffisso non riesce è nelle lingue che non separano le singole parole con spazi. Il cinese è un buon esempio. La stringa '訪問中國' significa 'visit China'; tieni presente la mancanza di spazi tra le parole. Collettivamente, gli ultimi due caratteri ('中國') corrispondono alla parola 'China', ma se suddivisi significheranno rispettivamente 'centre' e 'country'. Per far sì che la corrispondenza di prefisso/suffisso in lingue come il cinese, inserisci semplicemente uno spazio nel punto in cui deve trovarsi l'interruzione. Ad esempio, '訪問 中國' e '訪問 美國' generano "visit [China/USA]", mentre '訪問 中 國' e '訪問 美 國' generano "visit [centre/beautiful] country".

Creazione di uno strumento di convalida a discesa

Il valore di un campo a discesa è una stringa indipendente dal linguaggio, quindi qualsiasi convalidatore deve accettare una stringa e restituire una stringa che è un'opzione disponibile, null o undefined.

Se lo strumento di convalida restituisce altro, il comportamento di Blockly non è definito e il programma potrebbe arrestarsi in modo anomalo.

Ad esempio, potresti definire un campo a discesa con tre opzioni e uno strumento di convalida come il seguente:

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 restituisce sempre il valore passato, ma chiama la funzione helper updateConnection che aggiunge o rimuove input in base al valore del menu a discesa:

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