A tour of how the Widget (Virtual DOM) code in Discourse works

Right, after a lot of headaches I’ve got it working - thanks for the help! :tada:

The two other problems I hit which could possibly do with some re-engineering in the widget code:

  • When setting dirtyKeys, it only re-renders the first widget with that buildKey. I’ve got around that by adding the post-id to the post-avatar’s buildKey so that every buildKey is unique
  • Setting the dirtyKey doesn’t work if the widget you want to re-render is inside another widget. In my case the post-avatar is inside a post. I think this is because of the shadowTree stuff.
    It would be really nice if the widget code could work out that the widget is deep in the tree and re-render its parents. I’ve got around this by setting the post widget as dirty as well.

That’s because keys are supposed to be unique! So adding the post id to the avatar is correct in this case. I might want to raise an error in development mode if two elements use the same keys. If you want to commit the post avatar key to master that would be fine.

That’s exactly what it is. By default I think a widget is supposed to re-render its parents, but the shadowTree is a performance optimization that avoids too much re-rendering and requires you to be more explicit.

Just in case anyone is trying to track down how widgets can use handlebars templates, see the commit message here (can’t find it documented anywhere on meta):

https://github.com/discourse/discourse/commit/dffb1fc4ee8a4d58f48145decb1590a304e8cf7d

كيفية إنشاء شريط تنقل؟ باستخدام أداة.

مثل هذا

image

الكود التالي في التعليمات لم يعد يعمل. العرض يعمل ولكن الحالة لا تزيد عند النقر:

<script type="text/javascript">
        const { createWidget } = require('discourse/widgets/widget');

        createWidget('increment-button', {
            tagName: 'button',

            defaultState() {
                return { clicks: 0 };
            },

            html(attrs, state) {
                return `Click me! ${state.clicks} clicks`;
            },

            click() {
                this.state.clicks++;
            }
        });
</script>


<script type='text/x-handlebars' data-template-name='/connectors/above-footer/increment-button'>
    {{mount-widget widget="increment-button" }}
</script>

غريب، بالنسبة لي، عندما أجرب هذا المكون، لا يتم عرضه على الإطلاق لأنه يفتقر إلى key. لقد قمت بتحديث الوثائق أعلاه لإضافة طريقة buildKey وهي تعمل معي. جرب ذلك.

شكرًا لك @eviltrout، تمكنت من جعل ذلك يعمل! نقدر ذلك كثيرًا

كيف يمكنني عرض HTML قادم من وسيط داخل الـ widget؟ حاليًا، يتم تحويل HTML إلى كود نصي وعرضه كما هو.

أيضًا، المثال التالي لا يعمل:

يبدو أن متغير المستخدم (user) فارغ (null). هل يجب عليّ القيام بشيء ما لنقل متغير المستخدم إلى ملف HBS من حيث يتم تثبيت الـ widget؟

وجدت إجابة لهذا السؤال:

الإجابة:

import { createWidget } from 'discourse/widgets/widget';
import RawHtml from "discourse/widgets/raw-html";

createWidget('display-name', {
  tagName: 'div.name',

  html() {
    return new RawHtml({ html: `<div>${this.siteSettings.user_rank_alert_message}</div>` });
  }
});

لكنني لا أعرف بعد كيفية الحصول على بيانات المستخدم في ملف connector hbs حيث لا يتم تمرير البيانات من outlet.

تفقد الأقواس الثلاثية يا صديقي :smiley:

ليس بهذه السرعة :wink: :warning: :

بدلاً من الأقواس المزدوجة الثلاثية، يمكنك استخدام المساعد التالي:

{{html-safe result}}

مرحبًا @eviltrout،

لاحظت في المنشور الأصلي (OP) لهذا الموضوع أنك تقول:

لكن في الأسفل من هذا الموضوع، تذكرت:

هل تود تعديل المنشور الأصلي؟

شكرًا لك، لقد قمت بتعديل ذلك.

@eviltrout ألا ينبغي أن يكون هذا action="deleteThing"؟

يعتمد الأمر على الويدجت الخاص بك. في مثال @eviltrout، يتوقع my-widget أن يتم تمرير إجراء له باسم “deleteThing”. ستستخدم الويدجت المختلفة أسماء مختلفة لإجراءاتها (بل ومن الممكن بالفعل أن تسمي إجراءها “action”)