gifts2017

HTML5 в ПолеHTMLДокумента на Управляемой форме - fireEvent в действии

Опубликовал Николай Гусев (GusevNA) в раздел Программирование - Практика программирования

Эта статья посвящена тому, как из ПолеHTMLДокумента управляемой формы вызывать Javascript и осуществлять вызовы 1С из Javascript, когда в ПолеHTMLДокумента используется Internet Explorer 9.

Суть проблемы:

В ранних версиях Internet Explorer (далее IE) вплоть до IE8 вызовы функций Javascript (далее JS) можно было осуществлять примерно так:

ПолеHTMLДокумента.document.parentWindow.MyFunc (...);

Начиная с версии IE9 такие вызовы, а также вызовы через eval () не работают, однако именно с этой версии начинается поддержка HTML5 и объекта Canvas, который предоставляет огромные возможности по рисованию, работе с картинками, аудио и видео и т.д. Также начиная с IE9 размер строки картинки в формате Base64 не ограничен (в IE8 - до 32К).

Однако, взаимодействие между Javascript'ом (далее JS) и 1С выглядит не так, как в старых версиях.

Решение:

Решением является использование JS-функции fireEvent.

Далее в статье рассматриваются вызовы 1С->JS и JS->1С для IE9 на примере функций вычисления суммы 2 чисел в 1С и JS. Cоответсвенно, функция JS вызывается из 1С, а 1С-функция - из JS.

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

В обработке к статье - полная версия примера.

Итак, начнем:

Сначала укажем, что наш HTML-код должен выполняться на движке IE9. Для этого в разделе <head> напишем строчку:

<head>
...
    <meta http-equiv="X-UA-Compatible" content="IE=9" />
...

</head>
Идем дальше. Поскольку JS-функция fireEvent может получать в качестве параметра только данные, относящиеся к сообщению, организуем передачу данных через невидимые на странице HTML-контейнеры <DIV>.

    <div id="ExtCommand" style="display:none">extcommand</div>
    <div id="EventName" style="display:none">js_event</div>
    <div id="BufferData" style="display:none">js_result</div>

Можно обойтись и одним <DIV>, в нашем примере их несколько для наглядности. Содержимое DIV-контейнера (точнее, свойство innerHTML) имеет строковый тип.

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

Также нам понадобится невидимая кнопка для вызова JS-функций:

    <input type=button style="display:none" id="SendEvent" = "ExecCommand ()" />

И JS-функция ExecCommand (), которая будет выполнять любой JS-код, передаваемый из 1С.

    function ExecCommand ()
    {
        code = document.getElementById ("ExtCommand").innerHTML;
        result = "" + eval (code);
        document.getElementById ("BufferData").innerHTML = result;
    }

Вызов Javascript из 1С:

&НаКлиенте
Процедура КомандаJS(Команда)
    // формуруем текст команды JS
    лКомандаJS = СкриптПоШаблону("SumJS (%1, %2)", ФрмЧ (Число1), ФрмЧ (Число2));    
    // записываем команду JS в контейнер div
    Элементы.НТМЛ.Документ.getElementById ("ExtCommand").innerHTML = лКомандаJS;
    // Посылаем сообщение невидимой кнопке, чтобы выполнить команду JS
    лКоманда = Элементы.НТМЛ.Документ.getElementById ("SendEvent");    
    лРезЕ = лКоманда.fireEvent ("onclick");
    // получаем результат из контейнера DIV
    лРез = Элементы.НТМЛ.Документ.getElementById ("BufferData").innerHTML;
    Сумма = Число (лРез);
КонецПроцедуры

Вызов 1С из Javascript:

Разместим на HTML-странице такие элементы:

<body>
...
    Число 1:<input type=text id="Val1" value="4" /><br />
    Число 2:<input type=text id="Val2" value="5" /><br />
    Сумма  :<input type=text id="Summa" value="0" /><br />
    <input type=button id="Button1" value="Сумма" ()" /><br />
...
</body>

Их назначение понятно из названий.

Далее функция ExtSum, которая вызывает обработчик ПриНажатии у ПолеHTMLДокумента в 1С:

    function ExtSum ()
    {
        // параметры вызова - имя действия
        document.getElementById ("EventName").innerHTML = 'CalcSum';
        // параметры действия строкой через точку с запятой
        document.getElementById ("BufferData").innerHTML = Val1.value+";"+Val2.value;
        
        var evt = document.createEventObject();
        // вызывает обработчик "НТМЛПриНажатии" в 1С
        document.body.fireEvent('onclick', evt);
        document.getElementById ("Summa").value = document.getElementById ("BufferData").innerHTML;
    }

Ну, и обработчик ПриНажатии в 1С:

&НаКлиенте
Процедура НТМЛПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
    // получаем имя нашего события из контейнера DIV
    лИмяСобытия = Элементы.НТМЛ.Документ.getElementById ("EventName").innerHTML;
    // очищаем содержимое контейнера DIV
    Элементы.НТМЛ.Документ.getElementById ("EventName").innerHTML = "";
    Если лИмяСобытия = "CalcSum" Тогда
        // получаем параметры из контейнера DIV в виде строки через точку с запятой
        лПараметры = Элементы.НТМЛ.Документ.getElementById ("BufferData").innerHTML;
        лПараметры = СтрЗаменить(лПараметры, ";", Символы.ПС);
        лЧисло1 = Число (СтрПолучитьСтроку(лПараметры, 1));
        лЧисло2 = Число (СтрПолучитьСтроку(лПараметры, 2));
        лСумма = лЧисло1+лЧисло2;
        лРез = ФрмЧ(лСумма);
        // помещаем результат в DIV
        Элементы.НТМЛ.Документ.getElementById ("BufferData").innerHTML = лРез;
        // здесь происходит возврат в JS
    Иначе
    // обработка других событий 
    КонецЕсли;
КонецПроцедуры

Этот пример тестировался и работает на платформе 1С 8.3.5.1517, на платформе 8.3.5.1383 выдавалась ошибка, похоже, платформенный баг.

 

 

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
Example_1C_JS_Interchange.epf
.epf 8,70Kb
18.04.15
40
.epf 0.1 8,70Kb 40 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Матвей Кудашкин (Patriot1S) 18.04.15 21:10
2. Николай Гусев (GusevNA) 18.04.15 22:01
(1) Patriot1S, Здесь все сделано стандартными средствами 1С и стандартными средствами HTML-JS. Насчет Linux - все зависит от того, как там реализован элемент управляемой формы ПолеHTMLДокумента.
Если аналогично Win, тогда нужно проверить платформу на баги (в релизе 8.3.5.1383 в тонком клиенте под Windows 7 просто баг выдавался и через Попытка-Исключение не обрабатывался).

Так что если кто-нибудь попробует под Linux, буду очень благодарен за комменты.

3. Александр Анисков (vandalsvq) 19.04.15 01:12
(0) Обрати внимание, в ие 9+ createEventObject не поддерживается. Точнее в 9 он остался для обратной совместимости, а в 10 и 11 выпилили. Поэтому я бы советовал использовать следующий код

if (document.createEvent) {
    var evt = document.createEvent('MouseEvents');
    evt.initEvent('click', true, false);
    document.body.dispatchEvent(evt);
} else if(document.createEventObject) {
    document.body.fireEvent('onclick');
}
...Показать Скрыть


И кстати можно еще объявить переменные в корне вроде

var eventName	 = '';
var eventParam = [];


Ну а потом обращаться к ним через ДокументHTML.parentWindow.EventName (или EventParam)
4. Николай Гусев (GusevNA) 19.04.15 15:06
(3) vandalsvq, Большое спасибо за код для IE10 - обязательно потестирую, когда время появится.

По этому примеру - он родился из реальной задачи, и там нужна была функциональность IE, которая начинается с версии 9.
Чтобы не тестировать HTML-JS для других версий IE, 9-я версия фиксирется строкой:

<meta http-equiv="X-UA-Compatible" content="IE=9" />

Она обозначает, что страница находится в режиме совместимости именно с IE9, даже если установлен IE10 или IE11.

А вот вызовы типа
ДокументHTML.parentWindow.EventName
начиная с IE9 не работают - для этого и используется fireEvent

Чтобы такие вызовы заработали, можно попробовать раздел реестра:
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_USE_LEGACY_JSCRIPT

Более подробно про режимы совместимости можно почитать здесь:
https://msdn.microsoft.com/ru-ru/library/cc288325%28v=vs.85%29.aspx
и здесь:
http://xiper.net/manuals/html/meta-tags/http-equiv/x-UA-Compatible

Про FEATURE_USE_LEGACY_JSCRIPT здесь:
http://weblog.west-wind.com/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version
5. Сергей Кудашкин (sikuda) 19.04.15 18:47
В Linux
не работает никакой fireEvent не работает
Элементы.НТМЛ.Документ.getElementById ("BufferData").innerHTML - работает!!! 8.3.6.1920
6. Александр Анисков (vandalsvq) 19.04.15 19:02
(4) GusevNA, не соглашусь на счёт параметров. Тестил режимы совместимости 9,10,11. В системе стоит ie11, win7 sp2. Все работало.
Линух пока не тестил.
7. Александр Анисков (vandalsvq) 19.04.15 19:03
(5) sikuda, А мой пример с createEvent работает?
8. Сергей Кудашкин (sikuda) 19.04.15 20:44
(7) vandalsvq, Да я честно не осознал зачем вообще fireEvent
Элементы.НТМЛ.Документ.getElementById ("SendEvent").click() - работает и в Windows и в Linux.

И в функции ExecCommand () добавь строку alert(navigator.userAgent); Ты будешь сильно удивлен своим IE9.
Yashazz; EliasShy; ZOMI; +3 Ответить
9. Сергей Ожерельев (Поручик) 20.04.15 07:15
navigator.userAgent покажет IE 7, какой бы режим совместимости не устанавливать.
ZOMI; sikuda; +2 Ответить 1
10. Юрий Гончарук (yukon) 20.04.15 11:14
(9) Поручик,
navigator.userAgent покажет IE 7, какой бы режим совместимости не устанавливать.

Это смотря где устанавливать. Если здесь: https://msdn.microsoft.com/en-us/library/ie/ee330730(v=vs.85).aspx#browser_emulation , то может и взетит.
11. Николай Гусев (GusevNA) 20.04.15 18:43
Еще раз по поводу вызовов типа ПолеHTMLДокумента.document.parentWindow.MyFunc1 ()

<!DO CTYPE html>
<ht ml>
<head>
<title>1C JS Interchange</title>
<met a http-equiv="Content-Type" content="text/html; charset=utf-8" />
<met a http-equiv="X-UA-Compatible" content="IE=8" />
<sc ript>
var var1 = "Debug_var";
function Debug1 ()
{
alert ("Debug");
}
</sc ript>
</head>
<body>
<p>Body</p>
</body>
</html>

Вызовы работают:
Рез = Элементы.НТМЛ.Документ.parentWindow.var1;
Сообщить (Рез); // выводит Debug_var
Элементы.НТМЛ.Документ.parentWindow.Debug1 (); // выводит MsgBox "Debug"

Если написать
<met a http-equiv="X-UA-Compatible" content="IE=9" />
При настройках IE по умолчанию ВЫЗОВЫ НЕ РАБОТАЮТ

Если вызовы все-таки работают, значит, накручены настройки IE в самом IE или в реестре.

Если Вы пишете под конкретного заказчика, и Вам доступны и настройки IE, и реестр, то можно все настроить так, как нужно.
Если Вы пишете обработки для всех, то лучше исходить из того, что настройки стоят по умолчанию.
12. Николай Гусев (GusevNA) 20.04.15 19:33
Насчет fireEvent и Click

Click также отлавливается элементом ПолеHTMLДокумента в событии ПриНажатии, так что можно использовать и такой метод. (тестировалось на Win7 32 bit 1С 8.3.5.1517). Судя по комментам, должно работать и в Linux.

Но, как я понял замысел разработчиков IE, click () - это непосредственное нажатие кнопки мыши, а fireEvent - это именно программный вызов события, так что с точки зрения правильности кода все-таки стоит использовать fireEvent

И еще насчет ПолеHTMLДокумента в Windows и Linux.
ПолеHTMLДокумента, насколько я знаю, использует ActiveX-компонент Webbrowser, а он работает на движке IE.
По крайней мере, так было в обычных формах. В УФ, возможно, также, только надстройка над компонентом Webbrowser изменена.
А в Linux на коком браузерном движке работает ПолеHTMLДокумента? Может, кто знает, напишите, плиз.
13. Сергей Кудашкин (sikuda) 20.04.15 23:06
(12) GusevNA, В Linux старенький web-kit:
Mozilla/5.0 (X11; Linux i686) AppleWebKit/538.15 (KHTML, like Gecko) Version/8.0 Safari/538.15

Насчет fireEvent не буду переубеждать.
14. Николай Гусев (GusevNA) 21.04.15 04:12
(13) sikuda, Спасибо, буду иметь ввиду. Попозже буду тестить под Linux на Virtualbox и отпишусь по результатам.

Кстати сказать, если вызовы fireEvent в 1С и JS заменить на вызов click (), то все работает также. Наверно, под Linux так и нужно делать.
15. Николай Гусев (GusevNA) 21.04.15 04:22
(3) vandalsvq, Если указать IE10
<met a http-equiv="X-UA-Compatible" content="IE=10" />

выдается ошибка "Произошла исключительная ситуация..." и для fireEvent и для click (). Ошибка не отлавливается Попыткой-Исключением. Точнее сказать, JS-функция отрабатывает, а потом выдается ошибка.
Похоже, это баг платформы, аналогичный тому, который был в 8.3.5.1383, только теперь уже под IE10.

Так что полноценного тестирования под движок IE10 не получается.
16. Сергей Марченко (MarSeN) 21.04.15 18:51
17. Сергей (Feelthis) 22.04.15 11:39
Может есть у кого примеры (хотя бы текстом, лучше картинки может и т. д.) реализаций крутых возможностей Javascript + 1C? Для чего полезного вы используете JavaScript?
У себя мы реализовывали только работу с картой google и yandex и построение маршрутов в 1С.
18. Яков Коган (Yashazz) 22.04.15 13:35
Поправьте, если ошибаюсь, но то чудо, которое засунуто в 1С под видом ПолеHTML, ведь никак не выше версии IE 8, так?
19. Александр Анисков (vandalsvq) 22.04.15 15:10
(0) хочу сказать что в своем сообщении (3) я был немного введен в заблуждение поведением платформы 1С.
8.3.5- получение параметров через точку невозможно, 8.3.6.1960 - работает.

И метод CreateEvent работает как то странно. Покопавшись, соглашусь с ранее высказанной мыслью что click() - самый универсальный способ (тем более как говорит sikuda он еще и кроссплатформенный).

Что же касается передачи параметров, то мое мнение можно через атрибуты их передавать.

HTML
<div id='name' data-eventName='' data-eventParam='' ...></div>


JS
getElementById('name').setAttribute('data-eventName', 'ИмяПроцедуры1С');
getElementById('name').getAttribute('data-eventName');


имена могут быть любые, но я делаю с префиксом data, надеясь что когда нибудь дата-атрибуты будут поддерживаться правильно (через dataSet).
20. Николай Гусев (GusevNA) 23.04.15 02:00
(18) Yashazz, Сейчас уже точно поддерживает движок IE 9 в релизе 8.3.5.1517. Все описанные фичи HTML5 для IE9 есть, так что налицо движение вперед:-))
21. Сергей Кудашкин (sikuda) 27.04.15 15:56
(19) vandalsvq, Да причем с точки зрения браузера не обязательно в HTML их прописывать.

<div id='name'></div>
getElementById('name').getAttribute('data-eventName'); -> NULL
getElementById('name').setAttribute('data-eventName', 'Значение');

Работает! и в 8.1
22. Николай Гусев (GusevNA) 21.05.15 19:09
После установки релиза 1С 8.3.1570 пример заработал для IE10:
<meta http-equiv="X-UA-Compatible" content="IE=10" />

И странный эффект - перестала выдаваться ошибка в релизе 8.3.1517
Проверялось на Windows 8 32 bit
23. Андраник Симонян (SmokeAce) 09.03.16 21:40
Спасибо автору и всем кто участвовал в обсуждении, помогло в боевых условиях.
24. Александр Вшивков (Dilovar9) 04.05.16 07:40
А как быть если innerHTML перестал работать в IE 11 ???
25. Николай Гусев (GusevNA) 04.05.16 12:36
(24) Dilovar9, Можно попробовать разные варианты строки:
<meta http-equiv="X-UA-Compatible" content="IE=8" />
Весь HTML должен работать как в IE8
Если не поможет, то поковырять настройки Винды, ИЕ, возможно, антивирусов.


26. Михаил Разговоров (Businka76) 25.06.16 00:12
обработка не помогла. обсуждение навело на результат. помог только ключ в реестре.
FEATURE_BROWSER_EMULATION позволяет выставить любой браузер.
10000 (0x2710) IE10
9000 (0x2328) IE9
8000 (0x1F40) IE8
7000 (0x1B58) IE7

более полно о доступных значениях ключей и что с ними делать есть здесь
https://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx
27. Николай Гусев (GusevNA) 25.06.16 10:05
(26) Businka76, бывает, что не работает из-за настроек Windows (IE все-таки компонент Windows) или из-за антивирусов
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа