Пересмотр виджетов в заголовке при смене маршрута без ошибок

Я пытаюсь переопределить этот шаблон виджета:

      api.reopenWidget("header-contents", {
        template: hbs`
          {{#if this.site.desktopView}}
            {{#if attrs.sidebarEnabled}}
              {{sidebar-toggle attrs=attrs}}
            {{/if}}
          {{/if}}

          {{home-logo attrs=attrs}}

          {{#if attrs.topic}}
            {{header-topic-info attrs=attrs}}
          {{else if this.siteSettings.bootstrap_mode_enabled}}
            {{#if transformed.showBootstrapMode}}
              {{header-bootstrap-mode attrs=attrs}}
            {{/if}}
          {{/if}}

          <div class="panel clearfix" role="navigation">{{yield}}</div>
        `,
      });

Несмотря на то, что шаблон в данный момент идентичен оригиналу по ссылке discourse/app/assets/javascripts/discourse/app/widgets/header-contents.js at 4aa81e709ea49e30383a3a3acd33dfedaebfc240 · discourse/discourse · GitHub

Это вызывает ошибку:

Это неожиданно, особенно учитывая, что я на самом деле ничего не “меняю” (пока)?

Я могу воспроизвести эту проблему, даже если это единственное изменение.

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

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

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

В любом случае, это ведет себя не так, как я ожидаю?

Мы не хотим тратить здесь много времени — виджеты скоро исчезнут. Какую именно кастомизацию вы пытаетесь внести? Можем ли мы помочь, добавив выход для плагина в нужном месте (сейчас у нас есть возможность добавлять обычные выходы для плагинов прямо внутри кода виджета).

Можете ли вы показать больше содержимого вашего файла (например, откуда импортируется hbs?)

Также, какая версия Discourse используется? В site-header.js:337 в настоящее время нет ссылки на переменную ‘header’

Понятно.

import { hbs } from "ember-cli-htmlbars";

По сути, я пытаюсь менять логотип в зависимости от маршрута. На практике я делаю это, прикрепляя изображение к домашнему логотипу на некоторых маршрутах и накладывая основной логотип. Я хочу, чтобы эта логика переоценивалась при переходе между маршрутами. Сейчас это, похоже, работает при входе в маршруты тем и выходе из них, вероятно, потому что виджет header-contents, к которому всё прикреплено, содержит логику оценки attrs.topic, которая, очевидно, меняется при этом.

Мой category-logo-widget прикрепляется следующим образом:

      api.decorateWidget("home-logo:after", (helper) => {
        const currentPath = helper.register
          .lookup("service:router")
          .get("_router.currentPath");

        if (
          helper.widget.currentUser &&
          !helper.widget.site.mobileView &&
          currentPath.indexOf("discovery") === -1
        ) {
          return helper.attach("category-logo-widget");
        } 
      });

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

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

Я вижу этот коммит, мне нужно обновить мой экземпляр разработки … PERF: Memoize element references for `dockCheck` (#21079) · discourse/discourse@db16700 · GitHub

В любом случае я отменю изменения, спасибо за ваше время!

Скорее всего, проблема именно в этом. Виджеты «templates» — это особенность Discourse, и они компилируются совершенно иначе, чем шаблоны Ember. Вам нужно импортировать hbs следующим образом:

Похоже, у нас есть событие приложения site-header:force-refresh, которое можно запускать в ответ на какое-либо другое событие приложения или событие роутера Ember:

(пример запуска здесь)

Отлично, спасибо, Дэвид! Исправлю устаревшую установку и также попробую ваши рекомендации. Несколько вопросов скопилось, спасибо, что помогли разобраться!

Так что, вероятно, это немного излишне, но я в итоге использовал вашу рекомендацию с:

      api.onPageChange(url =>  {
        const applicationController = container.lookup(
          "controller:application"
        );
        applicationController.appEvents.trigger(
          "site-header:force-refresh"
        );
      });

Это сработало отлично, хотя и не совсем идеально синхронизируется с переходом маршрута, но это не проблема.

Спасибо ещё раз!

Кстати, в качестве примечания: хотя API виджетов очень специфичен и местами неудобен (особенно то, что касается hyperscript), должен признать, что он чрезвычайно мощен: позволяет добавлять новое поведение к существующим виджетам, не переписывая при этом множество кода.

Например, я часто использую такой паттерн:

api.reopenWidget('discourse-awesome-widget', {

  html(attrs, state) {
    let contents = this._super(...arguments);

    contents.unshift(h("div.my-cool-new-thing", "крутая новая вещь"));

    return contents;
  }
});

this._super может содержать очень много кода!!!

И всё может стать ещё умнее, поэтому я действительно начал это ценить.

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

Основное решение здесь — это точки подключения плагинов. Как всегда, если вам нужен такой, которого ещё нет, не стесняйтесь создать PR для ядра :rocket: