在主题中嵌入文本内的窗口小部件

Discourse 是一个单页应用程序。您遇到的问题是因为您使用的脚本未意识到这一点。当您访问 Discourse 的主页或其他任何页面时,会得到类似以下的内容:

<html>
  <head>
    head 内容,包括您的脚本
  </head>
  <body>
    <section id="main">
      页面内容
    </section>
  </body>
</html>

当您导航到另一个页面时,唯一重新加载的内容是以下部分内部的内容:

<section id="main">

因此,DOM 已更改,您的自定义脚本不会再次触发。如果您尝试直接访问主题页面,您会发现它可以正常加载。

那么,现在的问题是如何使其与 Discourse 协同工作。

plugin-api 提供了一个方法,可用于“装饰”帖子。

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

您可以使用它在帖子渲染时触发第三方脚本。

以下是您需要的代码。将其添加到您主题的 common > header 选项卡中。

<script type="text/discourse-plugin" version="0.8">
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

const loadScript = require("discourse/lib/load-script").default;
const { iconHTML } = require("discourse-common/lib/icon-library");

const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
  class: "woxo-preview-icon"
});

const previewMarkup = () => {
  const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
  return markup;
};

// 创建帖子装饰器
api.decorateCookedElement(
  post => {
    const woxoWidgets = post.querySelectorAll("div[data-mc-src]");

    if (woxoWidgets.length) {
      woxoWidgets.forEach(woxoWidget => {
        if (post.classList.contains("d-editor-preview")) {
          woxoWidget.innerHTML = previewMarkup();
          return;
        }

        loadScript(WOXO_SCRIPT_SRC).then(() => {
          const script = document.head.querySelector(
            `script[src*="cdn2.woxo.tech"]`
          );
          script.dataset.usrc = "";
          window.MC.Loader.init();
        });
      });
    }
  },
  { id: "render-woxo-widgets" }
);
</script>

接下来,您需要为 CSP 添加几个域名。将这些添加到您的

content_security_policy_script_src

站点设置中:

https://*.woxo.tech/
https://us-central1-core-period-259421.cloudfunctions.net/availableComponentTracks

最后,您需要为静态编辑器预览添加一些 CSS。

这应放在您主题的 common > CSS 选项卡中。

.woxo-preview {
  height: 400px;
  width: 100%;
  background: var(--primary-low);
  display: flex;
  align-items: center;
  justify-content: center;
  .woxo-preview-icon {
    font-size: var(--font-up-4);
    color: var(--primary-high);
  }
}

然后,您只需在任意帖子中添加以下内容:

<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>

小部件将渲染并完全正常运行。

如果您查看 JavaScript 代码,会注意到其顶部有两个选项。

const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

WOXO_SCRIPT_SRC 更改为 woxo 提供的 src 地址。对于您创建的所有嵌入内容,该地址应相同。

PREVIEW_ICON 更改为您希望在编辑器预览中使用的图标名称。在编辑器中运行此代码开销较大,因此编辑器会显示一个静态预览,如下所示:

您选择的图标将显示在中间。

如果您想跟随了解代码的具体执行过程,以下是带注释的代码副本:

带注释的代码
<script type="text/discourse-plugin" version="0.8">
// 选项
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

// 我们使用 Discourse 的 Load script 库来确保脚本正确加载。
// 不用担心,它足够智能,如果脚本已加载则不会重复加载。
const loadScript = require("discourse/lib/load-script").default;

// 我们加载 Discourse 的 iconHTML 函数以获取我们要在静态编辑器预览中使用的图标 SVG。
const { iconHTML } = require("discourse-common/lib/icon-library");

// 设置编辑器预览图标
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
  class: "woxo-preview-icon"
});

// 创建编辑器预览标记的辅助函数
const previewMarkup = () => {
  const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;

  return markup;
};

// 创建帖子装饰器
api.decorateCookedElement(
  post => {
    // 此帖子是否包含 woxo 小部件?
    const woxoWidgets = post.querySelectorAll("div[data-mc-src]");

    // 是的,那么让我们做一些处理。
    if (woxoWidgets.length) {
      // 遍历每个 woxo 小部件
      woxoWidgets.forEach(woxoWidget => {
        // 如果是编辑器中的小部件,将其替换为静态预览并提前退出
        if (post.classList.contains("d-editor-preview")) {
          woxoWidget.innerHTML = previewMarkup();
          return;
        }

        // 如果不在编辑器中,则加载 woxo 脚本。
        loadScript(WOXO_SCRIPT_SRC).then(() => {
          // woxo 脚本非常特殊。如果脚本标签没有空的 data-usrc 属性,它将无法工作。因此,让我们添加它。
          const script = document.head.querySelector(
            `script[src*="cdn2.woxo.tech"]`
          );
          script.dataset.usrc = "";

          // 一切就绪,让我们调用 woxo 脚本中的 init 方法。
          window.MC.Loader.init();
        });
      });
    }
  },
  // 为装饰器添加 id 以避免内存泄漏
  { id: "render-woxo-widgets" }
);

</script>
3 个赞