Insertable, centrally maintained text/markdown snippets

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 лайка

Привет, @merefield — как ни странно, я тоже искал похожий функционал: вставку стандартного фрагмента текста. Но вместо кнопки мне хотелось бы использовать триггерную строку, которая разворачивалась бы в кусок markdown. (Хотя, в принципе, можно было бы просто превратить кнопку в выпадающий список с несколькими вариантами.)

Скорее всего, это не основная функция Discourse, а плагин.

Идеальное поведение:

  • Я ввожу :stub: (мне не принципиально использовать именно символы : в качестве разделителей, но интересно, сработает ли интеграция с интерфейсом эмодзи, поскольку там есть нужный мне тип поведения «автодополнения»)

  • Discourse заменяет :stub: на

    > Это статья-заготовка — пожалуйста, улучшите её, **отредактировав** текст, **добавив ссылки** и **детали** (это «вики», поэтому любой пользователь может редактировать и добавлять информацию) или **оставив комментарий** ниже.
    
  • что отображается как

    Это статья-заготовка — пожалуйста, улучшите её, отредактировав текст, добавив ссылки и детали (это «вики», поэтому любой пользователь может редактировать и добавлять информацию) или оставив комментарий ниже

  • Также где-то в интерфейсе должно быть место для настройки таких фрагментов, примерно как интерфейс пользовательских эмодзи.

5 лайков

Отличная идея для плагина! Вы не против, чтобы текст отображался только в предварительном просмотре и в окончательном отформатированном виде?

4 лайка

Предложение от @pacharanero было бы для нас тоже фантастическим. В нашем случае они были бы только для сотрудников, поэтому мы не хотели бы ничего показывать в панели инструментов редактора, но ввод короткого кода для вставки автоматически обновляемого блока был бы замечательным :+1:

1 лайк

На данный момент нецентральным, не связанным с Discourse способом реализации такого поведения сегодня является использование кроссплатформенного менеджера буфера обмена, такого как CopyQ, и настройка раздела «Команды/Глобальные горячие клавиши», чтобы можно было вставлять произвольный текст в буфер обмена.

Эти сниппеты затем можно управлять либо через интерфейс CopyQ, либо назначать им горячие клавиши, либо они будут отображаться в контекстном меню CopyQ при щелчке правой кнопкой мыши. Это не совсем так удобно, как встроенный плагин для Discourse, но зато работает во всех приложениях и уже существует!

(Обратите внимание, что такую настройку необходимо выполнить на каждом компьютере, который вы планируете использовать таким образом. Вы можете экспортировать и импортировать эти команды и глобальные горячие клавиши в файл, чтобы настроить одинаковые параметры на нескольких машинах или в команде).

Меня это вполне устроит. Я считаю, что, в отличие от DiscoTOC и Placeholders, этот элемент действительно должен корректно отображаться в панели предварительного просмотра, но в редакторе можно просто показывать выбранную триггерную фразу :slug:.

Спасибо за ответ. Решение CopyQ, похоже, не подходит для моих задач (по крайней мере, я так думаю).

Например, я хотел бы вставить фрагмент в пост (например, :slug:), и при рендеринге он должен отображать текущее содержимое для этого слага (которое может содержать Markdown). Если я изменю содержимое этого слага, то все посты, использующие его, должны быть немедленно обновлены с новым содержимым (сам пост содержит только слаг, а содержимое подставляется при рендеринге).

Меня вполне устроит, если поиск не будет знать о существовании содержимого (и показывать только финальную отрендеренную версию).

Спасибо!

Вот другой подход…

1 лайк