Как вызвать функцию JavaScript из 1С в версии 8.3.14 и выше при переходе на движок WebKit?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Начиная с версии платформы 1С:Предприятие 8.3.14, разработчики столкнулись с глобальным изменением во встроенном элементе ПолеHTMLДокумента. Платформа перешла со старого и привычного движка Internet Explorer (Trident) на современный кроссплатформенный движок WebKit (Chromium). Это нововведение значительно расширило возможности визуализации интерфейсов, но сломало множество старых механизмов интеграции 1С и JavaScript.

В этой статье мы подробно разберем, как адаптировать ваш код под требования WebKit, научимся правильно вызывать JS-функции из встроенного языка 1С, рассмотрим частые ошибки инициализации асинхронных библиотек (например, Яндекс.Карт) и разберем архитектуру обратного взаимодействия.

Переход с IE на WebKit: что изменилось в объектной модели документа?

В старых версиях платформы 1С для обращения к глобальной области видимости JavaScript (к объекту window) использовалось свойство parentWindow объекта Документ. Типичный вызов выглядел следующим образом:


// Так код работал в старых версиях (до 8.3.14)
Элементы.HTML_документ.Документ.parentWindow.func('Параметр');

С переходом на WebKit свойство parentWindow, как и метод прямой оценки строк window.eval() на уровне интерфейса интеграции, были упразднены или заблокированы из соображений безопасности и стандартизации. В новой модели для доступа к глобальному контексту окна загруженного HTML-документа необходимо использовать свойство defaultView.

Давайте разберем по шагам, как должен выглядеть правильный вызов внешней функции.

Решение 1. Правильный синтаксис вызова функции через defaultView

Для того чтобы вызвать объявленную в вашем HTML-документе функцию findAdress(address) и передать ей текстовый параметр из 1С, используйте конструкцию следующего вида:


стрАдрес = "Витебск, Московский проспект, д. 5";
Элементы.ЯндексКарта.Документ.defaultView.findAdress(стрАдрес);

Обратите внимание на несколько критически важных нюансов при написании этого кода:

  1. Тип кавычек в параметрах. При ручном вводе или копировании кода с веб-ресурсов в редактор 1С могут попасть «типографские» кавычки (например, одиночные кавычки вида ‘ или ’, либо кавычки-ёлочки). Это приведет к синтаксической ошибке компилятора 1С: Неправильная константа типа Дата. Используйте только стандартные прямые одиночные (') или двойные (") кавычки.
  2. Регистрозависимость JavaScript. В отличие от встроенного языка 1С, язык JavaScript крайне чувствителен к регистру символов. Если ваша функция на веб-странице называется findAdress, то вызов FindAdress или findadress из кода 1С завершится ошибкой или проигнорируется системой.

Решение 2. Обход ограничения отсутствия метода eval

В некоторых случаях разработчикам необходимо динамически собирать и выполнять целые блоки JS-кода из 1С в виде строки. Поскольку прямой вызов eval на уровне объекта Документ в WebKit заблокирован, мы можем применить изящный обходной путь.

Для этого внутри самого HTML-файла в теге <script> объявим простую функцию-обертку, которая будет принимать строку кода и выполнять ее локально:


function runJavaScriptEval(codeString) {
    return eval(codeString);
}

Теперь из модуля управляемой формы 1С мы можем передавать абсолютно любой JS-код на выполнение через нашу обертку:


КодНаВыполнение = "console.log('Выполняю произвольный JS-код из 1С!'); MyMap.setZoom(10);";
Элементы.ЯндексКарта.Документ.defaultView.runJavaScriptEval(КодНаВыполнение);

Решение 3. Борьба с асинхронностью: устранение проблемы «функция не отрабатывает»

Очень часто программисты сталкиваются с ситуацией: синтаксических ошибок в коде нет, вызов defaultView.имяФункции() отрабатывает без исключений в 1С, но визуально на форме ничего не происходит (например, не ставится метка на карте). Выясним первопричину этой проблемы.

Событие формы 1С ПриОткрытии или событие элемента ДокументСформирован свидетельствуют лишь о том, что платформа загрузила базовую DOM-структуру HTML-страницы. Однако тяжелые внешние библиотеки, такие как API Яндекс.Карт или Google Maps, загружаются асинхронно.

Если вы вызываете функцию findAdress() до того, как библиотека Яндекс.Карт полностью загрузилась в контексте страницы, логика функции внутри блока ymaps.ready() попросту не сработает или упадет с ошибкой, которая не будет видна в 1С.

Для надежного решения этой проблемы необходимо реализовать механизм обратной связи (сигнализации) от HTML-страницы к 1С о полной готовности всех скриптов.

Организация обратного вызова: Передача данных из JS в 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 карт загружено!
            // Можем безопасно активировать кнопки поиска или передать первый адрес
            Объект.КартаГотова КРабота = Истина;
            ВыполнитьПоискАдресаНаКарте();
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Полезные советы по отладке JS в среде WebKit 1С

Отсутствие привычной консоли разработчика (DevTools, вызываемой по клавише F12) в тонком клиенте 1С сильно усложняет жизнь программисту. Чтобы не заниматься «слепой» отладкой, возьмите на вооружение следующие правила:


window.onerror = function(message, source, lineno, colno, error) {
    // Отправляем информацию об ошибке в скрытое поле, чтобы 1С могла ее прочитать
    var errorText = "Ошибка JS: " + message + " в строке " + lineno;
    console.log(errorText); // для тестирования в обычном браузере
    return false;
};

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

← На главную