Добавить пользовательские теги bbcode для цитат в markdown

Я разрабатываю расширение для Discourse для отображения snapblocks. Мне удалось добавить теги BBCode, которые заменяются блоками, но, к сожалению, если вы решите процитировать эти блоки, текст внутри них появится в виде блока кода вместо исходного тега BBCode.

Я пытался изучить исходный код плагина spoiler, но не могу понять, как он позволяет цитировать спойлеры.

Есть ли способ исправить это и добавить исходный код блока внутрь пользовательских тегов BBCode?

Вот исходный код моего разрабатываемого плагина:

Меня действительно раздражает то, что нет стандартной документации, в которой легко разобраться, что значительно усложнило разработку моего плагина.

Думаю, это функции DecorateCallBack:

Связанный тест:

Чтобы помочь в отладке, выводя содержимое выделенного текста, можно добавить console.log(_selectedText); после этой строки в основном файле:

Скриншот интерфейса консоли браузера с различными текстовыми элементами и панелью навигации. (Подпись сгенерирована ИИ)

Я проверил это, и действительно, это позволило мне добавить [sb] вокруг текста, но, к сожалению, обрабатывался только текст, находящийся внутри элемента. Я бы хотел, чтобы вместо этого брался оригинальный текст, так как он содержит всё необходимое для воссоздания блока.

Сейчас я пытаюсь выяснить, можно ли сделать сам SVG не выделяемым, а вместо этого поместить под ним скрытый выделяемый элемент с исходным текстом.

Я реализую это, создавая контейнер, содержащий два элемента: SVG и исходный текст. Я пытаюсь установить для SVG position: relative, чтобы он мог выйти из потока и располагаться поверх исходного текста, а также задать контейнеру те же размеры, что и у SVG, чтобы он выглядел так, будто SVG всё ещё находится внутри текста. Кроме того, у исходного текста будет opacity: 0, и он будет очень маленького размера, чтобы быть невидимым на случай, если он выйдет за границы SVG.

Интересует, есть ли более простой способ сделать это, поскольку мой текущий подход потребует пересоздания всех постов, и, кроме того, это кажется костыльным решением проблемы, которая, как мне кажется, не должна требовать таких усилий.

Редактирование: после изучения кода функции addTagDecorateCallback() выяснилось, что в обратном вызове можно возвращать текст для замены любого текста, который использовался бы по умолчанию. Это действительно сильно поможет, так как, надеюсь, мне не придётся иметь дело с моей костыльной системой, которую я разрабатывал, и которая работает ужасно.

Мне удалось заставить это работать, сохранив исходный текст в атрибуте HTML, а затем в функции обратного вызова addTagDecorateCallback() просто возвращая его, чтобы получить исходный текст.

Вот фрагмент кода для тех, кто хочет узнать, что я сделал.

В файле assets/javascripts/lib/discourse-markdown/snapblocks-discourse.js, где инициализируются теги bbcode, я изменил код так, чтобы он сохранял исходный текст внутри атрибута snapblocks-source, чтобы я мог получить его позже.

В файле assets\javascripts\discourse\initializers\snapblocks-discourse.js я добавил код для обработки цитирования.

// assets\javascripts\discourse\initializers\snapblocks-discourse.js

import {
  addBlockDecorateCallback, // теги bbcode блоков
  addTagDecorateCallback, // встроенные теги bbcode
} from "discourse/lib/to-markdown";

function initializeSnapblocks(api, siteSettings) {
  addTagDecorateCallback(function () {
    // this.element не является HTML-элементом,
    // но он содержит все атрибуты HTML
    const { attributes } = this.element;

    // Обычно вы проверяете, совпадает ли "class" с вашим классом,
    // но здесь мне нужен только "snapblocks-source"
    if (attributes["snapblocks-source"]) {
      let prefix = "[sb";

      // Добавление атрибутов к тегу bbcode (которые также хранятся
      // в элементе как атрибуты).
      const attrs = [
        "blockstyle",
        "wrap",
        "wrapsize",
        "zebra",
        "showspaces",
        "santa",
      ];
      for (const attr of attrs) {
        if (attributes[attr]) {
          prefix += ` ${attr}=${attributes[attr]}`;
        }
      }

      prefix += "]";

      this.prefix = prefix;
      this.suffix = "[/sb]";
      // если вы возвращаете текст, он будет использован вместо выбранного текста
      return attributes["snapblocks-source"];
    }
  });
}

Для тегов bbcode блоков это работает аналогично, только нужно использовать addBlockDecorateCallback() вместо этого.

К сожалению, мне придется пересоздать (rebake) сообщения, если я хочу, чтобы старые фрагменты snapblocks можно было цитировать. Также это не работает, если вы выделяете текст на SVG-элементе; это срабатывает только в том случае, если вы выделяете текст до и/или после, а также хотя бы часть текста самого SVG.