Приоритеты настроек

Внутренняя модель конфигурации Tom Select строится как многоуровневая система объединения источников настроек, где итоговое поведение компонента определяется не отдельным параметром, а результатом разрешения конфликтов между несколькими слоями данных. Каждый слой имеет собственный приоритет, а также особенности применения в момент инициализации и в рантайме. Понимание порядка применения настроек критично для предсказуемого поведения экземпляра и предотвращения скрытых переопределений.

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

  • режим множественного выбора
  • стратегию поиска
  • поведение при создании новых элементов
  • шаблоны отображения
  • параметры загрузки данных
  • обработку клавиатурных событий

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

Конфигурация при инициализации

Следующий уровень — объект параметров, передаваемый при создании экземпляра Tom Select через JavaScript API. Этот слой обладает высоким приоритетом и является основным способом управления поведением компонента.

new TomSelect("#select", {
  maxItems: 3,
  create: true,
  sortField: "text"
});

Значения, переданные таким образом, не заменяют базовую конфигурацию целиком, а накладываются поверх неё. При этом используется неглубокое или частично глубокое слияние в зависимости от типа параметра. Простые типы (boolean, string, number) полностью перезаписывают значения по умолчанию, тогда как структурные параметры (например, callbacks или объекты настроек рендеринга) могут быть объединены частично либо заменены целиком в зависимости от внутренней логики обработки.

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

HTML-атрибуты как источник конфигурации

Tom Select способен извлекать часть настроек непосредственно из HTML-разметки исходного элемента <select>. Этот слой часто используется в декларативной модели и имеет более высокий приоритет по сравнению с дефолтами, но более низкий по сравнению с параметрами инициализации JavaScript.

Пример:

<select id="select" multiple data-max-items="5" data-create="true">

В данном случае значения data-* атрибутов интерпретируются как конфигурационные параметры. Внутренний механизм преобразует строковые значения DOM в соответствующие типы данных. Например:

  • "true"true
  • "false"false
  • числовые строки → number
  • JSON-подобные строки → объекты (в ограниченных сценариях)

Этот слой особенно важен при прогрессивной деградации интерфейса, когда компонент должен работать без явного JavaScript-конфига.

Приоритет между HTML и JavaScript конфигурацией

При столкновении значений из HTML и объекта инициализации применяется строгий приоритет:

  1. Параметры JavaScript-конструктора
  2. data-* атрибуты HTML
  3. значения по умолчанию

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

Плагины как модификаторы конфигурации

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

  • добавлять новые параметры
  • изменять поведение существующих опций
  • переопределять внутренние обработчики
  • внедрять дополнительные настройки рендеринга

Пример подключения:

new TomSelect("#select", {
  plugins: ["remove_button", "dropdown_input"]
});

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

Специфика слияния сложных параметров

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

Рендер-функции

render: {
  option: function(data, escape) {
    return `<div>${escape(data.text)}</div>`;
  }
}

Если базовая конфигурация содержит рендеры, а пользователь задаёт только часть ключей, поведение зависит от типа переопределения:

  • при полной замене объекта render предыдущие значения теряются
  • при частичном расширении (внутренние механизмы merge) отдельные функции могут сохраняться

На практике чаще применяется стратегия полной замены объекта render, что упрощает предсказуемость.

Колбэки

Колбэки вроде onChange, onInitialize, onItemAdd также подчиняются приоритету полной замены. Если в конфигурации указан новый обработчик, он полностью заменяет предыдущий.

Динамическое изменение настроек

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

const select = new TomSelect("#select");

select.setValue("1");
select.settings.placeholder = "Новый текст";
select.sync();

При рантайм-изменениях важно различать:

  • settings — текущая активная конфигурация экземпляра
  • исходный конфиг — недоступен напрямую после инициализации в полном виде
  • DOM-атрибуты — не синхронизируются автоматически

Изменение settings вручную не всегда приводит к немедленному применению. В большинстве случаев требуется вызов методов синхронизации (sync, refreshOptions, clearCache), которые пересчитывают внутреннее состояние.

Приоритеты при загрузке данных

Отдельный слой конфигурации связан с загрузкой данных (load, preload, options). Здесь также существует система приоритетов:

  1. Данные, загруженные через load callback
  2. Статические options
  3. Опции, добавленные через API (addOption)
  4. Данные из DOM

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

Влияние API на конфигурационный приоритет

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

addOption / updateOption

select.addOption({ value: "new", text: "New item" });

Добавленные таким образом данные становятся частью текущего состояния и могут перекрывать исходные options, особенно если совпадает ключ value.

setValue

Метод setValue не изменяет конфигурацию, но изменяет состояние, которое может влиять на визуальное поведение и триггеры событий. Это косвенно влияет на восприятие конфигурации, но не входит в её иерархию.

Иерархия приоритетов в итоговой модели

Сводная модель разрешения конфликтов параметров выглядит следующим образом:

  1. Runtime API (addOption, setValue, removeItem)
  2. JavaScript-конфигурация при инициализации
  3. Плагины (если не переопределены явно)
  4. HTML data-* атрибуты
  5. Встроенные значения по умолчанию

Эта иерархия не является линейной в строгом математическом смысле, поскольку отдельные подсистемы (рендеринг, данные, события) имеют собственные под-иерархии, но в большинстве практических сценариев именно эта модель определяет итоговое поведение.

Побочные эффекты переопределения

Изменение параметров с высоким приоритетом может приводить к неожиданным эффектам:

  • пересоздание внутренних списков опций
  • сброс состояния поиска
  • повторная инициализация событийных обработчиков
  • пересборка DOM-структуры dropdown

Особенно заметно это при изменении параметров, связанных с render и load, поскольку они затрагивают сразу несколько слоёв внутренней архитектуры.

Контекстное наследование настроек

В случае множественных экземпляров Tom Select на странице конфигурация не наследуется автоматически между инстансами. Каждый экземпляр формирует собственную цепочку приоритетов, начиная с базовых дефолтов. Однако общие паттерны часто повторяются, что создаёт иллюзию глобальной конфигурации, хотя фактически её нет.

При использовании фабричных функций или обёрток над инициализацией может формироваться внешний слой, который задаёт единые настройки для группы экземпляров, но внутри Tom Select он не имеет специального статуса и рассматривается как обычный JavaScript-объект инициализации.

Конфликт одинаковых параметров

Если один и тот же параметр задан в нескольких слоях, разрешение происходит строго по приоритету. Например:

  • HTML: data-max-items="2"
  • JS: maxItems: 5
  • default: null

Итоговое значение будет 5, поскольку JavaScript-конфигурация перекрывает остальные источники. Даже если HTML задан позже в DOM-структуре, он не влияет на уже применённый JS-конфиг.

Такая модель обеспечивает стабильность поведения независимо от способа интеграции компонента в приложение.