Как подружить Tickets и TinyMCE

Разрабатывая свой очередной (аж второй :) ) проект на Modx Revolution столкнулся со странностью поведения сниппета Tickets (tickets-1.6.16-pl ): при создании тикета не появлялась стандартная панелька Modx с кнопками сохранения, отмены и помощи в правом верхнем углу админки. Вот так выглядит админка при создании нового тикета: кнопок нет, полос прокрутки нет.


Погуглив я обнаружил, что неодинок в своих проблемах: этот вопрос неоднократно поднимался даже на этом ресурсе. Вариантов решения аж 2 (из комментариев к тем записям):
  1. Поставить другой редактор (у меня установлен TinyMCE-4.3.4-pl)
  2. Или использовать хак
Но неужели ничего нельзя сделать? Давайте попробуем разобраться под катом.
Если посмотреть в консоль браузера мы увидим ошибку JS




Можно предположить, что в данном месте происходит создание какого-то html элемента и заполнение его содержимым, которое должно до этого храниться в объекте Tiny.lang. Если мы попробуем посмотреть на его содержимое, то увидим, что оно undefined, т.е. этот объект не заполнен, более того — даже не создан. Попробуем найти откуда он заполняется, поставив брейкпоинт на эту строку и загрузив любую другую страницу, с которой не возникает проблем. И оказалось, что действительно этот объект в других страницах заполнен и содержит в себе данные локализации нашего любимого редактора tinymce.


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


В поисках места создания этого объекта я набрел на элемент script в head, в котором происходит заполнение данного объекта:


Значит этот вывод генерируется на сервере и нужно искать в Modx'е. После определенного поиска место генерации данного конфига было обнаружено метод initialize редактора (\core\components\tinymce\tinymce.class.php:169).


Путем использования дебагера было определено, что инициализация редактора происходит при подгрузке ресурса — неважно, создание это или обновление. А также оказалось замечено, что при создании тикета (который тоже является ресурсом) происходит инициализация редактора. Я предположил, что в процессе создания тикета происходит потеря ранее инициализированных данных, что и является причиной проблемы. За создание тикета отвечает класс TicketCreateManagerController (core\components\tickets\controllers\ticket\create.class.php), который наследуется от стандартного класса ResourceCreateManagerController и в котором происходит переопределение метода loadCustomCssJs (:40), где происходит следующее
$html = $this->head['html'];
parent::loadCustomCssJs();
$this->head['html'] = $html;
Именно вызов родительского метода loadCustomCssJs и обеспечивает корректную подгрузку всех данных, в том числе так необходимого нам объекта Tiny.lang из конфига TinyMCE, и помещает их в виде массива в $this->head['html'] (далее head['html']). Но вся проблема заключается в том, что этот массив после заполнения перезаписывается более ранним вариантом, в котором нет того, что нам нужно. Далее в процессе выполнения метода создания тикета происходит добавление новых элементов в этот массив, хранящих настройки и свойства для клиентской части, однако конфиг редактора оказывается безвозвратно потерян и в конечном рендере страницы не участвует. Путем экспериментов было определено, что корректная работа будет восстановлена при замене всего лишь одного элемента массива head['html'], содержащего данные о документе. В данном массиве он устанавливает с индексом 1, поэтому изначальный вариант лечения выглядел так




Однако позже меня посетила мысль, что не всегда этот элемент может занимать именно этот индекс, поэтому гораздо лучше будет его гарантированно находить и заменять на нужный. Для этого был написан приватный метод класса создания тикета
/**
   * To replace the the required array element
   *
   * @param $needle string
   * @param $html string
   * @param $srcHead array as reference
   *
   * @return void
   */
  private function replaceHeadHTML($needle, $html, &$srcHead)
  {
    foreach ($srcHead as &$haystack) {
      if (strpos($haystack, $needle)) {
        $haystack = $html;
        break;
      }
    }
  }
который находит именно тот элемент в исходном массиве head['html'], который нужно заменить (там строки одинаково начинаются) и заменяет его на переданную строку, содержащую те данные, что мы хотим передать в клиентскую часть. Тогда в методе loadCustomCssJs использую данный метод следующим образом
//данные, которые должен подгрузить сниппет помещаем в переменную
	$newLoadProperties = '
	<script type="text/javascript">
	// <![CDATA[
	MODx.config.publish_document = ' . (int)$this->canPublish . ';
	MODx.config.default_template = ' . $this->modx->getOption('tickets.default_template', 
null, $this->modx->getOption('default_template'), true) . ';
	MODx.onDocFormRender = "' . $this->onDocFormRender . '";
	MODx.ctx = "' . $this->ctx . '";
	Ext.onReady(function() {
		MODx.load(' . $this->modx->toJSON($ready) . ');
	});
	// ]]>
	</script>';
    
	// заменяем в массиве строку, начинающуюся таким же образом, как и та, которую нужно перезаписать
	$this->replaceHeadHTML('
		<script type="text/javascript">
	    // <![CDATA[
	    MODx.config.publish_document = ', $newLoadProperties, $this->head['html']);
При этом, естественно, вышеуказанный кусочек с заполнением head['html'] должен выглядеть как вызов функции класса-родителя без дополнительных переопределений
parent::loadCustomCssJs();
Недостаток данного метода в том, что такие же манипуляции нужно произвести в классе TicketUpdateManagerController (core\components\tickets\controllers\ticket\update.class.php).
З.Ы. Также на данный момент замечен баг: при входе в созданный тикет для редактирования его html текст отображается в поле «Аннотация»


В комментариях хочется увидеть мнение сообщества по поводу данного способа решения проблемы и стоит ли делать пулл-реквест с данным решением для включения его в исходный сниппет?
З.З.Ы. Поставил Tickets-1.8.0 pl. Теперь при переходе на страницу — раздел с тикетами — она не отображается вообще. Все свои изменения естественно откатил до исходного состояния. Может это у меня одного такая проблема? Поделитесь пожалуйста.
livalex
23 февраля 2017, 19:36
modx.pro
2
4 777
+5

Комментарии: 22

Алексей Андреев
24 февраля 2017, 10:35
+3
Нифига не понял по методу, но плюсую за желание решить проблему, сам сейчас мучаюсь с TinyMCE RTE 1.1.x, он менее удобен, чем обычный TinyMCE.

З.Ы. Также на данный момент замечен баг: при входе в созданный тикет для редактирования его html текст отображается в поле «Аннотация»
По-моему это не баг, туда автоматически помещается текст, который потом выводится в качестве интро у тикета (до кнопки «Читать далее»). По дефолту, насколько я понял, просто пропускается всё содержимое content через Jevix.
    TITAN-UZ
    24 февраля 2017, 13:54
    +1
    У меня ест решения будет время вложу!
    Василий Наумкин
    24 февраля 2017, 19:25
    +3
    1. Ребят, насколько я понимаю, в miniShop2 такой проблемы нет.
    2. Tickets и miniShop2 очень похожи — ибо автор у них один.
    3. Неужели никто не может сравнить работу с TinyMCE у этих двух дополнений и прислать PR с исправлением?

    Я сам не пользуюсь TinyMCE, так что решение проблемы исключительно в ваших руках.
      Николай Савин
      24 февраля 2017, 22:30
      0
      Василий а ты каким редактором пользуешься? Почему именно им?
        Василий Наумкин
        24 февраля 2017, 22:36
        0
        Ace, потому что он хороший.

        Мне не нравится, когда редактор от меня что-то скрывает. Или меняет то, что я написал modx.pro/security/8811-about-the-benefits-of-rte/
          livalex
          25 февраля 2017, 20:41
          0
          А для контент-менеджеров удобно? Или всяким там менеджерам отдельную фронтенд часть делать нужно?
            Василий Наумкин
            25 февраля 2017, 21:03
            0
            Не знаю. У меня нет контент менеджеров и последний сайт на заказ, который я делал на MODX, был Vrmedia, с отдельной админкой на фронте.
        brioni
        26 февраля 2017, 17:28
        +1
        Василий, сколько денег будет стоить внесение таких изменений (не дожидаясь PR) + замена MarcitUp на TinyMCE хотя бы для TicketCreate во фрондэнде? (для краудфандинга)
          Василий Наумкин
          26 февраля 2017, 17:34
          0
          PR для исправления работы с редактором уже прислали, как будет время — обработаю. А менять на фронтенде я ничего не планирую.

          MarkItUp отключается в настройках, дальше можно подключать любой удобный редактор самостоятельно.
            brioni
            26 февраля 2017, 18:02
            +1
            Ок. Спасибо.

            С отключение MarkItUp все просто, а вот подключить любой удобный редактор самостоятельно у меня не получается. Пробовал.
      Константин Ильин
      25 февраля 2017, 19:07
      +1
      Вчера только столкнулся с такой проблемой, потом увидел, что на сайте стоит TinyMCE, удалил поставил другой, полет нормальный.
      Самый оптимальный редактор для менеджеров который я ставлю — это CKEditor.
      Выбрал CKEditor из-за того, что он хотя бы не плодит дохерища тегов.
        Василий Наумкин
        01 марта 2017, 14:50
        +1
        Выпустил новую версию, должно работать — проверяйте.
          Денис Чубенко
          02 марта 2017, 16:08
          0
          У меня не заработала новая версия, вернее выдает окно ошибки хоть с TinyMCE, хоть без. Ошибка появляется только на ресурсах с тикетами. Интересно, что окно ошибки выдает с прозрачностью нулевой, не сразу его видно. Может чего-то нахимичил когда переставлял. Содержимое окна — это 404 страница.
            Василий Наумкин
            02 марта 2017, 18:15
            +1
            Вот какая связь может быть между 404 и редактором?

            Почему на чистом сайте всё ок?
              Денис Чубенко
              02 марта 2017, 19:10
              0
              Возможно и я что-то напортачил, поставил предыдущую версию, все нормально работает. Это окно заметил когда в редакторе TinyMCE попытался переключить в режим HTML. Что-то не давало нажать кнопку, по F12 увидел, что есть поверх всего дополнительный div у которого opacity было 0. Сам сайт еще пустой, только начал его настраивать.
              Вот я повторно установил и опять появилось, может есть предположение, что это такое? Не понятно почему он берет данные именно 404 страницы.
                Василий Наумкин
                02 марта 2017, 19:12
                0
                Без понятия.

                Еще раз — я не пользуюсь такими редакторами и разбираться с их особенностями мне не досуг. Кнопка HTML у меня на тесте работала без проблем.
        Павел Левин
        11 марта 2017, 01:52
        0
        Была аналогичная проблема вплоть до некой php ошибки при попытке создать/редактировать документ.

        Я решил это так: использовать CKEditor.
          Николай Каленников
          16 мая 2017, 17:46
          2
          0
          CKEditor на фронтенде тоже неплохо подключается. Деактивируем в настройках MarkItUp, текстовое поле в чанке
          <textarea class="form-control" placeholder="[[%ticket_content]]" name="content" id="content"   
           rows="40"></textarea>
          подключаем скрипт на странице
          <script src="/assets/components/ckeditor/ckeditor.js"></script><script>CKEDITOR.replace('content');</script>
          Загруженные картинки просто перетаскиваются в текст. Заказчики с MarkItUp никак не дружат.
            Роман
            20 декабря 2019, 13:35
            0
            Подскажите, а вопрос как-то решился или нет?
              Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
              22