Как добавить пользовательский HTML после "post_1"

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

Темы Discourse позволяют декорировать виджеты, так что вы можете использовать эту возможность.

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

Начните с добавления разметки ко всем постам. Что-то вроде этого:

<script type="text/discourse-plugin" version="0.8">
api.decorateWidget("post:after", helper => {
  return helper.h("div", "test text");
});
</script>

в секцию заголовка вашей темы. Этого должно быть достаточно, чтобы добавить «test text» под каждым постом.

Давайте разберем приведенный выше скрипт.

api.decorateWidget("post:after", helper => {

вызывает метод decorateWidget, целевой виджет — post, а целевое расположение — after. То есть после виджета поста.

helper — это встроенный помощник, который дает вам доступ к множеству вещей, о которых я расскажу позже.

return helper.h("div", "test text")

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

Объяснение того, что такое виртуальные узлы или как работает синтаксис, выходит за рамки этой темы, поэтому я пропущу это. Я добавил заметку о написании инструкции по созданию виртуальных узлов, но пока вот несколько примеров:

helper.h("div", "test text")

рендерится как

<div>test text</div>

а

return helper.h("div#custom-ad", [
  helper.h(
    "a.custom-ad-link",
    { href: "example.com" },
    helper.h("img", { src: "https://picsum.photos/id/74/750/90" })
  )
]);

будет рендериться как

<div id="custom-ad">
  <a href="example.com" class="custom-ad-link">
    <img src="https://picsum.photos/id/74/750/90">
  </a>
</div>

Кратко: узел выглядит так:

helper.h(selector, {properties}, children)

Я объясню это подробнее в инструкции по виртуальным узлам.

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

<script type="text/discourse-plugin" version="0.8">
  api.decorateWidget("post:after", helper => {
    return helper.h("div#custom-ad", [
      helper.h(
        "a.custom-ad-link",
        { href: "example.com" },
        helper.h("img", { src: "https://picsum.photos/id/74/750/90" })
      )
    ]);
  });
</script>

Однако здесь все еще есть проблема: реклама будет вставлена под каждым постом в потоке, что не идеально.

Вот где пригодится helper: атрибуты поста передаются в helper, так что вы можете быстро выполнить

console.log(helper)

Вы увидите все доступные атрибуты поста, с которыми можно работать.

Это лишь примеры, там есть еще много чего.

К счастью, здесь доступен атрибут firstPost, так что вам остается только добавить условную проверку, которая будет рендерить разметку рекламы только если это действительно первый пост, иначе ничего не произойдет. Что-то вроде этого:

<script type="text/discourse-plugin" version="0.8">
api.decorateWidget("post:after", helper => {
  const firstPost = helper.attrs.firstPost;
  const h = helper.h;
  if (firstPost) {
    return h("div#custom-ad", [
      h(
        "a.custom-ad-link",
        { href: "example.com" },
        h("img", { src: "https://picsum.photos/id/74/750/90" })
      )
    ]);
  }
});
</script>

и это вставит вашу рекламу только после первого поста. Еще один момент: нужно добавить высоту к изображению, иначе при загрузке возникнет дрожание. Как я кратко упоминал выше, атрибут height для тега изображения является свойством, поэтому его нужно добавить рядом с src.

С учетом всего сказанного, вот финальный код для того, чего вы пытаетесь достичь:

<script type="text/discourse-plugin" version="0.8">
api.decorateWidget("post:after", helper => {
  const firstPost = helper.attrs.firstPost;
  const h = helper.h;
  if (firstPost) {
    return h("div#custom-ad", [
      h(
        "a.custom-ad-link",
        { href: "example.com" },
        h("img", { src: "https://picsum.photos/id/74/750/90", height: "90" })
      )
    ]);
  }
});
</script>

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

<script type="text/discourse-plugin" version="0.8">
  const RawHtml = require("discourse/widgets/raw-html").default;
  api.decorateWidget("post:after", helper => {
    const firstPost = helper.attrs.firstPost;
    if (firstPost) {
      return [
        new RawHtml({
          html: `<div id="custom-ad">
                   <a href="example.com">
                     <img src="https://picsum.photos/id/74/750/90" height="90">
                   </a>
                 </div>`
        })
      ];
    }
  });
</script>

но, опять же, это не рекомендуется.