В УПП поле форматированного документа недоступно из-за режима совместимости, а свободы HTML-документа хочется, поэтому было внедрено решение, которое за счет простой расширяемости позволяет не только форматировать текст, но и обрабатывать его совместно в 1С и JavaScript.
Для этого был выбран редактор Summernote, который предоставляет не только легковесный и легко интегрируемый редактор, но и позволяет просто расширять его своими кнопками и функциями обработки. Например, можно подписаться на событие изменения и обрабатывать его по своему. О возможностях расширения редактора можно прочитать на странице Deep Dive.
В целом решение не сильно отличается от других редакторов, в том числе поля форматированного документа 1С, но есть отличия, которые удалось дополнительно реализовать. О них и расскажу. Кстати, реализован весь функционал в виде обработки, что позволяет максимально просто внедрить и использовать решение.
Начиналось все как решение для обычных форм, но постепенно переросло в изучение управляемых, так что они основные. Расширение также пробовал, но особых преимуществ пока не увидел: также основные действия приходится выполнять на сервере из-за ограничений, в том числе веб-клиента, под который также подстроено текущее решение, те же макеты, общие или в обработке. Примеры внедрения присутствуют в самой обработке, но есть и в тестовой базе, где это разрабатывалось. При этом ввиду нагруженности основной формы также добавил форму Мини, чтобы описать там только основные моменты. Если хочется узнать, с чего начиналось, читайте первую статью, она с технической точки зрения поинтересней будет.
1. Добавление своих кнопок
ИконкаВставки = ОбработкаОбъект.ПолучитьИконкуИзНабора(6, 128, 128);
Кнопка = ОбработкаОбъект.НоваяКнопка("ФоноваяКартинка", , "Картинка" , , ИконкаВставки);
Кнопка.Подсказка = "Установить фоновое изображение";
ОбработкаОбъект.РазместитьКнопку(БольшоеТекстовоеПоле, Кнопка);
В один из макетов загружена полоска иконок, собранная с помощью базового редактора XnView с одним прозрачным цветом, из которой и получается иконка для кнопки, указывается ее код, с помощью которого потом можно отследить нажатие этой кнопки (часть ДанныеСобытия.Element.className), вид (текст или картинка) и всплывающая подсказка. Также можно указать код JavaScript и даже сделать глобальную вставку переменной (см. пример с Моей кнопкой), чтобы использовать ее в своем коде 1С или кнопки. Все эти примеры есть в реализации основной формы УФ, в процедуре ОбновитьСодержимоеПоляНаСервере.
Дальнейшая обработка нажатия кнопки происходит так:
СписокКлассов = "%" + СтрЗаменить(ДанныеСобытия.Element.className, " ", "% %") + "%";
Если Найти(СписокКлассов, "%btn-toentrance%") > 0 Тогда
...
ИначеЕсли ДанныеСобытия.Element.innerHTML = "Копировать" Тогда
СредаДокумента().ExecuteEditorCommand("focus");
...
ИначеЕсли Найти(СписокКлассов, "%ФоноваяКартинка%") Тогда
Ждать КлиентскийКонтекст.УстановитьФоновуюКартинку(СредаДокумента(), УникальныйИдентификатор);
Модифицированность = Истина;
, где btn-toentrance и ФоноваяКартинка - это коды кнопок, а Копировать - текст кнопки контекстного меню, которое также достаточно просто редактируется в макете МакетОписания, раздел wrapper. Обработчик меню кодом не вставляется, его нужно заносить в МакетОсновногоСкрипта самостоятельно.
2. Свои шрифты, в том числе фиксированный набор шрифтов
В общем-то, свои шрифты может добавить любой пользователь (что конечно, не гарантирует аналогичного отображения на других ПК)), можно и составить свой набор для всех клиентов, в том числе фиксированный:
РедакторГТР.НаборШрифтов.Добавить("Georgia");
РедакторГТР.НаборШрифтов.Добавить("Times New Roman");
РедакторГТР.НаборШрифтов.Добавить("Calibri");
РедакторГТР.ФиксированныеШрифты = Истина;
3. Общие настройки панели и частные для каждой формы, например
Поддерживается настройка панели инструментов, любую кнопку можно передвинуть или скрыть/отобразить (например, по умолчанию в редакторе скрыты кнопки истории, что достаточно обидно - всегда достаю, когда в новой базе настраиваю). Причем эти правила могут распространяться как на отдельные формы (НазваниеСохраненныхНастроек), так и на всю базу. При этом, что характерно, общие настройки не спорят с персональными, отображаются те кнопки, которые отображены хотя бы в одной настройке, но те, что скрыты в персональной и будут скрыты и лишний шрифт скрыть тоже можно. Если не нравится, меняйте порядок обработки общих и персональных настроек.

4. Управление фоном элемента, включая распространение его на родительский элемент
Всегда хотелось сплошной заливки элемента, особенно при разреженном отображении строк, поэтому добавил такую функцию, которая позволяет перенести фон или фоновое изображение на родительский или указанный подчиненный элемент. Особенно эффектно смотрится абзац, расположенный в отдельной ячейке таблицы, залитой полностью, но это надо знать, к сожалению. Для фонового изображения настраивается также его яркость, что важно. Все это доступно через контекстное меню.
5. Управление таблицами
Собственно, таблицы поддерживаются уже в базе и в поле редактора они всегда будут выглядеть адекватно, но хотелось большей гибкости. Поэтому добавил возможность управления шириной колонки (через ячейку) и границами, чтобы и вне редактора таблица выглядела приемлемо, а не сжатыми ячейками без границ. Кроме того, естественно, хочется и объединять ячейки, что тоже доступно. Также реализовал через контекстное меню
6. Полностью клиентская процедура чтения содержимого поля
Размер редактируемого текста может превышать несколько мегабайт (например, из-за хранения изображений в теле документа), поэтому не хотелось бы при обычном обновлении реквизита справочника или документа лишний раз гонять все данные с клиента на сервер и обратно. Поэтому процедура получения изменения достаточно простая:
Если СредаДокумента.Modificated() Или ОбновлятьВЛюбомСлучае Тогда
МодифицированностьФормы = Истина;
Содержание = СредаДокумента.Content();
СредаДокумента.CheckItSaved();
КонецЕсли;
, где СредаДокумента это defaultView Документа поля HTML. При этом отмечается, что содержимое уже обновлено, чтобы при следующей проверке изменений не считывать все заново. Таким образом легко получить всегда синхронизированную версию редактируемого текста.
7. Умная обработка стилей
Также с предыдущей версии остались и улучшены управление стилями. В частности это хорошо работает с текстом, вставленным из Word/Excel, позволяя сократить размер тела документа до 30 и более процентов (иногда в разы) без потери качества. Для этого служат процедуры СкомпоноватьСтили и УдалитьЛишниеСтили. Суть компоновки в том, что ищутся одинаковые объявления стилей в тегах документа и выделяются в отдельный стиль, который применяется ко всем таким элементам, экономя таким образом объем текста. Хотя для некоторых случаев здесь есть недостаток. Он в том, что стили, прописанные в теге, по умолчанию считаются основными, в то время как добиться такого же поведения от стилей, расположенных в блоке styles, можно для каждого свойства указывая !important, чего я, конечно, не делаю, поэтому, например, ссылки станут выглядеть как ссылки, если они были черными, а границы таблицы в редакторе (!) станут опять едва заметными, потому что это стиль, прописанный по умолчанию.
8. Чем отличается первая версия от второй
Отличается в первую очередь своей легкой внедряемостью, поскольку весь код сосредоточен в обработке, ее легко соединить с нужным элементом и обрабатывать текст. Во вторых, кнопки добавляются простым кодом (да, с иконками надо решать самому - в расширении можно было бы реализовать свои кнопки в интерфейсном варианте, что есть в тестовой базе). В третьих, большинство перечисленных функций, не говоря уже о тонкой подгонке решения, произведены именно в ней и позволяют комфортней работать с редактором как пользователю, так и программисту. В первой банально не было настроек, например.
9. Реквизиты обработки - управление настройками
- ВысотаКнопок - отвечает как ни странно, за высоту кнопок, которые можно сделать немного повыше или пониже в зависимости от размер элемента, например
- МестоЗаполнитель - текст, который будет высвечиваться бледным, если текста нет
- НаборШрифтов - список значений, который будет хранить все шрифты, которые доступны в зависимости от настроек. При фиксированных шрифтах задается вручную
- НазваниеСохраненныхНастроек - служит для разделения настроек для разных форм/элементов
- ОсновнойШрифт - название шрифта текста, который будет использоваться для вывода текста с неуказанным шрифтом
- ОтключитьТаб - Кнопка Таб по умолчанию работает, но странно, если честно, то есть табуляция добавляется, но вместе с тем происходит переход по тексту, при значении Истина при нажатии Таб ничего не происходит
- ОткрыватьСсылкиВнутри - в ходе эксплуатации выяснилось, что пользователи, несмотря на наличие кнопки Вставить ссылку, в основном вставляют их простым копированием, что приводит к тому, что нажатие на нее открывает вместо редактора ссылку. Во избежание этого добавлен параметр
- ПлавающийРежим - редактор может работать в двух режимах - режим панели и плавающий. Последний отличается всплывающей по правой кнопке панелью - естественно без меню
- РазмерШрифтаКнопок - вместе с высотой кнопок позволяет экономить место либо заботиться о слабовидящих
- РазмерШрифтаПоУмолчанию - используется для основного текста
- РесурсыЧерезВременноеХранилище - для старых версий 1С либо просто для совместимости оставлен вариант с полной подгрузкой текста скриптов и шрифта summernote, но вообще-то рекомендуемый метод именно этот
- Содержание - собственно текстовое наполнение со всеми тегами и стилями, конечно
- ТолькоПросмотр - доступность редактирования текста
- ФиксированныеШрифты - при использовании фиксированных шрифты подгружается только список, указанный в НаборШрифтов.
Также хочется отметить, что для отображения в списке в содержании текста сперва идет текст, а потом стили, но для лучшего опыта, конечно, нужно использовать метод УбратьТегиДляПредставления, который расположен в модуле менеджера (есть соответствующий макет для импорта).
10. Некоторые клиентские функции
Подсмотрел в одной из интеграций метод, при котором для объявления клиентских функций используют специально выделенную форму и метод ПолучитьФорму, как способ доступа к функциям, поэтому решил выделить основные функции туда - в КлиентскийКонтекст. Чтобы сохранить совместимость с версией 8.3.23 - выделил использование буфера обмена (нужен только для линукс, в Windows вставка из буфера обмена средствами JavaScript отлично работает) также в отдельную форму.

Это позволяет разгрузить форму использования поля ГТР и не запоминать вызовы функций JavaScript, которые именованы на английском (это сделано также для совместимости, поскольку ранние версии 1С не поддерживают русские названия функций JavaScript - только переменных).
11. Совместимость
На Windows проверял вплоть до версии 8.3.23 - все работает, на линукс добиться такой же совместимости не удалось, поскольку в основном скрипте уже используются более новые технологии, в частности стрелочные функции, да даже банально $('#summernote').summernote не работает, хотя чего уж там - jquery, обращение по id. В общем на линукс минимальная совместимая версия 8.3.26 или свежая 8.3.25. На версии 8.3.25.1394 также прогружается скрипт, но почему-то не обрабатываются события Нажатия. При всем при этом режим совместимости влияния не оказывает и это решение запросто работает в старенькой УПП.
Кстати, в выгрузке базы есть первая версия обработки, которая лишена большинства перечисленных выше функций, кроме добавления кнопок, но которая запускается даже в версии 8.3.23 на линукс благодаря тому, что основана на более старой версии summernote.
Проверено на следующих конфигурациях и релизах:
- 1С:Библиотека стандартных подсистем, редакция 3.1, релизы 3.1.10.174
Вступайте в нашу телеграмм-группу Инфостарт