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

Всем привет,

Мы создали виджет topic-timeline-bookmark, который отображает кнопку закладки на уровне темы после виджета topic-timeline.

Теперь, при нажатии на кнопку закладки topic-timeline, открывается модальное окно для настройки закладки. После сохранения закладки обновляются кнопки закладок под кнопками first-post-menu и topic-footer-button, но сам виджет не обновляется до тех пор, пока не будет обновлён виджет topic-timeline (то есть до прокрутки), и наоборот.

first-post-menu

image


topic-footer-button

image

Я обнаружил, что при установке/снятии закладки обновляется виджет post-stream, поэтому кнопки закладок в post-menu и topic-footer-button работают синхронно.

Так как же теперь обновлять мой виджет topic-timeline-bookmark при установке/снятии закладки или при обновлении виджета post-stream? Ниже мой код:

<script type="text/discourse-plugin" version="0.8">
  const { h } = require('virtual-dom');
  const { getOwner } = require("discourse-common/lib/get-owner");
  const topicController = getOwner(this).lookup("controller:topic");

  api.createWidget("topic-timeline-bookmark", {  
      tagName: 'div.discourse-bookmark-button-wrapper',
      buildKey: () => `topic-timeline-bookmark`,
      toggleBookmark() {
        topicController.send('toggleBookmark');
      },
      html(attrs, state) { 
        let contents = [];
        const user = api.getCurrentUser();
        if (user) {
            let tooltip = 'bookmarked.help.bookmark';
            let label = 'bookmarked.title';
            let buttonClass = 'btn btn-default bookmark';
            let icon = "bookmark";  
            let bookmarkedPosts = topicController.model.bookmarked_posts;
            let bookmarkCount = 0;

            if(bookmarkedPosts && bookmarkedPosts.length > 0){
              bookmarkCount =  bookmarkedPosts.length;
              
              //Иконка
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
              else
                icon = "bookmark";

              //Метка
              if (bookmarkCount === 0)               
                  label = "bookmarked.title";          
              else if (bookmarkCount === 1)
                  label = "bookmarked.edit_bookmark"; 
              else 
                  label = "bookmarked.clear_bookmarks";

              //Подсказка
              if (bookmarkedPosts.length === 1)
                  tooltip = 'bookmarked.help.edit_bookmark';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = 'bookmarked.help.unbookmark_with_reminder';
              
              //Добавляем CSS-класс, если закладка установлена
              if (bookmarkCount > 0) { buttonClass += ' bookmarked' }
            }
    
            contents.push(
            this.attach('button', {
              action: 'toggleBookmark',
              title: tooltip,
              label: label,
              icon: icon,
              className: buttonClass
            })
          );
        }
        return contents;
      }, 
    });
 
  api.decorateWidget('topic-timeline:after', function(helper) {
    return helper.attach('topic-timeline-bookmark');
  });
</script>

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

Привет,

Я не пробовал это локально, но, возможно, сработает следующее:

В вашем основном скрипте добавьте этот вызов API:

api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');

В коде виджета объявите эту функцию:

api.createWidget("topic-timeline-bookmark", {  
  // код опущен

  // возможно, можно назвать это schedule-rerender
  // напрямую в вызове API вместо force-refresh
  // и избежать необходимости в этой функции
  forceRefresh() {
    this.scheduleRerender();
  }
});

Думаю, это должно сработать. Если нет — дайте знать, я попробую собрать рабочий пример локально.

Спасибо за ответ, @joffreyjaffeux.

Мы попробовали предложенный вами код, но он не работает.

  1. Добавили следующий вызов API:
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    А затем добавили метод forceRefresh() в виджет “topic-timeline-bookmark”.
    Но это не помогло.

  2. Я также попытался переименовать второй параметр метода dispatchWidgetAppEvent в “schedule-rerender” и удалил функцию forceRefresh из виджета. Это тоже не сработало.

Я изучил реализацию метода api.dispatchWidgetAppEvent: он принимает три аргумента, где второй — это widgetKey. Мне кажется, это должно быть значение, возвращаемое функцией buildKey() виджета.
Третий аргумент — это appEvent, который преобразуется в camelCase и используется как имя метода.

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L1448

Не упустили ли мы что-то?

Я попробую локально, вероятно, я допустил ошибку.

@saurabhmasc Я добился работы локально, однако пришлось исправить ошибку в ядре и добавить новую функцию в ядро. Я обновлю тему, когда всё это будет слито.

Спасибо, @j.jaffeux.

Привет @j.jaffeux,

Есть ли какая-то идея, когда эти изменения будут слиты?

Привет, да, я только что слил его (так что вам нужно сначала развернуть его): DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

Также вот пример компонента, который я сделал для этого:

Дайте знать, если у вас возникнут вопросы.

Привет, @j.jaffeux,

  1. Раньше мы заметили, что при добавлении закладки из кнопок в подвале темы первый пост также помечался как закладочный, но теперь первый пост не помечается. Это правильно?

  2. Мы протестировали ваш компонент: все случаи работают корректно, кроме функции «Очистить закладки», которая не синхронизируется.
    Чтобы это исправить, мы добавили следующие строки кода, и теперь функция «Очистить закладки» также работает корректно.

  api.dispatchWidgetAppEvent(
    "topic-timeline",
    "topic-timeline-bookmark",
    "post-stream:refresh"
  );

Спасибо.

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

После различных тестов я считаю, что это ожидаемое поведение (и не связано с компонентом).

Спасибо, @j.jaffeux, за ваш отзыв.

Мы создадим новый тикет с запросом на внедрение этих основных изменений в наши среды Staging и Production. Это позволит нам протестировать их в среде Staging.