Расширяемый редактор форматированного текста для 1С (WYSIWYG)

25.04.24

Разработка - Инструментарий разработчика

Наступает момент, когда текстовое поле, которое сделали большим и многострочным, пользователи пытаются наполнить уже не просто текстовым содержанием, но списками, псевдо-таблицами, КАПСОМ и прочими элементами, чтобы только тот, кто это будет читать, смог постигнуть весь смысл, заложенный в этом "тайном послании". Тогда все средства хороши, особенно, если они с открытым кодом и встраиваются в 1С. На моем компьютере предложенные ранее решения не заработали (не в обиду будет сказано, просто дома требовательный linux), поэтому полез впиливать свое, со своими кнопками (непременное условие), и вот что получилось.

Скачать исходный код

Наименование Файл Версия Размер
Расширяемый редактор форматированного текста для 1С (WYSIWYG):
.zip 8,32Mb
4
.zip 0.9.9 8,32Mb 4 Скачать

Этап 1. Знакомимся с редактором Summernote

Этап 2. Внедряем шрифты

Этап 3. Добавляем свои кнопки

Этап 4. Автоматизируем добавление кнопок

Этап 5. Обрабатываем нажатия кнопок

Этап 6. Обрабатываем вставку из других редакторов (компрессия стилей)

Этап 7 Возвращаем совместимость с Linux

Этап 8. Заключительный

Этап 9. Дополнение

По поиску легковесный редактор WYSIWYG (или по-нашему: ЧТВТТИП), наткнулся на интересный сайт, на котором было все, что нужно: кнопка Скачать и действующий пример внедрения на страницу:

 

Как выяснилось уже позже, у данного решения есть еще несколько преимуществ:

1. действительно легковесное решение - требует только jquery и bootstrap из стандартных библиотек, плюс 300 Кб основного года. Оговорюсь здесь, что требуется свой шрифт и встроить его оказалось не так просто, но эта проблема уже решена.

2. легко расширяется панель инструментов, где много кнопок уже предусмотрено, включая кнопки отмены/повтора, но не выводится по умолчанию

3. полностью рабочая вставка из других редакторов (выяснилось, что с ним в 1С необязательно нажимать Ctrl+V, чтобы вставить форматированный текст)

4. два режима работы: ненавязчивая всплывающая панель (пользователь даже не узнает о существовании редактора, пока не вздумает выделить что-то или нажать правой кнопкой) и обычная панель редактора.

 

Внедрение шрифта, когда все уже одним текстовым макетом

Итак, решение сдернуто с сайта, внедрено в текстовый макет 1С, подгружаемый при открытии формы, дома все работает, а на работе... Ограничения сети, другая версия 1С. Да 1С развиваются, как хотят, и в версии 8.3.24 они внедрили использование шрифтов формата woff/woff2, а версии 8.3.23 - нет, поэтому шрифт нужно конвертировать в ttf и тогда внедрить его в макет страницы можно в бинарном виде:

МакетШрифта = ПолучитьМакет("МакетШрифта");
ТекстHTML = СтрЗаменить(ТекстHTML, "summernote.woff2", "data:application/x-font-ttf;charset=utf-8;base64," 
    + СтрЗаменить(СтрЗаменить(Base64Строка(МакетШрифта), Символы.ПС, ""), Символы.ВК, ""));  
		

1С зачем-то вставляет переносы в строку Base64, но зная это, легко исправить. 

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

 Этап 3. Добавляем свои кнопки

Редактировать текст, выставляя стили, шрифты, таблицы и списки уже можно. Но хочется чего-то своего! Здесь авторы позаботились о достаточно простой интеграции дополнительных кнопок, все просто:

  1. Добавляем кнопку:
    this.context.memo("button.HtButtonClass", function() {
        return t.button({
            className: "HtButtonClass",
            contents: "HtButtonContent",
            tooltip: t.lang.HtButtonGroup.HtButtonClass,
            click: t.context.createInvokeHandler("sync1c.HtButtonMethod")
         }).render()
    }),

     

        2. Описываем подсказку: 

HtButtonGroup: {
    HtButtonClass: "HtButtonTooltip"
},

         3. Описываем метод, выполняемый при нажатии:

{
   key: "HtButtonMethod",
   value: function() {
       this.$editor.find(".note-editable").focus()
   }
},

        4. И теперь можно добавить кнопку непосредственно на панель:

["HtButtonGroup", ["HtButtonClass"]],

Всё! После нажатия на кнопку Форматирование (я добавил, легко убирается) ваша новая кнопка появилась:

 

 

 

Этап 4. А если это просто, почему бы не автоматизировать?

Это делалось, конечно, скорее шутки ради, просьба не пинать, но регулярные выражения и поиск нужных мест кода постарался сделать универсальным, чтобы искал и в сжатом модуле (minify) и распрекрасном (prettify), но вполне возможно, что при вашем изменении скрипта что-то пойдет не так, кнопка не добавится или перестанет выполнять код, тут уж отладчик и regex101.com вам в помощь (нужно выбирать Java 8 Flavor), если хочется автоматизации. Просто лишаться возможностей отладки и минификации одновременно (сперва ей активно пользовался) не хочется, поэтому просто расставить флаги %МетодКнопки%, %ПодсказкаКнопки% и прочее не решился, так что остался при регулярных выражениях и ими доволен.

Здесь приведу только регулярные выражения и, собственно, снимок соответствующего справочника:

ШаблонМетода = "{(.|\n){0,60}key.{1,10}HtButtonMethod(.|\n){1,300}}, ?\{"; 
ШаблонКнопки = "this\.context\.memo\(""button\.HtButtonClass"",(.|\n){2,1800}t\.context\.createInvokeHandler\(""sync1c\.HtButtonMethod""\)(.|\n){2,200}}\),";
ШаблонПанели = "\[""HtButtonGroup"", ?\[.[^]]{1,1000}]],";

Подсказку искать совсем просто: там сочетание "НазваниеГруппы:", так что можно обойтись без шаблона. А вот и справочник КнопкиРедактораГТ:

 


Что видно из формы: кнопка с названием Кнопка03, входит в группу AlsoGroup, отображается как иконка высотой 22 пикселя, при нажатии вылетает предупреждение о том, что пора запастись зонтиками, затем вставляет специальную метку для вставки чего-то уже со стороны 1С (PasteFromClipboard) и ставит фокус на поле редактора (снимает его с кнопки, в браузере незаметно, а в 1С очень). Пометка (выделение кнопки) не используется. И все, теперь остается только добавить кнопку на форму при инициализации текста поля HTML и убрать рыбу, к которой цеплялись при добавлении:

НоваяКнопка = Справочники.КнопкиРедактораГТ.НайтиПоКоду("Кнопка03").ПолучитьОбъект();
НоваяКнопка.ДобавитьВСкрипт(ТекстHTML);
НоваяКнопка.ПочиститьРыбу(ТекстHTML);

 

Этап 5. Обрабатываем нажатия кнопок

Кнопка будет на панели (видно на КПДВ), осталось только обработать вставку и сжатие изображения со стороны 1С:

 
 Код вставки и сжатия изображения

 

Кстати, движок Webkit ну совершенно игнорирует ... попытки сжатия изображения своим посредством (методы ToBlob и ToDataUrl) и там, где обычные браузеры успешно сжимают на порядок и больше, сжатие тем же способом в 1С не дает ничего. Да. К счастью же, есть метод ПолучитьКартинку у объекта ОбрабатываемаяКартинка и здесь можно поиграться с параметрами изображения, чтобы сжать их. Убиваем сразу трех зайцев. Исправляем недочет движка 1С и... исправляем еще один недочет платформы - во встроенном в движок окне выбора файла изображения кнопка и надпись не переведены на русский язык, а в Учебной версии и вовсе утрачены тексты, да и окно, несмотря на указанный тип accept="image/*", дает на выбор все файлы, а вот диалог настраивается...

В этом коде есть интересный момент пляски с меткой, сделанной со стороны JavaScript. Зачем она нужна? Чтобы передвинуть курсор мыши строго после текущего положения курсора и вставка, разумеется, что произошла именно в то же место. Дело в том, что со стороны 1С мы максимум что можем - это определить координаты курсора мыши, но обрабатывать их в отношении к тексту на экране просто бессмысленно, нужна позиция именно в тексте с точностью до строки и символа. Это нам дает только JS, которая умеет с этим работать и то с серьезными ограничениями (то, что мы видим, не обязательно то, что оно есть, поэтому для выделения двух соседних слов есть специальная команда, а сами - попробуйте-ка в форматированном тексте!)
В общем, без хитростей не обойтись. И вторая хитрость здесь в том, что появляется скрытый элемент, который выделяется, а затем удаляется: дело просто в том, что если ничего не выделить, что при изменении свойства innerHTML у основного элемента - редактора позиция курсора уйдет в неопознанную область в самом начале, куда не попасть курсором вручную (залипает в спрайтах, не иначе). И если пользователь, не дай бог, решит еще раз воспользоваться вставкой, не передвинув щелчком курсор мыши ... слететь может все, включая панельку и рабочие скрипты. Поэтому в сложных случаях подставляем скрытый элемент, на который после изменения innerHTML и переходим, либо, если позволяет логика, просто выделяем весь текст, а пользователь пусть делает как знает:

ЭлементыФормы.ПолеHTMLОписанияЗадачи.Документ.defaultView.SelectAllText();

Разумеется, эта простенькая процедура уже размещена в модуле скрипта, но если вы очень смелы, можете попробовать вызвать ее тело прямо от defaultView или даже Документа, там не сложно: document.execCommand("selectAll")

Вышеупомянутую пугалку убирать не буду, потому что момент важный, но как выяснилось, обходится еще легче: догадались? Все тот же focus(), который я ставил в конце вызова, нужно поставить перед выполнением основного кода, например, вставки, и тогда все пройдет отлично независимо от положения курсора перед вызовом функции!

Этап 6 Вставка из Word/Excel

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

 
 Сжатие стилей. Для LibreOffice на примерах экономит процентов 20, для Word'a - в разы (итоговый результат удивительно близок, выводы делайте сами)

 Надеюсь, сжатие кому-нибудь да пригодится - на случайно скачанном сложном файле из Word'a показал 13 769 байт строки вместо 30 229 до сжатия стилей (только на них!). Конечно, текста еще раз в 5 меньше, но вы попробуйте такое текстом создать:

 

 

 

Этап 7 Возвращение совместимости с Linux

Здесь чуда не случится, но что замечено/проделано:

  1. линуксовая версия WebKit щепетильнее относится к употреблению ключевого слова let, которое по примеру источника я опрометчиво поставил вместо var. Было время, когда я и сам разбирался в тонкостях этих двух ключевых слов, но потом мне прострелили колено... ©
  2. WebKit на линукс не знает обратных кавычек ``, которые в обычном мире давно обозначают обычный текстовый шаблон
  3. addEventListener - с ним большие сложности, никаких "() =>" нельзя, а bind полной заменой не служит (по моему поверхностному, но упрямому, подтвержденному практикой мнению). Если кто-то может разубедить, будет здорово, но в применении к данному решению не очень важно, поскольку все выше приведенные конструкции просто не позволяют коду основного скрипта нормально инициализироваться и окно с кнопками просто не появится, но когда вы это исправите:
  4. не отображаются подсказки
  5. внезапно, для строки нет функции includes, ее просто нет, так что используем indexOf по полной!, пока ее тоже не убрали(
  6. естественно, на linux регулярные выражения, используемые мной при подготовке текста ГТР доступны только с версии 8.3.23, а меня интересует совместимость с 8.2.13, поэтому регулярные выражения 1С я лишь попробовал, нашел, что они работают исправно, но с одним ограничением: они более чувствительны или скорее требовательны к экранированию специальных символов и там где обычная регулярка отловит } в тексте именно как фигурную скобку, регулярное выражение 1С вылетит с ошибкой, пока вы не сделаете \}, чтобы показать, что это просто фигурная скобка и ничего более. Но я это только на 8.3.23 проверял, на 24 и далее поведения не знаю.

В общем, если нужен линукс, то организовать это не сложно, возможно и с ограничениями, как и везде на линукс. Кстати, если кто не знал: на управляемых формах 1С нажатие клавиш Ctrl+Alt+Shift+F12, что на линукс, что на windows приводит к отображению горячо любимой всеми причастными к веб-разработке Консоли разработчика. Применительно к данному случаю консоль нужно вызывать (повторюсь - на управляемых формах), предварительно щелкнув в область за пределами редактируемого сейчас кода, снизу, например, по крайней мере, так срабатывает стабильнее.

 

Этап 8. Заключительный

Итак, код исправно работает, оболочка редактора, написанная на JavaScript, успешно встроена в 1С. Время радоваться! Но нет. Есть здесь капля дегтя в бочке меда. За две-три недели экспериментов встречено минимум два случая, когда на месте панели не оказывалось ничего. Вплоть до перезагрузки 1С, когда все опять свистело и вертелось. Но пятнышко-то ... осталось. Одну из возможных причин помогает проработать эксперимент с управляемыми формами. У них не все так кристально, как с обычными, поскольку нет метода УстановитьТекст, который заново инициализирует элемент управления, запуская встроенные стили и скрипты или я плохо старался его найти (но мне и не надо, хм, а здесь используется альтернативный подход). Так вот, при перезаписи свойства innerHtml у основного элемента (в замену такового метода) скрипт инициализации редактора сам не запускается. Поэтому было предусмотрено окно, в котором наивному пользователю будет предложено поработать рычагом, он же дергалка, он же "кривой стартер":

 

 

Попутно, обнаружен и более быстрый (окно с этими кнопками не успевает появиться) метод инициализации: подписка на событие load вместо стандартной инициализации методом jquery. Так что, возможно, картинка выше никогда не появится, но практика и время покажет.

На этом все, базу и основные файлы тоже выкладываю: экспериментируйте, пользуйтесь, радуйтесь, как я радовался при проработке данного перекрестного проекта. Действительно было очень интересно, не думаю, что мои порывы в технологии web на этом закончены, они все ближе, даже на таких, казалось бы устаревших проектах как УПП 1.3. Все самое интересное впереди!

 

Этап 9 Регулярные выражения

Считаю, эта статья была бы неполной без некоторого экскурса в регулярные выражения, потому что здесь без них никуда. Так что попытаюсь упорядочить свои полученные знания, да и кому-то пригодится, может. Заодно обновлюсь на 23 версию со встроенными регулярками (СтрНайтиВсеПоРегулярномуВыражению, СтрНайтиПоРегулярномуВыражению и (Ух-ты!) СтрЗаменитьПоРегулярномуВыражению)

Задача 1. Ищем последовательность с открывающим и закрывающим символом. Поиск атрибута html со значением (если вас просто интересует значение атрибута, никто не запрещает получить его через свойство Attributes любого элемента, но здесь атрибуты нужно обработать все и произвольно).

Пример текста: <p class="MsoNormaldop0"><span class="class1dop6">

Вызов: Совпадения = СтрНайтиВсеПоРегулярномуВыражению(ТекстHTML,  "class=""[^""]*", Истина, Истина);

Объясняю: ищем объявление атрибута, поэтому начало - class=" (двойные кавычки для экранирования строк 1С, на сайте regex101.com, например, их экранировать не нужно), далее мы знаем, что объявление заканчивается теми же кавычками, поэтому включаем фразу ([^""]*), которая означает - квадратные скобки для объявления набора символов, в котором доступно все кроме (^) кавычек (") неограниченное число раз (*). Итогом два значения: class="MsoNormaldop0 и class="class1dop6, где значение удобно брать, начиная с кавычек.

Задача 1.1 Закрепляем. Убираем все открытия и закрытия тэгов, чтобы скрыть их предпросмотра

Пример текста: <p class="MsoNormaldop0" align="center">Должность (специальность, профессия)<o:p></o:p></p>

Вызов: Описание = СтрЗаменитьПоРегулярномуВыражению(Описание, "<[^>]*>", "", Истина, Истина);

Объясняю: тег открывается "<" и закрывается ">", поэтому ищем открытие тега, затем неограниченное число любого символа кроме ">" ([^>]*) и сам символ закрытия. Результатом вызова будет строка: Должность (специальность, профессия). При этом последнее закрытие в нашем случае может быть неполным, поэтому дополняем вызовом с таким шаблоном: "<[^>]*$", в котором последний символ ($) означает конец строки. Так <p class="MsoNormaldop0" align="c будет заменен на пустую строку.

Задача 2. Поиск буквенных последовательностей. Например, поиск объявления стиля в формате css.

Пример текста: td.class1dop13 { border: 1px solid #000000; padding: 0cm 0.05cm }

Вызов: Совпадения = СтрНайтиВсеПоРегулярномуВыражению(ТекстHTML, "\w*\.[a-zA-Z]{2,}\w*[^\}]*\}", Истина, Истина);

Объясняю: (\w*) - последовательность букв, цифр или знака подчеркивания (в нашем случае тег), далее точка, где обратный слэш используется для экранирования (\.), далее класс, то есть две и более букв ([a-zA-Z]{2,}), где {2,} означает от 2 до бесконечности, затем опять цифры\буквы (\w*) и вообще все, включая перенос строки, но кроме закрывающей фигурной скобки, которую тоже экранируем ([^\}]*), ну и сама, экранированная, скобка. Без экранирования, напоминаю, выпадает ошибка 10301 (U_REGEX_RULE_SYNTAX). В результате приводимая строка будет выбрана в таком же виде. Если нужны только цифры, используйте \d.

Задача 3. Учимся считать - это нужно! Например, при поиске объявления метода кнопки

Пример текста: {
                                                    key: "HtButtonMethod",
                                                    value: function() { 
                                                          this.$editor.find(".note-editable").focus(), CheckItModificated() 
                                                    }
                                            }, {

Вызов: ШаблонМетода = "\{(.|\n){0,60}key.{1,10}HtButtonMethod(.|\n){1,300}\}, ?\{"; 
Совпадения = СтрНайтиВсеПоРегулярномуВыражению(ТекстHTML, ШаблонМетода, Истина, Истина);

Объясняю: открывающая скобка (\{), затем любые символы или перенос строки ((.|\n){0,60}), внимание, в количестве до 60 символов.

Зачем это? А если символов будет 61? Придется ставить по 61 символ, потому что если поставить *, то будет ошибка 10311 (U_REGEX_STACK_OVERFLOW), да и обычные регулярки тоже работать не будут. Это общее поведение. Причем здесь есть интересный момент: вы можете поставить несколько блоков {0,Число}, но если их общая сумма символов перевалит за 2000, то сайт regex101, например, выдаст engine error, а 1С - нет, справляется, но тогда в эти 2000 символов может попасть еще несколько методов, с открывающими и закрывающими скобками, да и тупит она при этом знатно, так что берем по минимуму.

Далее key и до 10 любых символов, ибо (.{1,10}), затем ... , потом один или 0 пробелов ( ?) - делаем для учета минификации\украшения кода, ну и закрывающая скобка (\{), все!

Обычные формы ЧТВТТИП JavaScript Совместимость Linux Свои кнопки

См. также

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    127825    689    389    

740

Infostart PrintWizard - создание и редактирование печатных форм в 1С 8.3

Пакетная печать Печатные формы Инструментарий разработчика Платформа 1С v8.3 Запросы 1С:Зарплата и кадры бюджетного учреждения 1С:Конвертация данных 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 Платные (руб)

Инструмент, позволяющий абсолютно по-новому взглянуть на процесс разработки печатных форм. Благодаря конструктору можно значительно снизить затраты времени на разработку печатных форм, повысить качество и "прозрачность" разработки, а также навести порядок в многообразии корпоративных печатных форм.

18000 руб.

06.10.2023    8578    25    6    

47

Infostart УДиФ: Управление данными и формами 1С

Инструменты администратора БД Инструментарий разработчика Роли и права Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Расширение позволяет без изменения кода конфигурации выполнять проверки при вводе данных, скрывать от пользователя недоступные ему данные, выполнять код в обработчиках. Не изменяет данные конфигурации, легко устанавливается практически на любую конфигурацию на управляемых формах.

10000 руб.

10.11.2023    4874    13    2    

38

SALE! 15%

PowerTools

Инструментарий разработчика Инструменты администратора БД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Россия Платные (руб)

Универсальный инструмент программиста для администрирования конфигураций. Сборник наиболее часто используемых обработок под единым интерфейсом.

3600 3060 руб.

14.01.2013    179114    1086    0    

863

Бустер Конвертации данных 3 (Infostart Toolkit)

Инструментарий разработчика 8.3.14 1С:Конвертация данных Россия Платные (руб)

Расширение для конфигурации “Конвертация данных 3”. Добавляет подсветку синтаксиса, детальную контекстную подсказку, глобальный поиск по коду.

15000 руб.

07.10.2021    15166    3    12    

38

Богатый редактор картинок, хранимых в базе, с возможностью РИСОВАНИЯ. Редактор внешних файлов картинок. Объект, расширяющий возможности работы с картинками из встроенного языка (Три в одном) + Обработка «Стандартизация картинок»

Работа с интерфейсом Рабочее место Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Обработка предназначена для редактирования картинок в режиме «Предприятие», с возможностью РИСОВАТЬ на них. Поддерживается работа как в обычных формах (толстый клиент) так и на управляемых формах (тонкий клиент). Обработка позволяет редактировать как картинки, хранимые в базе, так и графические файлы с диска на файловой системе. Помимо базовых функций (изменение размеров, преобразование формата, обрезание картинки, повороты и т.п.) – редактор имеет богатый набор инструментов для рисования. Доступна функция вставки изображения из буфера обмена. Также обработка может быть использована из встроенного языка как объект для редактирования картинок. Объект может быть использован: на стороне клиента, на стороне сервера, из внешнего соединения. Данная обработка будет особенно полезна тем, кто вносит картинки в базу (изображения номенклатуры, фотографии физических лиц и т.п.). Функционал реализуется с использованием JavaScript и бесплатного ПО ImageMagick (без использования внешних компонент).

6000 руб.

16.01.2015    62150    43    59    

81

Многопоточность. Универсальный «Менеджер потоков» 2.1

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Восстановление партий или взаиморасчетов, расчет зарплаты, пакетное формирование документов или отчетов - теперь все это стало доступнее. * Есть желание повысить скорость работы медленных алгоритмов! Но... * Нет времени думать о реализации многопоточности? * о запуске и остановке потоков? * о поддержании потоков в рабочем состоянии? * о передаче данных в потоки и как получить ответ из потока? * об организации последовательности? Тогда ЭТО - то что надо!!!

5000 руб.

07.02.2018    100069    239    97    

298

1С HTML Шаблоны / HTML Templates

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Быстрая и удобная обработка для работы с шаблонами HTML. Позволяет легко и быстро формировать код HTML.

2040 руб.

27.12.2017    28489    4    10    

16
Оставьте свое сообщение