別のウィジェットの更新時にウィジェットをリロード/リフレッシュする

皆様、こんにちは。

「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 のブックマークボタンは同期して動作します。

そこで、ブックマークが設定/解除されるたびに、あるいは post-stream ウィジェットがリフレッシュされるたびに、私の「topic-timeline-bookmark」ウィジェットをどのようにリフレッシュすればよいでしょうか?以下が私のコードです。

<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;
              
              //Icon
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
              else
                icon = "bookmark";

              //Label
              if (bookmarkCount === 0)               
                  label = "bookmarked.title";          
              else if (bookmarkCount === 1)
                  label = "bookmarked.edit_bookmark"; 
              else 
                  label = "bookmarked.clear_bookmarks";

              //Tooltip
              if (bookmarkedPosts.length === 1)
                  tooltip = 'bookmarked.help.edit_bookmark';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = 'bookmarked.help.unbookmark_with_reminder';
              
              //Append CSS class if bookmark is set
              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>
「いいね!」 2

ご連絡いただきありがとうございます。当社の開発者の一人が本件を確認し、役立つ情報をお知らせいたします。

「いいね!」 3

こんにちは、

ローカルでは試していませんが、以下の方法が機能する可能性があります。

メインスクリプトに、この API 呼び出しを追加してください。

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

ウィジェットコードでは、この関数を宣言してください。

api.createWidget("topic-timeline-bookmark", {  
  // コードは省略

  // API 呼び出しで 'force-refresh' の代わりに
  // 'schedule-rerender' と直接名付けることで、
  // この関数を不要にできるかもしれません
  forceRefresh() {
    this.scheduleRerender();
  }
});

これで動作するはずです。もし動作しない場合はお知らせください。ローカルで動作するサンプルを作成して確認します。

「いいね!」 3

@joffreyjaffeux さん、返信ありがとうございます。

ご提案いただいたコードを試してみましたが、動作しません。

  1. 以下の API 呼び出しを追加しました。
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    その後、「topic-timeline-bookmark」ウィジェットに forceRefresh() メソッドを追加しましたが、動作しません。

  2. また、dispatchWidgetAppEvent メソッドの第 2 引数を「schedule-rerender」に改名し、ウィジェットから forceRefresh 関数を削除しました。これも動作しません。

api.dispatchWidgetAppEvent メソッドの実装を確認したところ、3 つの引数を受け取ります。第 2 引数は widgetKey で、これはウィジェットの buildKey() メソッドが返す値であるべきだと考えられます。
第 3 引数は appEvent で、これがキャメルケースに変換され、メソッド名として使用されます。

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

何か見落としているのでしょうか?

ローカルで試してみます。おそらく私がミスをしたのでしょう。

「いいね!」 1

@saurabhmasc ローカル環境では動作するようになりましたが、コアのバグ修正と新しい機能の追加が必要でした。これらがすべてマージされ次第、トピックを更新します。

「いいね!」 3

@j.jaffeux さん、ありがとうございます。

@j.jaffeux さん、こんにちは。

これらの変更がマージされるのはいつ頃になりそうでしょうか。

「いいね!」 1

こんにちは、はい、すでにマージしました(まずデプロイする必要があります):DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

また、これ用に作成したコンポーネントの例はこちらです:

ご質問がございましたら、お知らせください。

「いいね!」 3

@j.jaffeux さん、こんにちは。

  1. 以前はトピックのフッターボタンからブックマークすると、最初の投稿もブックマーク済みとしてマークされていましたが、現在は最初の投稿がブックマークされなくなっています。これは正しい動作でしょうか?

  2. 提供されたコンポーネントは全ケースで正常に動作していることを確認しましたが、「ブックマークをクリア」機能のみが同期して動作していませんでした。
    これを修正するため、以下のコード行を追加したところ、「ブックマークをクリア」機能も正常に動作するようになりました。

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

よろしくお願いいたします。

「いいね!」 1

最初の点を確認します。2点目については、はい、ケースを見落としていた可能性があります。ブックマークの主要な作者が現在不在のため、いくつか変更したいと考えていますが、彼が戻ってくるのを待つ必要があります。あなたの修正で問題ないと思います。

「いいね!」 3

いくつかのテストを行った結果、これは想定通りの動作であり(コンポーネントとは無関係です)。

「いいね!」 1

@j.jaffeux さん、フィードバックをありがとうございます。

これらのコア変更をステージング環境と本番環境に適用するよう求める新しいチケットを作成します。これにより、ステージング環境でテストを行うことができます。

「いいね!」 2