Мне нужно изменить отдельные вхождения иконок на всём сайте. Я не хочу использовать replaceIcon() и заменять все экземпляры этой иконки. Судя по прошлому опыту, это было возможно для конкретных областей сайта, или, по крайней мере, так я это понимаю, но не для всего сайта в целом.
Например, я хочу изменить ОДНУ иконку шестерёнки в поиске, чтобы она лучше отражала то, что произойдёт при клике пользователя. Я не хочу менять все иконки шестерёнок.
Какая конкретно это иконка (где она отображается)? Если есть разумные основания полагать, что это может быть полезно другим, мы можем создать для неё алиас, чтобы разрешить её отдельную замену.
По умолчанию здесь используется иконка “sliders” (и это единственное её использование в Discourse по умолчанию), поэтому в данном случае безопасно использовать replaceIcon().
Поскольку у нас нет API для замены отдельных иконок, лучший способ поддержки этой функции сегодня — это рассмотрение запросов на добавление новых алиасов, объединяющих схожие случаи использования.
Например, мы используем d-liked как алиас для heart, чтобы replaceIcon() можно было применить к d-liked и изменить иконку в контексте лайков, вместо того чтобы заменять каждое вхождение иконки сердца во всём приложении.
Будет здорово иметь возможность заменять любое отдельное вхождение, так как это не редкая ситуация в темах — надеемся, что однажды у нас появится для этого API.
Хорошо, теперь, кажется, понял, каков вердикт по этому вопросу. Грустно осознавать, что это станет доступно только после обновления API, поэтому пока мне придётся использовать тот метод, который я применял ранее.
Да, ты прав! Это не слишком стабильно. Может быть, с помощью requestAnimationFrame или MutationObserver это станет стабильнее? Но да, лучшим решением было бы наличие отдельного API, как ты и упоминал.
Спасибо, что обратили на это внимание — вы абсолютно правы. Использование только api.onPageChange может быть ненадёжным, так как оно срабатывает при смене маршрута, а не после рендеринга DOM. Это создаёт риск состояния гонки, когда кнопка #create-topic может ещё не существовать в момент, когда скрипт пытается получить к ней доступ.
api.onPageChange(() => {
const targetSelector = "#create-topic";
const tryEnhanceButton = () => {
const button = document.querySelector(targetSelector);
if (button) {
// Отключаем наблюдатель после нахождения элемента
observer.disconnect();
// Временно скрываем кнопку, пока мы заменяем иконку
button.style.display = "none";
// Удаляем старую иконку, если она есть
const oldIcon = button.querySelector("svg");
if (oldIcon) oldIcon.remove();
// Создаём и вставляем новую SVG-иконку Font Awesome
const newIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
newIcon.setAttribute("class", "fa d-icon d-icon-feather-pointed svg-icon svg-string");
newIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
newIcon.innerHTML = '<use href="#feather-pointed"></use>';
button.insertBefore(newIcon, button.firstChild);
// Снова показываем кнопку
button.style.display = "block";
}
};
// Наблюдаем за изменениями в DOM и пытаемся улучшить кнопку, когда она появится
const observer = new MutationObserver(() => tryEnhanceButton());
observer.observe(document.body, { childList: true, subtree: true });
// Также пробуем сразу, на случай если элемент уже существует
tryEnhanceButton();
});
@Don Я добавил MutationObserver, чтобы гарантировать, что скрипт выполнится только после того, как целевой элемент действительно появится в DOM. После выполнения своей задачи наблюдатель отключается, чтобы избежать лишних накладных расходов. Также сохраняется попытка немедленной проверки на случай, если элемент уже существует.
Мне не удалось получить нужную SVG-иконку из системы иконок Discourse, хотя я зарегистрировал её в подмножестве административных SVG-иконок, поскольку, похоже, она есть в Font Awesome, но отсутствует в Discourse.