С выходом технологической платформы 1С:Предприятие 8.3.14 разработчики столкнулись с масштабным изменением: встроенный движок отображения HTML-документов был заменен с устаревшего Internet Explorer (MSHTML) на современный кроссплатформенный WebKit. Это нововведение принесло полноценную поддержку стандартов HTML5, CSS3, SVG, значительно ускорило рендеринг страниц и обеспечило идентичное отображение форм во всех операционных системах и веб-клиентах. Однако обратной стороной медали стало то, что старый код интеграции JavaScript и 1С перестал работать.
В этой статье мы подробно разберем, почему возникает ошибка при обращении к контексту браузера, как правильно заменить устаревшие свойства, и рассмотрим ключевые архитектурные изменения при взаимодействии 1С и JavaScript в новой модели WebKit.
Рассмотрим классический пример интеграции внешнего HTML-редактора (например, популярного текстового редактора CKEditor) в форму 1С. В старых версиях платформы (до 8.3.14) для получения или записи данных в редактор использовался следующий код:
// Этот код отлично работал в среде Internet Explorer, но вызывает ошибку в WebKit
html = Элементы.Body.Документ.parentWindow.eval("CKEDITOR.instances.editor1.getData();");
При выполнении этой строки на новых версиях платформы система выдает ошибку. Происходит это по двум ключевым причинам:
parentWindow является специфичным (нестандартным) свойством объекта document в Internet Explorer. Современные браузеры, включая движок WebKit, не поддерживают это свойство. Вместо него по спецификации W3C необходимо использовать стандартное свойство defaultView.eval() из кода 1С к контексту WebKit теперь заблокирован или ограничен из-за ужесточения политик безопасности и изоляции контекстов исполнения (песочницы).Давайте разберем по шагам, как переписать этот и сопутствующие механизмы под требования современной платформы.
Для доступа к глобальному объекту окна (аналогу window в JavaScript) из кода 1С вместо свойства parentWindow мы должны использовать defaultView. Это стандартный способ получения ссылки на объект окна, которому принадлежит документ.
Посмотрим, как изменится код получения данных из редактора CKEditor:
// Было (до 8.3.14):
ДанныеHTML = Элементы.Body.Документ.parentWindow.CKEDITOR.instances.editor1.getData();
// Стало (после 8.3.14):
ДанныеHTML = Элементы.Body.Документ.defaultView.CKEDITOR.instances.editor1.getData();
Аналогично переписывается и код для инициализации или передачи данных обратно в редактор. Посмотрим на рабочий пример передачи текста в редактор с обработкой обратного вызова (callback):
Элементы.Body.Документ.defaultView.CKEDITOR.instances.editor1.setData(ПередаваемыйHTML, "function()
|{
| this.checkDirty();
|});");
Использование defaultView полностью восстанавливает доступ к глобальным переменным и библиотекам, объявленным на веб-странице.
В некоторых сценариях разработчикам требуется динамически выполнять произвольный JavaScript-код, сформированный в 1С. Попытка вызвать defaultView.eval("код") напрямую может завершиться ошибкой безопасности.
Чтобы обойти это ограничение, мы рекомендуем использовать архитектурный паттерн "функция-обертка". Суть метода проста: внутри самого HTML-документа (в тегах <script>) объявляется стандартная функция, которая принимает строку кода и выполняет её локально в контексте страницы. Из 1С мы вызываем уже не системный eval, а нашу собственную безопасную функцию.
Разберем этот пример на практике. Добавим в HTML-код страницы следующую функцию:
function executeJsFrom1C(codeString) {
try {
return eval(codeString);
} catch (e) {
console.error("Ошибка выполнения кода: " + e.message);
return null;
}
}
Теперь из модуля формы 1С мы можем безопасно вызывать выполнение любого скрипта через нашу обертку:
КодДляВыполнения = "CKEDITOR.instances.editor1.getData();";
Результат = Элементы.Body.Документ.defaultView.executeJsFrom1C(КодДляВыполнения);
Простая замена свойств — это лишь верхушка айсберга. Переход на WebKit принес глубокие изменения в объектную модель, которые могут полностью сломать более сложные интеграции. Проанализируем ключевые особенности взаимодействия 1С и нового движка.
В старой модели на базе IE свойство Документ у поля HTML-документа возвращало полноценный COMОбъект. Разработчик мог обращаться к специфическим интерфейсам Windows, манипулировать DOM-деревом напрямую через COM-методы и использовать специфичные библиотеки Microsoft.
В WebKit тип свойства Документ изменился на ВнешнийОбъект. Это означает следующее:
defaultView.В старых конфигурациях для передачи события из браузера обратно в 1С часто использовался механизм externalForm. Разработчики передавали контекст формы 1С в JavaScript следующим образом:
// В коде 1С:
Элементы.ПолеHTML.Документ.parentWindow.externalForm = ЭтаФорма;
После этого внутри JavaScript-кода можно было напрямую вызвать экспортный метод формы 1С: externalForm.ИмяПроцедуры(Параметры). В WebKit этот механизм полностью заблокирован и не работает! Попытка передать сложный объект формы 1С в среду WebKit приведет к тому, что объект превратится в undefined.
Рассмотрим два надежных альтернативных способа организации обратной связи:
Этот способ основан на том, что событие нажатия на элемент страницы перехватывается платформой 1С. Мы можем создать на странице скрытый элемент (например, тег <div>), записывать в его атрибуты или текст нужные данные из JS, а затем программно вызывать клик по нему.
Разберем реализацию по шагам.
Шаг 1. Размещаем скрытый элемент в HTML-коде нашей страницы:
<div id="comm_bridge" style="display:none;" data-payload=""></div>
Шаг 2. В JavaScript пишем функцию отправки сообщения в 1С:
function sendMessageTo1C(actionName, data) {
var bridge = document.getElementById('comm_bridge');
// Упаковываем данные в JSON-строку
var packet = { action: actionName, payload: data };
bridge.setAttribute('data-payload', JSON.stringify(packet));
// Эмулируем клик, который перехватит 1С
bridge.click();
}
Шаг 3. В 1С создаем обработчик события ПриНажатии для Поля HTML документа:
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Проверяем, что клик совершен по нашему "мосту"
Если ДанныеСобытия.Элемент.id = "comm_bridge" Тогда
// Отменяем стандартное поведение браузера
СтандартнаяОбработка = Ложь;
// Считываем упакованные данные из атрибута элемента
ДанныеПакета = Элементы.ПолеHTML.Документ.getElementById("comm_bridge").getAttribute("data-payload");
// Десериализуем JSON в структуру 1С
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ДанныеПакета);
РезультатСобытия = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Вызываем нужный обработчик в зависимости от действия
Если РезультатСобытия.action = "saveText" Тогда
ОбработатьСохранениеТекста(РезультатСобытия.payload);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Второй популярный метод заключается в изменении адреса страницы на специальную псевдо-ссылку, параметры которой парсятся на стороне 1С в событии ПриИзменении или ПриНажатии.
В JavaScript вызываем смену адреса:
window.location.href = "1c://action?name=save&payload=" + encodeURIComponent(myData);
В 1С перехватываем изменение навигации, парсим строку адреса, извлекаем параметры и отменяем переход, чтобы страница не перезагрузилась.
При передаче сложных объектов (массивов, структур, соответствий) из JavaScript напрямую в 1С через возвращаемые значения функций, вы столкнетесь с тем, что они приходят в виде типов ВнешнийОбъект. Обращение к элементам таких коллекций в 1С может вызывать синтаксические трудности (например, обращение к индексам массива может требовать строковых ключей вида Результат["0"] вместо числовых Результат[0]).
Золотое правило интеграции: Всегда сериализуйте сложные данные в формат JSON при передаче границы сред "1С <-> JS". Это избавит вас от проблем несовместимости типов.
JSON.stringify(object).ПрочитатьJSON() и ЗаписатьJSON().Движок Internet Explorer сквозь пальцы смотрел на безопасность при работе с локальными файлами. С переходом на WebKit вы столкнетесь со строгой политикой песочницы (Sandbox). Браузер заблокирует прямые попытки подключить внешние скрипты или стили по абсолютным путям файловой системы (например, <script src="C:/MyScripts/ckeditor.js">).
Для решения этой проблемы придерживайтесь следующих рекомендаций:
<img src="data:image/png;base64,...">.Обратите внимание на то, что старый встроенный браузер на базе IE автоматически наследовал системные настройки прокси-сервера из операционной системы Windows. Новый движок WebKit эти настройки игнорирует. Если ваши скрипты внутри поля HTML-документа обращаются к внешним веб-ресурсам и требуют работы через прокси, параметры прокси-сервера теперь необходимо принудительно прописать в конфигурационном файле платформы inetcfg.xml.
Перевод поля HTML-документа на модель WebKit требует от разработчика понимания современных веб-стандартов. Давайте зафиксируем ключевые шаги для успешной миграции кода:
.parentWindow на стандартные .defaultView.eval() из кода 1С в пользу вызова локальных функций-оберток, объявленных внутри HTML-страницы.externalForm. Для отправки данных из JS в 1С используйте механизм перехвата клика по скрытому элементу (Click-хак) или кастомные схемы URI.Применение этих простых правил позволит сделать ваши интерактивные HTML-интерфейсы в 1С стабильными, быстрыми и полностью кроссплатформенными!