При разработке интерфейсов на базе Поля HTML-документа в 1С:Предприятии (особенно в обычных формах) разработчики часто сталкиваются с проблемой «изоляции» среды исполнения JavaScript. В отличие от управляемых форм, где механизм window.external реализован более прозрачно, в обычных формах (ОФ) прямого способа передать ссылку на объект 1С или форму внутрь DOM-модели не существует. Попытки передать ЭтаФорма напрямую приводят к получению значения null или простой строки.
В этой статье мы подробно разберем, как преодолеть барьер «песочницы» JavaScript и организовать надежный вызов процедур 1С из веб-интерфейса, используя доступные события и механизмы платформы 1С 8.3.
Прежде всего, проанализируем ситуацию: JavaScript в браузере ничего не знает о внутреннем устройстве 1С. Для него 1С — это внешнее приложение, которое просто отображает страницу. Чтобы «достучаться» до 1С, нам нужно использовать одно из стандартных событий элемента управления «Поле HTML-документа», которое 1С умеет перехватывать. Суть любого решения сводится к следующему алгоритму:
Это один из самых распространенных способов. Мы не можем напрямую привязать функцию 1С к атрибуту onclick в HTML-коде, но мы можем «подписаться» на клики по документу со стороны 1С. Рассмотрим этот процесс по шагам.
Сначала подготовим HTML-код с кнопкой, имеющей определенный идентификатор:
<button id="mySuperButton" data-param="777">Нажать для вызова 1С</button>
Теперь в модуле обычной формы нам нужно перехватить момент окончания загрузки страницы, чтобы установить обработчик события. Используем событие ДокументСформирован (DocumentComplete):
Процедура ПолеHTMLДокументаДокументСформирован(Элемент)
// Получаем объект COM-объекта документа
Документ = ЭлементыФормы.ПолеHTML.Документ;
// Подписываемся на событие клика по всему документу
Документ.onclick = Новый COMОбъект("htmlfile").parentWindow.eval("
|(function(event) {
| window.lastClickedElement = event.srcElement;
|})");
// В ОФ чаще используется прямое назначение обработчика события через встроенные механизмы
Документ.onclick = ЭтаФорма; // В некоторых реализациях
КонецПроцедуры
Однако более надежным методом в ОФ является анализ элемента в процедуре-обработчике, которая привязана к событию onmouseup или onclick через COM-соединение. Проанализируем пример получения данных:
Процедура ПриНажатииВПолеHTML(Элемент)
ТекущийДокумент = ЭлементыФормы.ПолеHTML.Документ;
// Получаем элемент, по которому кликнули
АктивныйЭлемент = ТекущийДокумент.activeElement;
Если АктивныйЭлемент.id = "mySuperButton" Тогда
Параметр = АктивныйЭлемент.getAttribute("data-param");
ВыполнитьДействиеВ1С(Параметр);
КонецЕсли;
КонецПроцедуры
Вызов справки — это стандартное событие браузерного движка, которое 1С перехватывает штатно. Это едва ли не самый быстрый способ передачи сигнала без необходимости парсинга координат клика.
Разберем реализацию в JavaScript:
function call1C(data) {
// Записываем данные в скрытый инпут, чтобы 1С могла их прочитать
var transferField = document.getElementById('transfer_data');
if (!transferField) {
transferField = document.createElement('input');
transferField.id = 'transfer_data';
transferField.type = 'hidden';
document.body.appendChild(transferField);
}
transferField.value = data;
// Вызываем штатное событие справки
window.showHelp();
}
Теперь в 1С в свойствах Поля HTML-документа находим событие Справка (OnHelp):
Процедура ПолеHTMLСправка(Элемент, ДанныеСобытия, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Чтобы не открывалось окно справки системы
Документ = ЭлементыФормы.ПолеHTML.Документ;
ПолеПередачи = Документ.getElementById("transfer_data");
Если ПолеПередачи <> Неопределено Тогда
ЗначениеОтJS = ПолеПередачи.value;
Сообщить("JavaScript прислал данные: " + ЗначениеОтJS);
// Здесь вызываем любую функцию 1С
МояПроцедураОбработки(ЗначениеОтJS);
КонецЕсли;
КонецПроцедуры
Этот метод основан на попытке браузера перейти по новому адресу. Мы подменяем window.location.href, а 1С перехватывает это событие до того, как страница начнет перезагружаться.
В JavaScript пишем функцию-обертку:
function sendTo1C(command, params) {
var url = "1capp://command=" + encodeURIComponent(command) + "¶ms=" + encodeURIComponent(JSON.stringify(params));
window.location.href = url;
}
В 1С используем событие ПередЗагрузкойУстановкойУказателя (BeforeNavigate):
Процедура ПолеHTMLПередЗагрузкойУстановкойУказателя(Элемент, URL, Узел, Фрейм, Ресурс, Отказ)
Если Найти(URL, "1capp://") > 0 Тогда
// Отменяем переход в браузере
Отказ = Истина;
// Извлекаем данные из URL
ПараметрыСтрокой = Сред(URL, Найти(URL, "1capp://") + 8);
// Выполняем парсинг параметров и запуск логики 1С
ОбработатьКомандуИзJS(ПараметрыСтрокой);
КонецЕсли;
КонецПроцедуры
Выясним важную деталь: поскольку передать ссылку на объект (например, на СправочникСсылка) напрямую невозможно, всегда используйте сериализацию. 1С в обычных формах (начиная с платформы 8.3.6) отлично работает с JSON.
Рассмотрим пример передачи сложной структуры из JavaScript в 1С:
// JS код
var orderInfo = {
id: "000001",
date: "2023-10-27",
items: [{name: "Товар 1", qty: 2}, {name: "Товар 2", qty: 5}]
};
call1C(JSON.stringify(orderInfo));
В 1С для восстановления данных воспользуемся объектом ЧтениеJSON:
Функция ПрочитатьДанныеИзJS(СтрокаJSON)
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(СтрокаJSON);
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Возврат Результат; // Получаем структуру 1С
КонецФункции
Если вы используете WebKit в обычных формах, следует учитывать, что его поведение может отличаться от старого движка Internet Explorer (MSHTML). В частности:
window.parentWindow может потребовать обращения через defaultView.http/https, а напрямую из строки или файла.eval(). Например: ЭлементыФормы.ПолеHTML.Документ.parentWindow.eval("myJSFunction('Привет из 1С')").Резюме: Несмотря на то, что обычные формы не предоставляют такого удобного моста, как СредстваКриптографии.ExternalEvent в управляемых формах, использование события onhelp или перехват навигации позволяет построить полноценное двустороннее взаимодействие между 1С и JavaScript.