Все началось с того, что возникла задача: "Хотим, в УТ, вводить форматированное описание для товара, чтобы оно потом летело в интернет-магазин", потому что стандартное описание для товара прилетает сплошной строкой без переносов и выглядит очень не очень. Сразу возникло желание использовать форматированный документ, там и редактор простенький есть, и в HTML можно выгрузить. Но как только я показал сформированный форматированным документом HTML веб-разработчикам, они сразу замахали руками и сказал, что так не пойдет. На сайте уже есть свои стили для отображения нужных блочных элементов и поведение такого рода текста может стать непредсказуемым.
Функция ПолучитьHTML, форматированного документа возвращает полностью сформированную страницу HTML, со всей структурой тегов, а что самое неприятное, с inline-стилями. Выглядит это так.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="format-detection" content="telephone=no" />
<style type="text/css">
body{margin:0;padding:8px;}
p{line-height:1.15;margin:0;white-space:pre-wrap;}
ol,ul{margin-top:0;margin-bottom:0;}
img{border:none;}
li>p{display:inline;}
</style>
</head>
<body>
<p><span style="text-decoration: underline;">Абзац</span></p>
<p><span style="font-weight: bold;">жирный текст</span></p>
<p><span style="color: #ff0000;font-weight: normal;">красный текст</span></p>
<p><br></p>
</body>
</html>
И если получить содержимое тега body это простая задача, то заниматься парсингом и вырезать атрибуты стиля из тегов совсем не хотелось.
TinyMCE же возвращает приятного вида верстку. Позволяя себе inline-стили только в случае с цветом, что уже гораздо лучше.
<p>Абзац</p>
<p><strong>Жирный</strong></p>
<p><span style="color: #ff0000;">Красный</span></p>
Было принято решение интегрировать сторонний редактор текста TinyMCE. К тому же опыт его интеграции сообществом 1С уже довольно большой.
Может быть это было ошибкой тогда, и нужно было просто парсить текст сформированный форматированным документом, но имеем, что имеем.
1.Особенности решения
- Так как 1С не разрешает подгружать на страницу в поле HTML локальные файлы из файловой системы, для этого обязательно нужен веб-сервер или хотя бы адрес этого файла во временном хранилище, то положить js-библиотеку Tiny рядышком с 1С и подгружать ее в заголовках HTML документа нельзя — придется сформировать еще и файл с HTML-версткой который внутри себя формирует готовое окно редактора и его уже подключать к HTML документу.
Вообще, на самом деле, подгрузить библиотеку, если получить для нее адрес в хранилище, можно, если бы она была скомпилирована в один файл, а Tiny помимо основной библиотеки содержит еще и js-файлы плагинов, менеджер стилей, и сами файлы стилей, русификаторов, иконок и т.д., и как сами понимаете это довольно сильно усложняет задачу. В одно время даже возникла идея скомпилировать все это добро в один файл и не знать проблем, но разбираться в инструментах было долго. Потом был найден TinyMCE Builder на официальном сайте, который компилирует весь js в один файл и это же было бы маленькой победой, если бы он так же поступал с css, но нет, css по-прежнему лежал рядом в нескольких папках.
- TinyMCE для окна редактирования создает iframe, который сам по себе является встроенным в страницу HTML-документом, так что события возникающие в этом iframe 1С не может отследить, об этом ниже.
- Конфигурация УТ 11.4 на момент разработки имела режим совместимости 8.3.12, так что по факту сейчас она использовала IE в качестве встроенного браузера, но дальнейшее обновление подразумевало переход на новые версии, которые уже используют web-kit.
2. Первые шаги.
Основные отличия в работе с web-kit:
- Основной объект ПоляHTML теперь имеет другую структуру и, для того чтобы работать с содержимым страницы нужно использовать свойство defaultView
Элементы.ПолеHTML.Document.DefaultView
раньше для этого использовалось свойство parentWindow
Элементы.ПолеHTML.Document.parentWindow
-
Запрет на использование eval, который раньше повсеместно использовался для вызова JS кода. Что-то вроде этого
Элементы.ПолеHTML.Document.parentWindow.eval("alert('Вызов кода из 1С')")
Зато можно обращаться к методам напрямую из 1С.
Элементы.ОписаниеHTML.Document.DefaultView.НазваниеМетодаJS();
И я быстро соорудил оберточные функции для всех методов Tiny которые мне нужны.
function GetText(){ return tinyMCE.activeEditor.getContent({format: "text"}); } function SetText(html){ return tinyMCE.activeEditor.setContent(html); } function GetHTML(){ return tinyMCE.activeEditor.getContent(); }
К которым дальше обращался из 1С так
ОбъектHTML = Элементы.ОписаниеHTML.Document.DefaultView; ОписаниеHTMLДляСайта = ОбъектHTML.GetHTML(); Описание = ОбъектHTML.GetText();
Хотя можно было бы обойтись и прямыми обращениями к объекту редактора, например так
Элементы.ПолеHTML.Документ.defaultView.tinyMCE.activeEditor.getContent()
Сразу была скачана обработка из публикации (автору отдельный респект), которая показала мне много интересностей. Она более-менее работала на IE, но на webkit не работал копи-паст, сначала это вызвало ступор, но дальше стало понятно, что это из-за iframe поле HTML не активировалось при нажатии внутри него, так как нажатие фактически происходило во вложенном документе HTML, события которого где-то застревали по пути к 1С. И потому если нажать Ctrl+C в одном месте формы и попытаться вставить внутри поля редактора, то текст вставится в том поле откуда был копирован потому что поле HTML документа не активируется. То же происходит и в обратном случае, сочетания клавиш для копирования и вставки не работают.
Сначала возникла мысль, что это косяк Tiny, и он блокирует непосредственную вставку из буфера, как CKEditor, который предлагает отдельное окно для вставки из буфера. Но проверить это было довольно легко, я создал пустой документ с одним полем ввода и попробовал копирования и вставки
Как видите все работает. Значит проблема где-то в Tiny или во взаимодействии с 1С.
3. Решение
Для решения проблемы с взаимодействием браузера и 1С был применен обычный прием, я создал невидимую кнопку на странице HTML, и планировал нажимать на нее из JS при возникновении нужных событий внутри страницы, которые 1С перехватывала бы в событии ПриНажатии HTMLДокумента. Но при каком событии осуществлять программное нажатие?
Верстка выглядит примерно так:
<body>
<textarea id="editor"></textarea>
<button id="button1c" style="display: none"></button>
</body>
И функция для вызова события нажатия на кнопку
function clickButton()
{
button1c.click();
}
Раньше можно было передать объект формы 1С в поле HTML как объект, и из-за того, что IE подключался к 1С по COM, форма как-то сама конвертировалась в понятный для IE объект и можно было вызывать экспортный функции формы 1С прямо из кода JS. Теперь так нельзя.
Была изучена документация по API Tiny, и найдена конструкция для перехвата обработчиков событий и подходящая комбинация событий, которая должна активировать поле HTML документа
tinymce.activeEditor.on('click', function(e){clickButton(e)});
tinymce.activeEditor.on('KeyDown', function(e){clickButton(e)});
Нужно поместить этот код в том месте, когда Tiny уже проинициализровался. Я сделал это в обработчике onload объекта window. Но можно сделать более красиво и разместить код при инициализации Tiny в параметре:
init_instance_callback
Теперь все должно быть в порядке. И форма должна работать как надо…
Стало сильно лучше, поле HTML действительно стало активироваться, но не всегда, почему-то некоторые нажатия не вызывали перехода фокуса к полю
На этой записи видно, что если нажать в строку, где мигает курсор, то фокус поля работает как нужно, но если нажать ниже, то активации поля не происходит.
Это был досадный артефакт, и попытки понять, что происходит не давали никакого решения. Я выводил алерты в обработчик и алерты выводились, но 1С не реагировала на событие ПриНажатии
Внезапно пришла в голову идея, а что, если 1С не успевает обработать событие происходящее в поле, что если немного затормозить выполнение JS скрипта, и посмотреть, что получится. Быстро была реализована функция паузы в JS с помощью промисов и async await. Как видите в JS ее тоже нет по умолчанию и ничего, живут люди)
function sleep(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function clickButton(e){
await sleep(1);
button1c.click();
}
Здесь я устанавливаю задержку в одну миллисекунду, перед нажатием на кнопку. И вуаля, все заработало. 1С стала вовремя обрабатывать нажатие на кнопку.
4. Допиливаем обмен
Так как для хранения нового описания в формате HTML, был добавлен новый реквизит к справочнику, то нам нужно подменить значение типового поля при выгрузке. Для этого в модуле ОбменССайтомПереопределяемый, добавляем в расширение функцию ПолучитьТекстыЗапросовКаталог, и пишем там
ТекстыЗапросов.Номенклатура = СтрЗаменить(ТекстыЗапросов.Номенклатура, "Номенклатура.Описание",
"Номенклатура.ОписаниеHTML_ОписаниеHTMLДляСайта");
На этом все. Запускаем обмен и все работает, остается только внести изменения на сайте, если это нужно, чтобы описание товара воспринималось как верстка а не как строка.
Резюме
На данном примере я попробовал взаимодействие JS WebKit и 1С, пособирал грабли и нашел решение.
Возможно для решения этой задачи было проще распарсить и очистить HTML-текст из форматированного документа, но было бы не так интересно и возможно получило бы какие-то проблемы при каких-то сложных вариантах форматирования)
Спасибо, что прочитали. Прикладываю к статье более-менее универсальную реализацию этого механизма для расширения функционала обмена УТ и сайта.
(0) нужно больше таких материалов про WebKit.
Плюсую.
(1) дополнил текст некоторыми пояснениями про изменения в вызове кода из 1С)
(2) Я также присоединяюсь. Автор, спасибо за статью, позновательно.
Ах… Вы! А я на кликбейт попался))
«Так как 1С не разрешает подгружать на страницу в поле HTML локальные файлы из файловой системы»
Неправда, позволяет.
У меня есть работающий пример интеграции, где структура папок TinyMCE скидывается на диск, а потом в поле HTML документа прописываем ссылку на Индекс.
Костыли с буфером обмена решаются выключением аддона Paste
(5) ссылку на индекс? это значит, что у вас уже есть сформированный файл с версткой лежащий в файловой системе, в который подключена библиотека?
(6). Да. Готовый HTML с подключённым редактором и стилями. В который контент можно загружать уже функциями 1С
(7) я не зря использовал слово «подгружать») Сформировать внутри 1С текст верстки страницы и написать там что-то вроде <sc ript src=»файловый путь»>, не удастся, получить доступ к локальному файлу библиотки из поля HTML мы не можем. Потому единственный вариант, без cdn или веб-сервера, это заранее сформированная страница, которая уже содержит все подключения, что я и использую в своей разработке
(8) А зачем подключать содержимое редактора как файл на диске? Мы можем загрузить содержимое прямо в редактор из 1С.
(9) Можем, но это особенность поляHTML 1C, которую я описал) для тех кто не в теме, может быть непонятным, почему верстка написанная файлом HTML запускается в обычном браузере, но при этом будучи скопированной в поле HTML не работает, и если делать интеграцию локальных скриптов в полеHTML то можно потерять время.
У меня тоже в вебките не всегда работает событие приНажатии, хз почему. Обошел функцией добавитьОбработчик на onclick и ondblcklick. С ней все работает прекрасно.
Поддержу автора, а то все лайкают, но никто не скачивает )
К сожалению web-kit пока сыроват. И сделать что нить крутое и стабильное пока нельзя. По типу такого…
(13)А с какими трудностями столкнулись? Выглядит как встроенная веб-версия whatsapp
(14)1) На разных браузерах разное отображение страниц. Т.е. верстка может поехать
2) Заблокирована работа из внешних устройств. Например камера и микрофон не работает
3) Веб сокеты не работают
4) Костыльное выполнение скриптов на странице
5) Глюки работы с фреймами
6) Какой то баг с кодировками. Например не удается передать файл, в котором русское название.
Это так, для начала.
.
(12)Спасибо за поддержку)
Поставил расширение,
http://prntscr.com/qb65xo
У меня такие глюки:
При нажатии правой кнопки вместо изображения в левом правом углу появляется окошко с кнопками «вперед» «назад»
Иногда при открытии просто черное поле
Сталкивались? Есть ли решение?
(18)а какая версия платформы?