Начиная с версии платформы 1С:Предприятие 8.3.14, разработчики столкнулись с глобальным изменением во встроенном элементе ПолеHTMLДокумента. Платформа перешла со старого и привычного движка Internet Explorer (Trident) на современный кроссплатформенный движок WebKit (Chromium). Это нововведение значительно расширило возможности визуализации интерфейсов, но сломало множество старых механизмов интеграции 1С и JavaScript.
В этой статье мы подробно разберем, как адаптировать ваш код под требования WebKit, научимся правильно вызывать JS-функции из встроенного языка 1С, рассмотрим частые ошибки инициализации асинхронных библиотек (например, Яндекс.Карт) и разберем архитектуру обратного взаимодействия.
В старых версиях платформы 1С для обращения к глобальной области видимости JavaScript (к объекту window) использовалось свойство parentWindow объекта Документ. Типичный вызов выглядел следующим образом:
// Так код работал в старых версиях (до 8.3.14)
Элементы.HTML_документ.Документ.parentWindow.func('Параметр');
С переходом на WebKit свойство parentWindow, как и метод прямой оценки строк window.eval() на уровне интерфейса интеграции, были упразднены или заблокированы из соображений безопасности и стандартизации. В новой модели для доступа к глобальному контексту окна загруженного HTML-документа необходимо использовать свойство defaultView.
Давайте разберем по шагам, как должен выглядеть правильный вызов внешней функции.
Для того чтобы вызвать объявленную в вашем HTML-документе функцию findAdress(address) и передать ей текстовый параметр из 1С, используйте конструкцию следующего вида:
стрАдрес = "Витебск, Московский проспект, д. 5";
Элементы.ЯндексКарта.Документ.defaultView.findAdress(стрАдрес);
Обратите внимание на несколько критически важных нюансов при написании этого кода:
‘ или ’, либо кавычки-ёлочки). Это приведет к синтаксической ошибке компилятора 1С: Неправильная константа типа Дата. Используйте только стандартные прямые одиночные (') или двойные (") кавычки.findAdress, то вызов FindAdress или findadress из кода 1С завершится ошибкой или проигнорируется системой.В некоторых случаях разработчикам необходимо динамически собирать и выполнять целые блоки JS-кода из 1С в виде строки. Поскольку прямой вызов eval на уровне объекта Документ в WebKit заблокирован, мы можем применить изящный обходной путь.
Для этого внутри самого HTML-файла в теге <script> объявим простую функцию-обертку, которая будет принимать строку кода и выполнять ее локально:
function runJavaScriptEval(codeString) {
return eval(codeString);
}
Теперь из модуля управляемой формы 1С мы можем передавать абсолютно любой JS-код на выполнение через нашу обертку:
КодНаВыполнение = "console.log('Выполняю произвольный JS-код из 1С!'); MyMap.setZoom(10);";
Элементы.ЯндексКарта.Документ.defaultView.runJavaScriptEval(КодНаВыполнение);
Очень часто программисты сталкиваются с ситуацией: синтаксических ошибок в коде нет, вызов defaultView.имяФункции() отрабатывает без исключений в 1С, но визуально на форме ничего не происходит (например, не ставится метка на карте). Выясним первопричину этой проблемы.
Событие формы 1С ПриОткрытии или событие элемента ДокументСформирован свидетельствуют лишь о том, что платформа загрузила базовую DOM-структуру HTML-страницы. Однако тяжелые внешние библиотеки, такие как API Яндекс.Карт или Google Maps, загружаются асинхронно.
Если вы вызываете функцию findAdress() до того, как библиотека Яндекс.Карт полностью загрузилась в контексте страницы, логика функции внутри блока ymaps.ready() попросту не сработает или упадет с ошибкой, которая не будет видна в 1С.
Для надежного решения этой проблемы необходимо реализовать механизм обратной связи (сигнализации) от HTML-страницы к 1С о полной готовности всех скриптов.
В старых версиях под IE разработчики передавали контекст формы через конструкцию defaultView.externalForm = ЭтотОбъект;. В WebKit из-за жесткой изоляции процессов и отказа от COM-технологий этот способ больше не работает (переменная в JS примет значение undefined).
Единственным штатным и кроссплатформенным способом передачи сигналов и данных из JavaScript в 1С является использование скрытых элементов страницы и перехват событий клика.
Давайте реализуем эту схему по шагам:
Шаг 1. Создаем скрытые элементы в HTML-документе. Добавим специальную невидимую ссылку, которая будет служить «кнопкой вызова» 1С, и скрытое поле для передачи параметров:
<!-- Скрытые элементы для связи с 1С -->
<a id="SignalTo1C" style="display:none;"></a>
<input type="hidden" id="DataTransfer" value="" />
Шаг 2. Пишем функцию отправки сигнала в JavaScript. Функция будет записывать полезную нагрузку в скрытое поле и эмулировать клик по ссылке:
function sendSignalTo1C(actionName, payload) {
var dataInput = document.getElementById('DataTransfer');
var signalLink = document.getElementById('SignalTo1C');
// Формируем пакет данных (можно в формате JSON)
var packet = {
action: actionName,
data: payload
};
dataInput.value = JSON.stringify(packet);
// Эмулируем клик для вызова события в 1С
signalLink.click();
}
Шаг 3. Сигнализируем о готовности карты. Модифицируем стартовую инициализацию нашей карты так, чтобы при успешном развертывании API отправлялся сигнал в 1С:
ymaps.ready(init);
function init() {
MyMap = new ymaps.Map('map', {
center: [55.753994, 37.622093],
zoom: 9
});
// Карта готова! Отправляем сигнал в 1С
sendSignalTo1C("MapLoaded", "Успешно");
}
Шаг 4. Обрабатываем событие на стороне 1С. В свойствах элемента формы ПолеHTMLДокумента (в нашем примере — ЯндексКарта) подключаем обработчик события ПриНажатии (в англоязычной версии — onclick). Код обработчика будет выглядеть так:
&НаКлиенте
Процедура ЯндексКартаПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Проверяем, что событие пришло от нашего скрытого элемента-сигнализатора
Если ДанныеСобытия.Element.id = "SignalTo1C" Тогда
// Отменяем стандартное поведение браузера на клик по ссылке
СтандартнаяОбработка = Ложь;
// Получаем документ страницы
ДокументHTML = Элементы.ЯндексКарта.Документ;
// Считываем сериализованные данные из скрытого инпута
ДанныеИзJS = ДокументHTML.getElementById("DataTransfer").value;
// Читаем JSON-пакет
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ДанныеИзJS);
ПакетДанных = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Если ПакетДанных.action = "MapLoaded" Тогда
// Теперь мы точно уверены, что API карт загружено!
// Можем безопасно активировать кнопки поиска или передать первый адрес
Объект.КартаГотова КРабота = Истина;
ВыполнитьПоискАдресаНаКарте();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Отсутствие привычной консоли разработчика (DevTools, вызываемой по клавише F12) в тонком клиенте 1С сильно усложняет жизнь программисту. Чтобы не заниматься «слепой» отладкой, возьмите на вооружение следующие правила:
alert() в реализации WebKit внутри окон 1С может вести себя непредсказуемо — либо полностью блокироваться политиками безопасности движка, либо намертво «замораживать» сеанс работы пользователя. Для тестирования лучше выводите лог-сообщения в специально созданный текстовый контейнер <div id="debugConsole"></div> внизу вашей страницы.Alert("Сообщение") с заглавной буквы гарантированно вызовет ошибку отсутствия функции (правильно писать: alert("Сообщение")).
window.onerror = function(message, source, lineno, colno, error) {
// Отправляем информацию об ошибке в скрытое поле, чтобы 1С могла ее прочитать
var errorText = "Ошибка JS: " + message + " в строке " + lineno;
console.log(errorText); // для тестирования в обычном браузере
return false;
};
Используя данный комплексный подход и объект defaultView, вы сможете построить надежную, быструю и отказоустойчивую интеграцию ваших прикладных решений 1С с любыми современными веб-интерфейсами и картографическими сервисами.