triggers
Описание
Необязательный. Определяет триггеры выпадающего списка для вставки упоминаний, тегов и других токенов
Когда пользователь вводит настроенный символ (например, @ или #), RichText открывает выпадающий список с заранее заданными элементами. Когда пользователь выбирает элемент, RichText вставляет его в документ как нередактируемый токен (<a data-token="..." data-token-id="...">).
Применение
triggers?: Array<{
trigger: string,
data: Array<{ id?: string | number; label?: string; url?: string }>
| ((query: string) =>
Array<{ id?: string | number; label?: string; url?: string }>
| Promise<Array<{ id?: string | number; label?: string; url?: string }>>),
showTrigger?: boolean,
action?: (item) => void
}>;
Параметры
Каждый элемент массива triggers принимает следующие поля:
trigger- (обязательный) символ, который открывает выпадающий список с подсказками (например,"@","#","/","$")data- (обязательный) источник данных для выпадающего списка; может быть массивом, синхронной функцией или асинхронной функцией. См. Формы источника данныхshowTrigger- (необязательный) еслиtrue(по умолчанию), RichText сохраняет символ триггера во вставленном токене (например,@Alice); еслиfalse, RichText вставляет толькоlabel(например,Alice)action- (необязательный) пользовательский калбэк, вызываемый при выборе элемента пользователем. Если задан, RichText удаляет введ ённый текст триггера (символ триггера и строку запроса) и вызываетaction(item)вместо вставки токена. Калбэк получает выбранный элемент и может вставить любое содержимое вместо выбранного. Параметрactionимеет приоритет надshowTrigger, который не оказывает эффекта, если заданaction. См. Пользовательское действие
Формы источника данных
- Статический массив — RichText автоматически фильтрует массив, сопоставляя запрос с полем
label(без учёта регистра,startsWith):
new richtext.Richtext("#root", {
triggers: [{
trigger: "@",
data: [
{ id: "alice", label: "Alice" },
{ id: "bob", label: "Bob" }
]
}]
});
- Синхронная функция — RichText вызывает вашу функцию с текущей строкой
query; вы выполняете фильтрацию и возвращаете подходящий массив:
new richtext.Richtext("#root", {
triggers: [{
trigger: "#",
data: query => tags.filter(t =>
t.label.toLowerCase().startsWith(query.toLowerCase())
)
}]
});
- Асинхронная функция — RichText вызывает вашу функцию с текущей строкой
query; возвращайтеPromise, который разрешается в подходящий массив. Удобно для серверного поиска:
new richtext.Richtext("#root", {
triggers: [{
trigger: "+",
data: async query => {
const res = await fetch(`/api/users?q=${encodeURIComponent(query)}`);
const users = await res.json();
return users.map(u => ({ id: String(u.id), label: u.name, url: u.website }));
}
}]
});
Поля элемента подсказки
Каждый элемент в data (или каждый элемент, возвращаемый функцией) содержит следующие поля:
id- (необязательный) уникальный идентификатор, сохраняемый в вставленном токене. Если не задан, RichText генерирует идентификатор автоматическиlabel- (необязательный) текст, отображаемый в выпадающем списке и вставляемый в документ. Обязателен только для рендеринга по умолчанию; при использовании пользовательскогоtriggerTemplateможно рендерить элементы из других полей (например,template(({ data }) => data.id)) и не указыватьlabelurl- (необязательный) URL, связанный с элементом. RichText сохраняет URL в атрибутеhrefвставленного токена.Ctrl+Clickпо токену открывает ссылку
Элемент также может содержать любое количество пользовательских полей помимо id, label и url (например, code для эмодзи, или image и name для аватара). Эти дополнительные поля передаются в калбэк triggerTemplate и в калбэк action.
Отрисованный токен
Когда пользователь выбирает элемент в выпадающем списке, RichText вставляет в документ нередактируемый элемент-токен:
<a data-token="@" data-token-id="alice" href="mailto:alice@example.com">@Alice</a>
@(вdata-token="@") -triggerэлементаalice(вdata-token-id="alice") -idэлементаmailto:alice@example.com(вhref="mailto:alice@example.com") -urlэлемента@Alice- сочетаниеtriggerиlabel; приshowTrigger: falseэто будет простоAlice
Используйте атрибуты data-token и data-token-id для стилизации токенов через CSS, например, чтобы выделить все упоминания пользователя:
.wx-editor-content a[data-token="@"][data-token-id="alice"] {
background: #fb8500;
color: #fff;
}
Пользовательское действие
По умолчанию, когда пользователь выбирает элемент, RichText вставляет его в документ как токен. Задайте параметр action, чтобы выполнить собственный код вместо этого: RichText удаляет введённую строку триггера (символ триггера и строку запроса) и вызывает калбэк action(item) с выбранным элементом. Токен не вставляется, поэтому вы сами решаете, что добавить в документ (или выполняете собственный код). Параметр action имеет приоритет над showTrigger. Если задан action, showTrigger игнорируется.
Добавление эмодзи
Распространённый сценарий использования — вставка эмодзи по триггеру :, где каждый элемент содержит пользовательское поле code. Совместите action с triggerTemplate, чтобы в выпадающем списке отображался сам эмодзи, а не только его label:
const { template, Richtext } = richtext;
const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: emoji, // [{ id: "apple", label: "apple", code: "1F34E" }, ...]
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// отображение самого эмодзи (а не только его названия) в выпадающем списке
triggerTemplate: template(({ data }) => `${emojiFromCode(data.code)} ${data.label}`)
});
function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}
Группировка эмодзи по категориям
Когда параметр data является функцией, вы не ограничены встроенным сопоставлением по полю label. Вы можете реализовать собственную фильтрацию и сохранить заголовки категорий в выпадающем списке. Добавьте элементы-заголовки, содержащие поле label, но не содержащие code. Функция data сначала находит эмодзи, соответствующие запросу, затем возвращает их вместе с заголовками категорий, в которых ещё есть совпадения:
const { template, Richtext } = richtext;
// элементы-заголовки не содержат поля `code`; элементы-эмодзи его содержат
const emoji = [
{ id: "$smileys", label: "Smileys", category: 1 }, // категория
{ id: "grinning", label: "grinning", code: "1F600", category: 1 },
{ id: "smile", label: "smile", code: "1F604", category: 1 },
{ id: "$animals", label: "Animals", category: 2 }, // категория
{ id: "dog", label: "dog", code: "1F436", category: 2 },
{ id: "cat", label: "cat", code: "1F431", category: 2 }
];
const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: query => {
const matched = emoji.filter(item =>
item.code &&
item.label.toLowerCase().startsWith(query.toLowerCase().trim())
);
const categories = new Set(matched.map(item => item.category));
// сохраняем подходящие эмодзи вместе с заголовками категорий, в которых остались совпадения
return emoji.filter(item =>
item.code ? matched.includes(item) : categories.has(item.category)
);
},
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// отображение строк с эмодзи обычным шрифтом, а заголовков категорий — жирным
triggerTemplate: template(({ data }) =>
data.code ? `${emojiFromCode(data.code)} ${data.label}` : `<b>${data.label}</b>`
)
});
function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}
// заголовки не имеют поля `code` — игнорируем их выбор, чтобы они никогда не вставлялись
editor.api.intercept("insert-token", ({ data }) => !!data.code);
Добавление командного меню в стиле slash
Вы можете использовать action для создания командного меню в стиле slash (как / в Notion или Slack). Сохраните имя команды в поле id каждого элемента, её параметры — в пользовательском поле config, и позвольте калбэку выполнить команду через api.exec:
// каждый элемент хранит название действия api.exec в `id`, а его параметры — в `config`
const commands = [
{ id: "set-text-style", label: "Heading 1", config: { tag: "h1" } },
{ id: "insert-list", label: "Bulleted list", config: { type: "bulleted" } },
{ id: "insert-line", label: "Divider" } // конфигурация отсутствует → применяется `|| {}`
];
const editor = new richtext.Richtext("#root", {
triggers: [
{
trigger: "/",
data: commands,
action: item => editor.api.exec(item.id, item.config || {})
}
]
});
Пример
В следующем примере настраиваются два триггера: @ для упоминаний (каждый элемент содержит url, который становится атрибутом href токена) и # для тегов (только label):
new richtext.Richtext("#root", {
triggers: [
{
trigger: "@",
data: [
{ id: "alice", label: "Alice", url: "mailto:alice@example.com" },
{ id: "bob", label: "Bob", url: "mailto:bob@example.com" }
]
},
{
trigger: "#",
data: [
{ id: "css", label: "CSS" },
{ id: "html", label: "HTML" }
]
}
]
});
История изменений: Свойство добавлено в v2.1
Связанные примеры:
- RichText. Упоминания, теги и асинхронный поиск
- RichText. Пользовательский шаблон выпадающего списка для каждого триггера
- RichText. Автодополнение эмодзи
- RichText. Slash-команды
- RichText. Поиск и выделение упоминаний
- RichText. Выделение всех упоминаний
Связанные статьи: Упоминания и теги