Добавить прямую кнопку в шаблоны ответов в редакторе

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

Добавление кнопок на панель инструментов осуществляется с помощью другого метода API плагинов.

Панель инструментов использует этот метод plugin-api.js.es6#L375-L391, в то время как всплывающее меню использует этот plugin-api.js.es6#L396-L411.

Плагин готовых ответов использует метод всплывающего меню следующим образом:

https://github.com/discourse/discourse-canned-replies/blob/master/assets/javascripts/initializers/add-canned-replies-ui-builder.js.es6#L18-L25

Вы не можете переместить кнопку, если не сделаете форк плагина — это крайне не рекомендуется.

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

На панели инструментов есть два типа кнопок. Первый тип — это кнопки, обрабатывающие форматирование, например Жирный и Курсив. Поскольку они не похожи на то, чего вы хотите достичь, пока проигнорируем их.

Другой тип кнопок вставляет такие вещи, как даты и эмодзи. Давайте посмотрим на кнопку даты — календаря.

Теперь у нас есть пример, к которому можно обратиться. Давайте попробуем создать новую кнопку.

Начнем с этого:

api.onToolbarCreate(toolbar => {
  toolbar.addButton({
  
  });
});

и по одному добавим атрибуты из кнопки готовых ответов. Для справки они следующие:

id: "canned_replies_button",
icon: "far-clipboard",
action: "showCannedRepliesButton",
label: "canned_replies.composer_button_text"

id: это позволяет добавить CSS-классы к кнопке — мы используем custom-canned-button.

icon: иконка, которую будет использовать кнопка — мы оставим её прежней.

label: у всплывающих кнопок есть текст, а у кнопок композера его нет, поэтому нам нужно изменить это на title и использовать то же значение.

action: здесь вы определяете, что делает кнопка. Давайте соберем всё вместе:

api.onToolbarCreate(toolbar => {
  toolbar.addButton({
    id: "custom-canned-replies",
    icon: "far-clipboard",
    action: "showCannedRepliesButton",
    title: "canned_replies.composer_button_text"
  });
});

Если вы попробуете это, вы получите кнопку на панели инструментов, но при нажатии на неё ничего не произойдет. Это происходит потому, что действие showCannedRepliesButton не определено. Это связано с другим контекстом, так как вы делаете это в теме.

Если вы посмотрите на плагин готовых ответов, то заметите, что это действие определено в контроллере композера:

https://github.com/discourse/discourse-canned-replies/blob/master/assets/javascripts/initializers/add-canned-replies-ui-builder.js.es6#L5-L16

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

const composerController = api.container.lookup("controller:composer");

api.onToolbarCreate(toolbar => {
  toolbar.addButton({
    title: "canned_replies.composer_button_text",
    id: "custom-canned-replies",
    group: "extras",
    icon: "far-clipboard",
    sendAction: () => composerController.send("showCannedRepliesButton")
  });
});

Обратите внимание, что мы использовали тот же паттерн, что и в кнопке календаря, для sendAction. Единственные два отличия: вместо этого

toolbar.context.send мы используем composerController.send

и мы не передаем событие, так как, думаю, это не нужно.

Это должно дать вам полностью функциональную кнопку на панели инструментов:

но мы еще не закончили, так как эта кнопка теперь видна всем участникам. Условия использования всё ещё применяются, и если пользователь без прав попытается на неё нажать, он получит ошибку. Однако нерабочая кнопка — это плохо, поэтому давайте исправим это.

Права на использование готовых ответов здесь:

https://github.com/discourse/discourse-canned-replies/blob/master/assets/javascripts/initializers/add-canned-replies-ui-builder.js.es6#L34-L38

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

const currentUser = api.getCurrentUser();
const canUseCannedReplies = currentUser
  ? currentUser.can_use_canned_replies
  : false;

if (!canUseCannedReplies) return;

и это обеспечит отображение кнопки только при наличии необходимых прав.

Итак, давайте соберем всё вместе:

import { withPluginApi } from "discourse/lib/plugin-api";

export default {
  name: "move-canned-button",
  initialize() {
    withPluginApi("0.8.7", api => {
      const currentUser = api.getCurrentUser();
      const canUseCannedReplies = currentUser
        ? currentUser.can_use_canned_replies
        : false;

      if (!canUseCannedReplies) return;

      const composerController = api.container.lookup("controller:composer");

      api.onToolbarCreate(toolbar => {
        toolbar.addButton({
          title: "canned_replies.composer_button_text",
          id: "custom-canned-replies",
          group: "extras",
          icon: "far-clipboard",
          sendAction: () => composerController.send("showCannedRepliesButton")
        });
      });
    });
  }
};

Это помещается в этот файл в компоненте темы:

javascripts/discourse/initializers/move-canned-button.js.es6

если вы используете новую функцию Split up theme Javascript into multiple files — крайне рекомендуется.

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

Старый синтаксис
<script type="text/discourse-plugin"
        version="0.8">
const currentUser = api.getCurrentUser();
const canUseCannedReplies = currentUser
  ? currentUser.can_use_canned_replies
  : false;

if (!canUseCannedReplies) return;

const composerController = api.container.lookup("controller:composer");

api.onToolbarCreate(toolbar => {
  toolbar.addButton({
    title: "canned_replies.composer_button_text",
    id: "custom-canned-replies",
    group: "extras",
    icon: "far-clipboard",
    sendAction: () => composerController.send("showCannedRepliesButton")
  });
});
</script>

Последнее, что вам нужно сделать, — скрыть старую кнопку, и это можно сделать так:

.toolbar-popup-menu-options {
  [data-name="Canned replies"] {
    display: none;
  }
}