可插入的、集中维护的文本/Markdown 片段

I was wondering if there was any way I could define a string of text in a single place and insert it within posts with a single, short reference.

It’s a bit like the out of the box Admin -> Customize -> Text Content, but for my own custom variables that can be inserted into posts.

My use case was adding a disclaimer for my affiliate links. As the number of affiliate links grew across many posts and Topics I noted that my disclaimers were proliferating along with them. I occasionally like to make improvements to the disclaimers and this gets more onerous as the number grows.

I’m also considering making my affiliate links more generic so I have one centrally managed link for each product link, for example, which appears multiple times. If that product link changes, I only have to change it in one place.

Obviously I might be able to do some kind of rails find & replace, but that’s not as clean/safe nor ‘online’.

So I wanted a place to define & maintain a text string in a single place and have changes immediately reflected everywhere that is used on next page view.

Read on for @Johani’s solution!:

3 个赞

One possible option is to use a theme component.

This goes in header.html

<script type="text/discourse-plugin" version="0.8">
var disclaimer = settings.Disclaimer_text,
  disclaimer_selector = 'div[data-theme="disclaimer"]';

$.fn.disclaimer = function() {
  if (!this.length) {
    return;
  } else {
    this.each(function() {
      $(this).html(disclaimer);
    });
    return this;
  }
};

api.decorateCooked($elem => $elem.children(disclaimer_selector).disclaimer());

// create composer button
let currentLocale = I18n.currentLocale();

I18n.translations[currentLocale].js.disclaimer_button = "Add disclaimer";
I18n.translations[currentLocale].js.composer.disclaimer_prompt = ""; // leave empty

api.onToolbarCreate(function(toolbar) {
  toolbar.addButton({
    trimLeading: true,
    id: "disclaimer-button",
    group: "insertions",
    icon: "exclamation-circle", // change icon
    title: "disclaimer_button",
    perform: function(e) {
      return e.applySurround(
        '<div data-theme="disclaimer">',
        "</div>",
        "disclaimer_prompt"
      );
    }
  });
});
</script>

and this goes into your component’s settings.yml file

Disclaimer_text:
  default: "Lorem ipsum dolor sit amet, ei purto complectitur has, per at quas senserit. Et malis libris eos, vix id pericula dissentiet, aliquid apeirian pro eu. Sed ex viderer inciderint, vitae officiis dissentiet eos no. Omnes percipit singulis in has, ne nam nibh tation inciderint. Quas nulla ei sit, ex eam rebum voluptaria. Id eam altera similique. Ex justo assentior persequeris mea, ei hinc paulo ubique mei. <br><br>Cu nam epicurei torquatos, et accusam accommodare vim. Vis sint saperet officiis et. Ad consequat posidonium mea, et duo paulo quidam maluisset, vel an electram expetendis. An vis repudiare tincidunt, mentitum convenire eloquentiam ut vis, summo partiendo pro ad."
  description:
    en: Enter desired disclaimer text. Use &lt;br&gt; for linebreaks.

You would then have a button in the composer that looks like so:

and clicking the button would add

<div data-theme="disclaimer"></div>

which get’s converted to whatever you set in the component’s settings

and the end result looks like this

and you can use

[data-theme="disclaimer"] {

}

in CSS to style it however you like.

21 个赞

That’s awesome! Thanks @Johani

Added to Tips’n’Tricks.

2 个赞

Hi @merefield - funnily enough I was looking for similar functionality - inserting a standard snippet of text - but rather than a button I wanted a trigger string that would expand out to a piece of markdown. (OK, I suppose alternatively I could modify the button to a dropdown with a few options)

This is probably not a core Discourse feature but a plugin.

Ideal behaviour:

  • I type :stub: (I don’t mind about using something instead of the delimiting : characters, but wondered if hooking into the emoji interface might work since that has the kind of ‘completion’ type behaviour that I’d like)

  • Discourse replaces :stub: with

    > This article is a stub - please improve it by  **editing**  and  **adding links**  and  **detail**  (it’s a ‘wiki’ so any user can edit and add information) or by  **commenting**  below.
    
  • which is rendered as

    This article is a stub - please improve it by editing and adding links and detail (it’s a ‘wiki’ so any user can edit and add information) or by commenting below

  • and there should be somewhere in the UI to configure these snippets, a bit like the Custom Emoji interface

5 个赞

Great idea for a plugin! Would you be ok for the text to appear only in the preview and the final cooked view?

4 个赞

@pacharanero 的建议对我们来说也太棒了。在我们的案例中,它们将仅供员工使用,因此我们不希望在编辑器工具栏中显示任何内容,但输入一个简短的代码来插入自动更新块将是惊人的 :+1:

1 个赞

目前,要实现此行为的一种非 Discourse、非中心化管理的方式是使用跨平台剪贴板管理器,例如 CopyQ,并设置“命令/全局快捷方式”部分,以便您可以将任意文本插入剪贴板。

然后,这些片段可以在 CopyQ UI 中进行管理、分配给热键,或出现在右键单击的 CopyQ 菜单中。这不像嵌入 Discourse 的插件那么好用,但它的优点是可以在所有应用程序中工作,而且已经存在!

(请注意,这需要在您希望以这种方式使用的每台计算机上进行设置。您可以将这些命令和全局快捷方式导出和导入到文件中,以便在多台计算机或团队之间设置相同的设置)

对我来说完全没问题。我认为与 DiscoTOC 和 Placeholders 不同,它_确实_需要在预览窗格中正确渲染,但在编辑器中,它可以简单地显示所选的任意 :slug: 触发短语。

感谢您的回复。CopyQ 解决方案似乎不符合我的要求(至少我认为不符合)。

例如,我想在帖子中输入一个片段(例如 :slug:),然后在渲染时,它会渲染此 slug 的当前内容(其中可能包含 markdown)。如果我更改此 slug 的内容,那么所有使用它的帖子都会立即更新为包含新内容(帖子本身只包含 slug,内容在渲染时被切换进来)。

即使搜索不知道内容的存在,我也没关系(只显示最终的已处理版本对我来说就足够了)。

祝好!

这里是另一种方法……

1 个赞