Pola menu

Pole menu zawiera ciąg znaków jako wartość, a ciąg znaków jako tekst. Wartość jest kluczem neutralnym dla języka, która służy do uzyskiwania dostępu do tekstu. Nie zostanie przetłumaczona, gdy Blockly przełączy się między językami. Jest to zrozumiały dla człowieka ciąg tekstowy, który będzie wyświetlany użytkownikowi.

na podstawie trendów

Konstruktor menu obejmuje generator menu i opcjonalny validator. Generator menu jest bardzo elastyczny, ale zasadniczo jest tablicą opcji, z których każda zawiera część zrozumiałą dla człowieka i ciąg znaków neutralny dla języka.

Proste menu tekstowe

Otwórz menu z 2 opcjami tekstowymi

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

Przechowywanie informacji dostępnych dla człowieka niezależnie od klucza neutralnego dla języka pozwala zachować ustawienie menu w różnych językach. Na przykład angielska wersja bloku może zdefiniować element [['left', 'LEFT'], ['right', 'RIGHT]], a niemiecka wersja tego samego bloku określa element [['links', 'LEFT'], ['rechts', 'RIGHT]].

Menu obrazów

Opcje w menu mogą też obejmować obrazy zamiast tekstu. Obiekty graficzne mają właściwości src, width, height i alt.

Pamiętaj, że chociaż menu może zawierać kombinację opcji tekstowych i graficznych, pojedyncza opcja nie może obecnie zawierać zarówno obrazu, jak i tekstu.

Pole z obrazami i tekstem

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

Dynamiczne menu

Pole z dniami tygodnia

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

Użyjesz do tego rozszerzenia 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;
  }
};

Zamiast listy statycznych opcji możesz wykorzystać menu, dzięki czemu opcje te mogą być dynamiczne. Ta funkcja powinna zwrócić tablicę opcji w tym samym formacie [human-readable-value, language-neutral-key] co opcje statyczne. Po każdym kliknięciu menu funkcja zostaje uruchomiona, a opcje są obliczane ponownie.

Serializacja

JSON

Kod JSON pola menu wygląda tak:

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

Gdzie FIELDNAME to ciąg znaków odwołujący się do menu, a wartość to wartość do zastosowania do pola. Wartość powinna być kluczem opcji niezależnym od języka.

XML

Kod XML pola wygląda tak:

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

Gdzie atrybut name pola zawiera ciąg znaków odwołujący się do menu, a tekst wewnętrzny to wartość do zastosowania do pola. Tekst wewnętrzny powinien być prawidłowym kluczem opcji niezależnym od języka.

Personalizacja

Właściwość Blockly.FieldDropdown.ARROW_CHAR może służyć do zmiany znaku Unicode reprezentującego strzałkę w dół.

Pole ze strzałką niestandardową

Właściwość ARROW_CHAR przyjmuje domyślnie wartość \u25BC (▼) na Androidzie lub \u25BE (▾) w przeciwnym razie.

Jest to usługa globalna, więc po skonfigurowaniu będzie modyfikować wszystkie pola menu.

Maksymalna wysokość menu można zmieniać za pomocą właściwości Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH. Wartość ta jest określona jako wartość procentowa wysokości widocznego obszaru, gdzie jest to okno.

Właściwość MAX_MENU_HEIGHT_VH przyjmuje domyślnie wartość 0,45.

Jest to usługa globalna, więc po skonfigurowaniu będzie modyfikować wszystkie pola menu.

Dopasowanie prefiksu/sufiksu

Jeśli wszystkie opcje menu mają wspólne prefiksy lub sufiksy, są one automatycznie usuwane i wstawiane jako tekst statyczny. Na przykład oto 2 sposoby na utworzenie tego samego bloku (pierwszy bez dopasowania sufiksu, a drugi z ):

Bez dopasowania przyrostka:

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

Z pasującym sufiksem:

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

Pole z

Jedną z zalet tego podejścia jest łatwiejsze przetłumaczenie tekstu na inne języki. Wcześniejszy kod zawiera ciągi znaków 'hello', 'world' i 'computer', a poprawiony kod – 'hello world' i 'hello computer'. Tłumacze mają znacznie łatwiej tłumaczyć frazy niż słowa w oderwaniu od siebie.

Inną zaletą tego podejścia jest to, że kolejność słów często się zmienia w różnych językach. Wyobraź sobie język, w którym używano 'world hello' i 'computer hello'. Algorytm dopasowywania sufiksów wykryje typową właściwość 'hello' i wyświetli ją po menu.

Czasami jednak dopasowanie prefiksu/sufiksu kończy się niepowodzeniem. Istnieją sytuacje, w których 2 słowa zawsze powinny występować obok siebie, a prefiks nie powinien być pomijany. Na przykład wartości 'drive red car' i 'drive red truck' powinny mieć uwzględnione tylko 'drive', a nie 'drive red'. W miejscu zwykłej spacji można użyć nierozdzielającej spacji '\u00A0' w zestawie Unicode, aby pominąć dopasowanie prefiksu/sufiksu. Powyższy przykład można poprawić za pomocą właściwości 'drive red\u00A0car' i 'drive red\u00A0truck'.

Błędy w dopasowaniu prefiksów/sufiksów również nie udaje się w językach, w których poszczególne słowa nie są rozdzielone spacjami. Dobrym przykładem jest język chiński. Ciąg '訪問中國' oznacza 'visit China'. Zwróć uwagę na brak spacji między słowami. Łącznie 2 ostatnie znaki ('中國') to słowo powiązane z adresem 'China', a po podzieleniu oznaczałyby odpowiednio 'centre' i 'country'. Aby dopasowanie prefiksów/sufiksów działało w językach takich jak chiński, po prostu wstaw spację w miejscu, w którym powinna być przerwa. Na przykład '訪問 中國' i '訪問 美國' dają wynik "visit [China/USA]", a '訪問 中 國' i '訪問 美 國'"visit [centre/beautiful] country".

Tworzenie walidatora menu

Wartość pola menu jest ciągiem znaków neutralnym dla języka, więc wszystkie narzędzia do sprawdzania poprawności muszą zaakceptować ciąg znaków i zwrócić ciąg znaków będący opcją dostępną, null lub undefined.

Jeśli walidator zwróci cokolwiek innego, działanie Blockly jest niezdefiniowane i program może ulec awarii.

Możesz np. zdefiniować pole z 3 opcjami i walidatorem w ten sposób:

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

Funkcja validate zawsze zwraca przekazaną wartość, ale wywołuje funkcję pomocniczą updateConnection, która dodaje lub usuwa dane wejściowe na podstawie wartości menu:

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