Определить блоки

Определения блоков описывают, как блок выглядит и ведет себя, включая текст, цвет, форму и то, с какими другими блоками он может соединяться.

Формат JSON и API JavaScript

Blockly имеет два способа определения блоков: объекты JSON и функции JavaScript. Формат JSON предназначен для упрощения процесса локализации при разработке для языков с разным порядком слов. Формат JSON является предпочтительным методом определения блоков.

Однако формат JSON не может напрямую определять расширенные функции, такие как мутаторы или валидаторы. Они должны быть написаны на JavaScript, обычно в виде расширений .

Приложения, использующие исходную реализацию Blockly на JavaScript, также могут записывать определения блоков непосредственно в вызовы функций Blockly API нижнего уровня, как показано в различных примерах JavaScript ниже.

JSON

Blockly.defineBlocksWithJsonArray([{
  "type": "string_length",
  "message0": 'length of %1',
  "args0": [
    {
      "type": "input_value",
      "name": "VALUE",
      "check": "String"
    }
  ],
  "output": "Number",
  "colour": 160,
  "tooltip": "Returns number of letters in the provided text.",
  "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
}]);

JavaScript

Blockly.Blocks['string_length'] = {
  init: function() {
    this.appendValueInput('VALUE')
        .setCheck('String')
        .appendField('length of');
    this.setOutput(true, 'Number');
    this.setColour(160);
    this.setTooltip('Returns number of letters in the provided text.');
    this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp');
  }
};

Функция init создает форму блока. В контексте этой функции ключевое слово this — это фактически создаваемый блок.

Оба примера загружают один и тот же блок string_length.

В Интернете формат JSON загружается с помощью функции initJson . Это также позволяет смешивать два формата на веб-страницах Blockly. По возможности рекомендуется определять блок с помощью JSON и использовать JavaScript только для тех частей определений блоков, которые JSON не поддерживает.

Ниже приведен пример блока, который преимущественно определен с использованием JSON, но расширен с помощью API JavaScript для добавления динамической всплывающей подсказки.

JavaScript

var mathChangeJson = {
  "message0": "change %1 by %2",
  "args0": [
    {"type": "field_variable", "name": "VAR", "variable": "item", "variableTypes": [""]},
    {"type": "input_value", "name": "DELTA", "check": "Number"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 230
};

Blockly.Blocks['math_change'] = {
  init: function() {
    this.jsonInit(mathChangeJson);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "%1".'.replace('%1',
          thisBlock.getFieldValue('VAR'));
    });
  }
};

Цвет блока

Основной цвет блока определяется свойством colour JSON, функцией block.setColour(..) или использованием тем и определением стиля блока.

JSON

{
  // ...,
  "colour": 160,
}

JavaScript

init: function() {
  // ...
  this.setColour(160);
}

Более подробную информацию см. в руководстве по цветам блоков .

Связи операторов

Пользователи могут создавать последовательности блоков, используя соединители nextStatement и previousStatement . В стандартной компоновке Blockly эти соединения находятся сверху и снизу, а блоки расположены вертикально.

Блок с предыдущим разъемом не может иметь выходной разъем , и наоборот. Термин «блок операторов» относится к блоку без вывода значения. Блок операторов обычно имеет как предыдущее, так и следующее соединение.

Соединения nextStatement и previousStatement могут быть типизированы , но эта возможность не используется стандартными блоками.

Следующее соединение

Создает точку внизу блока, чтобы под ней можно было разместить другие операторы. Блок со следующим соединением, но без предыдущего соединения, обычно представляет событие и может быть настроен для рендеринга с помощью шляпы .

JSON

Нетипизированный:

{
  ...,
  "nextStatement": null,
}

Напечатано ( редко ):

{
  "nextStatement": "Action",
  ...
}

JavaScript

Нетипизированный:

this.setNextStatement(true);  // false implies no next connector, the default

Напечатано (редко):

this.setNextStatement(true, 'Action');

Предыдущее подключение

Создает вырез в верхней части блока, чтобы его можно было соединить как стек операторов.

Блоки с предыдущим соединением не могут иметь выходное соединение.

JSON

Нетипизированный:

{
  ...,
  "previousStatement": null,
}

Напечатано ( редко ):

{
  "previousStatement": "Action",
  ...
}

JavaScript

Нетипизированный:

this.setPreviousStatement(true);  // false implies no previous connector, the default

Напечатано (редко):

this.setPreviousStatement(true, 'Action');

Блок вывода

Блок может иметь один выход, представленный в виде вилки-лобзика на передней кромке. Выходы подключаются к входам значений. Блоки с выходом обычно называются блоками значений .

JSON

Нетипизированный:

{
  // ...,
  "output": null,
}

Напечатано:

{
  // ...,
  "output": "Number",
}

JavaScript

Нетипизированный:

init: function() {
  // ...
  this.setOutput(true);
}

Напечатано:

init: function() {
  // ...
  this.setOutput(true, 'Number');
}

Блоки с выходным разъемом также не могут иметь предыдущую выемку.

Блокировать входы

Блок имеет один или несколько входов, где каждый вход имеет последовательность полей и может заканчиваться соединением. Существует несколько типов встроенных входов.

  • Вход значения : подключается к выходному соединению блока значений . Блок math_arithmetic (сложение, вычитание) является примером блока с двумя входными значениями.
  • Ввод оператора : подключается к предыдущему соединению блока операторов . Вложенный раздел цикла while является примером ввода оператора.
  • Фиктивный вход : Не имеет блочного соединения. Действует как новая строка, когда блок настроен на использование внешних входных значений.
  • Ввод конечной строки : не имеет блочного соединения и всегда действует как новая строка.

Вы также можете создать собственный ввод для поддержки пользовательского рендеринга .

Формат JSON и API JavaScript используют несколько разные модели для описания входных данных.

Входные данные и поля в JSON

Определенные в JSON блоки структурированы как последовательность интерполированных строк сообщений ( message0 , message1 , ...), где каждый токен интерполяции ( %1 , %2 , ...) является полем или концом ввода (таким образом, где входной соединитель отображается внутри сообщения) в соответствующем массиве JSON argsN . Этот формат предназначен для облегчения интернационализации.

JSON

{
  "message0": "set %1 to %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

Токены интерполяции должны полностью соответствовать массиву args0 : никаких дубликатов и пропусков. Токены могут присутствовать в любом порядке, что позволяет на разных языках менять расположение блока.

Текст по обе стороны от токена интерполяции обрезается по пробелам. В тексте, использующем символ % (например, при упоминании процента), следует использовать %% , чтобы он не интерпретировался как токен интерполяции.

Порядок аргументов и типы аргументов определяют форму блока. Изменение одной из этих строк может полностью изменить макет блока. Это особенно важно для языков, порядок слов в которых отличается от английского. Рассмотрим гипотетический язык, в котором "set %1 to %2" (как в примере выше) нужно поменять местами, чтобы сказать "put %2 in %1" . Изменение этой строки (и оставление остальной части JSON нетронутой) приводит к следующему блоку:

Blockly автоматически изменил порядок полей, создал фиктивный ввод и переключился с внешних входов на внутренние.

Blockly также автоматически заменяет любой символ новой строки ( \n ) в строке сообщения вводом конечной строки.

JSON

{
  "message0": "set %1\nto %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

Аргументы

Каждая строка сообщения связана с массивом args того же номера. Например, message0 сочетается с args0 . Токены интерполяции ( %1 , %2 , ...) относятся к элементам массива args . Каждый объект имеет строку type . Остальные параметры варьируются в зависимости от типа:

Вы также можете определить свои собственные настраиваемые поля и настраиваемые входные данные и передать их в качестве аргументов.

Каждый объект также может иметь поле alt . В случае, если Blockly не распознает type объекта, вместо него используется alt объект. Например, если в Blockly добавлено новое поле с именем field_time , блоки, использующие это поле, могут использовать alt для определения резервного варианта field_input для старых версий Blockly:

JSON

{
  "message0": "sound alarm at %1",
  "args0": [
    {
      "type": "field_time",
      "name": "TEMPO",
      "hour": 9,
      "minutes": 0,
      "alt":
        {
          "type": "field_input",
          "name": "TEMPOTEXT",
          "text": "9:00"
        }
    }
  ]
}

alt объект может иметь свой собственный alt объект, что позволяет создавать цепочки. В конечном счете, если Blockly не может создать объект в массиве args0 (после попытки использования любых alt объектов), этот объект просто пропускается.

Фиктивный ввод будет автоматически добавлен в конец блока, если строка message заканчивается текстом или полями, которые не содержатся во вводе. Таким образом, если последний ввод в блоке является фиктивным вводом, то его можно опустить из массива args и не требуется интерполяция в message . Автоматическое добавление хвостового фиктивного ввода позволяет переводчикам изменять message без необходимости изменять остальную часть JSON. См. пример "set %1 to %2" (без фиктивного ввода) и "put %2 in %1" (добавлен фиктивный ввод) ранее на этой странице.

implicitAlign0

В редких случаях автоматически созданный конечный фиктивный вход необходимо выровнять по "RIGHT" или "CENTRE" . По умолчанию, если не указано иное, используется "LEFT" .

В приведенном ниже примере message0 — это "send email to %1 subject %2 secure %3" и Blockly автоматически добавляет фиктивный ввод для третьей строки. Установка для implicitAlign0 значения "RIGHT" приводит к выравниванию этой строки по правому краю. Это выравнивание применяется ко всем входным данным, которые не определены явно в определении блока JSON, включая входные данные конечной строки, которые заменяют символы новой строки ( '\n' ) в сообщении. Существует также устаревшее свойство lastDummyAlign0 , которое ведет себя так же, как и implicitAlign0 .

При проектировании блоков для RTL (арабского и иврита) левое и правое меняются местами. Таким образом, "RIGHT" будет выравнивать поля по левому краю.

message1 , args1 , implicitAlign1

Некоторые блоки естественным образом делятся на две или более отдельных частей. Рассмотрим этот повторяющийся блок, который имеет две строки:

Если бы этот блок был описан одним сообщением, свойство message0 было бы "repeat %1 times %2 do %3" . Эта строка неудобна для переводчика, сложно объяснить, что означает замена %2 . Фиктивный ввод %2 также может быть нежелательным на некоторых языках. И может быть несколько блоков, которые хотят совместно использовать текст второй строки. Лучшим подходом является использование JSON более одного свойства message и args:

JSON

{
  "type": "controls_repeat_ext",
  "message0": "repeat %1 times",
  "args0": [
    {"type": "input_value", "name": "TIMES", "check": "Number"}
  ],
  "message1": "do %1",
  "args1": [
    {"type": "input_statement", "name": "DO"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 120
}

В формате JSON можно определить любое количество свойств message , args и implicitAlign , начиная с 0 и последовательно увеличиваясь. Обратите внимание, что Фабрика блоков не способна разбивать сообщения на несколько частей, но сделать это вручную несложно.

Входные данные и поля в JavaScript

API JavaScript включает метод append для каждого типа ввода:

JavaScript

this.appendEndRowInput()
    .appendField('for each')
    .appendField('item')
    .appendField(new Blockly.FieldVariable());
this.appendValueInput('LIST')
    .setCheck('Array')
    .setAlign(Blockly.inputs.Align.RIGHT)
    .appendField('in list');
this.appendStatementInput('DO')
    .appendField('do');
this.appendDummyInput()
    .appendField('end');

Каждый метод добавления может принимать строку идентификатора, используемую генераторами кода. Фиктивные входные данные и входные данные конечной строки редко требуют ссылки, и идентификатор обычно не устанавливается.

API JavaScript также включает общий метод appendInput для добавления пользовательских входных данных . Обратите внимание, что в этом случае идентификатор должен быть передан непосредственно в конструктор вашего пользовательского ввода.

JavaScript

this.appendInput(new MyCustomInput('INPUT_NAME'))
    .appendField('an example label')

Все методы appendInput (как универсальные, так и неуниверсальные) возвращают входной объект, чтобы их можно было дополнительно настроить с помощью цепочки методов. Для настройки входов используются три встроенных метода.

setCheck

JavaScript

input.setCheck('Number');

Эта дополнительная функция используется для проверки типа подключенных входов. Если задан аргумент, равный нулю (по умолчанию), то этот вход можно подключить к любому блоку. Подробности см. в разделе «Проверки типов» .

setAlign

JavaScript

input.setAlign(Blockly.inputs.Align.RIGHT);

Эта дополнительная функция используется для выравнивания полей (см. ниже). Существует три самоописательных значения, которые могут быть переданы в качестве аргумента этой функции: Blockly.inputs.Align.LEFT , Blockly.inputs.Align.RIGHT и Blockly.inputs.Align.CENTER .

При проектировании блоков для RTL (арабского и иврита) левое и правое меняются местами. Таким образом, Blockly.inputs.Align.RIGHT выравнивает поля по левому краю.

appendField

После того, как ввод был создан и добавлен к блоку с помощью appendInput , можно при желании добавить к вводу любое количество полей . Эти поля часто используются в качестве меток для описания того, для чего предназначен каждый ввод.

JavaScript

input.appendField('hello');

Самый простой элемент поля — текст. Соглашение Blockly заключается в использовании всего текста в нижнем регистре, за исключением имен собственных (например, Google, SQL).

Входная строка может содержать любое количество элементов поля. Несколько вызовов appendField могут быть объединены в цепочку для эффективного добавления нескольких полей в одну и ту же входную строку.

JavaScript

input.appendField('hello')
     .appendField(new Blockly.FieldLabel('Neil', 'person'));

Вызов appendField('hello') на самом деле является ярлыком для использования явного конструктора FieldLabel: appendField(new Blockly.FieldLabel('hello')) . Конструктор можно использовать только при указании имени класса, чтобы текст можно было стилизовать с помощью правила CSS.

Встроенный или внешний

Входные данные блока могут отображаться как внешние, так и внутренние.

В определении блока можно указать необязательное логическое значение, определяющее, являются ли входные данные встроенными или нет. Если false , то любые входные значения будут внешними (например, левый блок). Если true , то любые входные значения будут встроенными (например, правый блок выше).

JSON

{
  // ...,
  "inputsInline": true
}

JavaScript

init: function() {
  // ...
  this.setInputsInline(true);
}

Если он не определен, Blockly будет использовать некоторые эвристики, чтобы угадать, какой режим лучше. Предполагая, что Blockly сделает правильный выбор, предпочтительнее оставить это поле неопределенным, поскольку переводы на разные языки могут автоматически иметь разные режимы. См. пример JSON "set %1 to %2" (внешние входные данные) и "put %2 in %1" (встроенные входные данные) ранее на этой странице.

Используйте встроенные входные данные, когда блок может содержать небольшие входные данные, например числа. Пользователь может переключить эту опцию через контекстное меню, если включена конфигурация collapse (по умолчанию установлено значение true, если панель инструментов имеет категории).

Поля

Поля определяют большинство элементов пользовательского интерфейса внутри блока. К ним относятся метки строк, изображения и входные данные для литеральных данных, таких как строки и числа. Самый простой пример — блок math_number , который использует field_input , чтобы позволить пользователю вводить число.

Поля добавляются в блок с помощью AppendField .

Blockly предоставляет ряд встроенных полей, включая текстовые поля, палитры цветов и изображения. Вы также можете создавать свои собственные поля.

→ Дополнительная информация о встроенных полях .

→ Дополнительная информация о создании настраиваемого поля .

Иконки

Значки определяют элементы пользовательского интерфейса в блоке, которые отображают «мета» информацию о блоке.

Иконки добавляются в блок с помощью addIcon .

Blockly предоставляет ряд встроенных значков, включая значки комментариев и значки предупреждений. Вы также можете создавать свои собственные значки.

→ Дополнительная информация о создании собственных значков .

Подсказки

Подсказки предлагают мгновенную помощь, когда пользователь наводит указатель мыши на блок. Если текст длинный, он будет перенесен автоматически.

JSON

{
  // ...,
  "tooltip": "Tooltip text."
}

JavaScript

init: function() {
  this.setTooltip("Tooltip text.");
}

В API JavaScript всплывающие подсказки также можно определить как функцию, а не как статическую строку. Это позволяет оказывать динамическую помощь. См. math_arithmetic для примера всплывающей подсказки, которая меняется в зависимости от того, какой вариант раскрывающегося списка был выбран.

JavaScript

Blockly.Blocks['math_arithmetic'] = {
  init: function() {
    // ...

    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var mode = thisBlock.getFieldValue('OP');
      var TOOLTIPS = {
        'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
        'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
        'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
        'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
        'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
      };
      return TOOLTIPS[mode];
    });
  }
};

Используя API JavaScript, блоки могут указывать функцию вместо статической строки, которая возвращает строку подсказки. Это позволяет использовать динамические подсказки. См. пример math_arithmetic .

Настройка

Вы также можете настроить внешний вид всплывающих подсказок, предоставив специальную функцию рендеринга. Создайте функцию, которая принимает два параметра:

  • во-первых, элемент <div> , в котором вы будете отображать содержимое
  • во-вторых, фактический элемент, на который наводится курсор мыши и для которого вы покажете всплывающую подсказку

В теле функции вы можете отображать в div любой контент, который вам нравится. Чтобы получить строку подсказки, определенную для блока, на который наведен курсор, вы можете вызвать Blockly.Tooltip.getTooltipOfObject(element); где element — второй параметр выше.

Наконец, зарегистрируйте эту функцию, чтобы Blockly мог вызвать ее в подходящее время:

Blockly.Tooltip.setCustomTooltip(yourFnHere);

Пример см. в демонстрации «Пользовательские всплывающие подсказки» .

URL-адрес справки

Блоки могут иметь связанную с ними страницу справки. Это доступно пользователям Blockly for Web, щелкнув блок правой кнопкой мыши и выбрав «Справка» в контекстном меню. Если это значение равно null , меню будет выделено серым цветом.

JSON

{
  // ...,
  "helpUrl": "https://en.wikipedia.org/wiki/For_loop"
}

JavaScript

init: function() {
  // ...
  this.setHelpUrl('https://en.wikipedia.org/wiki/For_loop');
}

Используя API JavaScript, блоки могут указывать функцию вместо статической строки, которая возвращает строку URL-адреса, что позволяет использовать динамическую справку.

Изменить прослушиватели и валидаторы

Блоки могут иметь функции прослушивания изменений, которые вызываются при любом изменении рабочей области (включая те, которые не связаны с блоком). Они в основном используются для установки текста предупреждения блока или аналогичного уведомления пользователя за пределами рабочей области.

Функция добавляется путем вызова setOnChange с функцией и может быть выполнена во время инициализации или через расширение JSON , если вы планируете использовать его на всех платформах.

JSON

{
  // ...,
  "extensions":["warning_on_change"],
}

Blockly.Extensions.register('warning_on_change', function() {
  // Example validation upon block change:
  this.setOnChange(function(changeEvent) {
    if (this.getInput('NUM').connection.targetBlock()) {
      this.setWarningText(null);
    } else {
      this.setWarningText('Must have an input block.');
    }
  });
});

JavaScript

Blockly.Blocks['block_type'] = {
  init: function() {
    // Example validation upon block change:
    this.setOnChange(function(changeEvent) {
      if (this.getInput('NUM').connection.targetBlock()) {
        this.setWarningText(null);
      } else {
        this.setWarningText('Must have an input block.');
      }
    });
  }
}

Система вызывает функцию, передавая событие изменения . Внутри функции this относится к экземпляру блока.

Поскольку функция вызывается при любом изменении, если она используется, разработчики должны обеспечить быстрое выполнение прослушивателя. Также следует опасаться изменений в рабочей области, которые могут каскадно или зацикленно вернуться к слушателю.

Примеры см. в блоках controls_flow_statements , logic_compare и procedures_ifreturn .

Обратите внимание, что редактируемые поля имеют собственные прослушиватели событий для проверки ввода и возникновения побочных эффектов.

Мутатор

Мутаторы позволяют расширенным блокам менять форму, особенно в результате того, что пользователи открывают диалоговое окно для добавления, удаления или изменения порядка компонентов. Мутаторы можно добавлять через JSON с помощью ключа mutator .

JSON

{
  // ...,
  "mutator":"if_else_mutator"
}

Поблочная конфигурация

Экземпляры блоков имеют ряд свойств, определяющих их поведение по отношению к пользователю. Их можно использовать для ограничения рабочей области, чтобы она отражала определенные свойства предметной области (например, существует только одно «стартовое» событие) или для концентрации усилий пользователя (например, учебное пособие).

Удаляемое состояние

block.setDeletable(false);

Если установлено значение false, пользователь не сможет удалить блок. Блоки по умолчанию доступны для удаления в редактируемой рабочей области.

Любой блок (даже неудаляемый) можно удалить программно:

block.dispose();

Редактируемое состояние

block.setEditable(false);

Если установлено значение false, пользователь не сможет изменять поля блока (например, раскрывающиеся списки и ввод текста). Блоки по умолчанию доступны для редактирования в редактируемой рабочей области.

Подвижное государство

block.setMovable(false);

Если установлено значение false, пользователь не сможет напрямую перемещать блок. Неподвижный блок, который является дочерним по отношению к другому блоку, не может быть отключен от этого блока, хотя он будет перемещаться вместе со своим родителем, если родительский блок будет перемещен. Блоки по умолчанию являются перемещаемыми в редактируемой рабочей области.

Любой блок (даже неподвижный) можно переместить программно, как только он окажется в рабочей области.

block.moveBy(dx, dy)

Начальная позиция блока в рабочей области по умолчанию равна (0, 0).

Блокировать данные

this.data = '16dcb3a4-bd39-11e4-8dfc-aa07a5b093db';

Данные — это необязательная и произвольная строка, прикрепленная к блоку. Когда блок сериализуется, строка данных сериализуется вместе с ним. Это включает в себя ситуации, когда блок дублируется или копируется/вставляется.

Часто это используется для связи блока с внешним ресурсом.

При сериализации в JSON данные сохраняются как свойство верхнего уровня в блоке:

{
  "type": "my_block",
  "data": "16dcb3a4-bd39-11e4-8dfc-aa07a5b093db",
  // etc..
}

При сериализации в XML (старая система сериализации Icebox) строка данных сохраняется в теге <data></data> внутри блока:

<block type="my_block">
  <data>16dcb3a4-bd39-11e4-8dfc-aa07a5b093db</data>
  <!-- etc... -->
</block>

Разрушение

У блоков есть хук destroy , который вызывается, когда они удаляются из рабочей области. Это можно использовать для уничтожения любых резервных моделей данных/внешних ресурсов, связанных с блоком, которые больше не нужны.

JSON

{
  // ...,
  "extensions":["destroy"],
}

Blockly.Extensions.registerMixin('destroy', {
  destroy: function() {
    this.myResource.dispose();
  }
});

JavaScript

Blockly.Blocks['block_type'] = {
  destroy: function() {
    this.myResource.dispose();
  }
}

Метод destroy вызывается после удаления родителя блока, но до того, как будут удалены какие-либо его дочерние элементы или поля.

Контекстные меню

По умолчанию блоки имеют контекстное меню, вызываемое правой кнопкой мыши, которое позволяет пользователям добавлять комментарии или дублировать блоки.

Вы можете отключить контекстное меню отдельного блока, выполнив:

block.contextMenu = false;

Вы также можете настроить параметры, отображаемые в меню. Чтобы настроить меню для всех блоков, обратитесь к документации по контекстным меню . Чтобы настроить меню для отдельного блока, вы можете реализовать customContextMenu . Эта функция принимает массив опций меню и изменяет их на месте, что означает, что вы можете как добавлять, так и удалять элементы.

Каждый пункт меню представляет собой объект с тремя свойствами:

  • text — отображаемый текст.
  • enabled — это логическое значение. Если этот параметр отключен, он отображается, но с серым текстом.
  • callback — это функция, которая будет вызываться при выборе опции.