В прошлой статье я рассказал, какие возможности скрывает в себе поле HTML-документа, выведенное на форму 1С. Сегодня подробнее остановлюсь на возможностях языков CSS (язык стилей и некоторых элементов поведения) и JavaScript (язык программирования, используемый в веб-разработке), которые могут пригодиться в работе с 1С-интерфейсом.
Демонстрационный пример
Работу с JS и CSS рассмотрим на примере разработки вот такого индикатора, который будет показывать для текстового поля, сколько символов еще можно напечатать.

Пример я буду реализовывать на демоконфигурации «Управляемое приложение», платформа 8.3.25.
Подготовка элемента формы и базовое наполнение
Подключим наш индикатор к полю с дополнительной информацией на форме элемента контрагента.

Наполним текст поля HTML-документа базовой разметкой. Можете запомнить этот шаблон, чтобы использовать его по умолчанию для новых элементов.
<html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <link rel="stylesheet" type="text/css" href="__STYLE__"> <style type="text/css"> /* Styles */ </style> </head> <body> <!-- HTML code --> <script> // Script </script> </body> </html>
В тексте HTML-документа используется сразу три языка:
язык разметки HTML,
язык стилей CSS,
язык программирования поведения JavaScript.
Это видно хотя бы по тому, что у каждого из них свой синтаксис обозначения комментариев. В проектах фронтенд-разработки отдельные модули этих частей выносят в разные файлы, но результат собирается именно в таком виде — весь код в одном файле.
Инициализацию поля HTML-документа выполним в процедуре, вызываемой из обработчика ПриСозданииНаСервере(), а отдельные смысловые части вынесем в соответствующие функции:
&НаСервере Процедура ИнициализироватьHTMLИндикатор() ТекстHTMLДокумента = "<html> | <head> | <meta http-equiv=""content-type"" content=""text/html;charset=utf-8""> | <link rel=""stylesheet"" type=""text/css"" href=""__STYLE__""> | <style type=""text/css""> | /* Styles */ | &ТекстСтилей& | </style> | </head> | <body> | <!-- HTML code --> | &ТекстHTML& | <script> | // Script | &ТекстJS& | </script> | </body> |</html>"; ТекстHTMLДокумента = СтрЗаменить(ТекстHTMLДокумента, "&ТекстHTML&", ТекстHTML()); ТекстHTMLДокумента = СтрЗаменить(ТекстHTMLДокумента, "&ТекстСтилей&", ТекстCSS()); ТекстHTMLДокумента = СтрЗаменить(ТекстHTMLДокумента, "&ТекстJS&", ТекстJavaScript()); HTMLИндикатор = ТекстHTMLДокумента; КонецПроцедуры Функция ТекстHTML() Возврат "<div class=""progressbar""> | <div class=""fillbar""> | </div> | <p class=""info""> | 145 | </p> |</div>"; КонецФункции Функция ТекстCSS() Возврат ".progressbar { | position: relative; | width: 104px; | height: 27px; | border: 1px solid #0aa; | border-radius: 4px; |} |.fillbar { | position: absolute; | top: 2px; | left: 2px; | width: 45px; | height: 21px; | border: 1px solid #aa0; | border-radius: 3px; | background-color: #aa0; | z-index: 2; |} |.info { | position: absolute; | right: 5px; | top: 8px; | margin: 0; | padding: 0; | font-size: 10px; | z-index: 3; |}"; КонецФункции Функция ТекстJavaScript() Возврат ""; КонецФункции
В результате при открытии формы, получим статичный элемент индикатора.

Теперь наша задача — вдохнуть в него жизнь и наделить определенным поведением:
по мере редактирования поля комментария индикатор должен показывать число оставшихся символов от максимальной длины текста;
длина заливки цветом должна соответствовать процентной доле объема текста;
цвет заливки будет меняться в зависимости от заполненности поля: зеленый при заполнении до 70%, желтый при 71% – 90%, красный при заполнении более 90% от допустимой максимальной длины.
Анатомия HTML-документа
Прежде чем начать манипуляции с HTML-полем, немного остановимся на том, как оно устроено изнутри.
Язык HTML
HTML-текст нашего элемента буквально рассказывает, какие элементы будут присутствовать в разметке. У нас их всего 3:
сам элемент-индикатор (тег div), обведенный рамкой;
вложенные в него цветовой ползунок (вложенный div);
элемент «параграф» (тег «p»), содержащий строковое представление числа символов.

Язык CSS
Сама по себе HTML-разметка не представляет большого интереса с точки зрения визуального результата. За взаимное расположение элементов и их внешний вид полностью отвечает язык описания стилей CSS.
Чтобы «сопоставить» элемент разметки при описании его стилей, в языке CSS выполняется позиционирование на элементе по так называемому Селектору. Типов селекторов существует с десяток, основные из них:
Позиционирование по имени тега. Например: «div {}» — стили будут применены ко всем элементам с тегом «div». Хотя для некоторых задач это бывает удобно, но в целом такой подход не очень гибкий, поскольку мы жестко привязаны к семантике расстановки HTML-тегов, а их разнообразие не так велико.
Позиционирование по ID элемента: «#myid {}» — применить к элементу с идентификатором myid. Сложность применения такого селектора в том, что идентификаторы должны быть уникальными в рамках всего HTML-документа, и за этим нужно дополнительно следить. К тому же этот подход не рекомендуется Стандартами.
Позиционирование по имени класса: «.info {}» (начиная с точки). Такой метод наиболее предпочтителен, и именно он используется в современной веб-индустрии. Управлять классами можно очень гибко, а задавать классы отдельным элементам разметки можно прямо в HTML-тексте в виде отдельного параметра тега class, что и сделано в нашем примере.
Открываем портал в HTML и управляем контекстом элемента
Динамически изменять число символов на индикаторе будем из кода на языке JavaScript, а инициализировать событие обновления будет обработчик текстового элемента формы ИзменениеТекстаРедактирования(). Его единственная задача — вызвать нашу процедуру ОбновитьHTMLИндикатор() (см. ниже).
Заполним текст модуля JS, который возвращает функция ТекстJavaScript():
Функция ТекстJavaScript() Возврат " |var maxLenght = 255; // Переменная, в которой будем хранить максимальную длину текста | |function updateText(num) { // Объявляем функцию изменения текста параграфа | var item = document.querySelector('.info'); // Находим интересующий элемент разметки по селектору | item.textContent = (maxLenght - num); // Заменяем текстовый контекст элемента |}"; КонецФункции
А теперь хорошая новость. Все, что объявлено в коде JavaScript, сразу становится доступным «снаружи», для этого не нужно специальным образом объявлять переменные или функции экспортными. Однако нужно заранее позаботиться о наличии «портала» для проникновения в код документа. Таким промежуточным звеном выступает сущность, которую условно назовем «контекст окна HTML». Хранить его будем в отдельной переменной модуля, а инициализировать в обработчике события ДокументСформирован() элемента «Поле HTML-документа».
&НаКлиенте Перем КонтекстДокументаHTML; &НаКлиенте Перем КонтекстОкнаHTML; &НаКлиенте Процедура HTMLИндикаторДокументСформирован(Элемент) Если НЕ HTMLЭлементыИнициализированы Тогда // Атрибут формы для предотвращения повторного запуска HTMLЭлементыИнициализированы = Истина; КонтекстДокументаHTML = Элемент.Документ; КонтекстОкнаHTML = КонтекстДокументаHTML.parentWindow; Если КонтекстОкнаHTML = Неопределено Тогда КонтекстОкнаHTML = КонтекстДокументаHTML.defaultView; КонецЕсли; КонтекстОкнаHTML.maxLenght = 100; // Инициируем переменную, объявленную в модуле JS КонецЕсли; ОбновитьHTMLИндикатор(); КонецПроцедуры
Вызываем функцию JavaScript из кода 1С
Теперь у нас все готово для манипуляции HTML-документом из кода 1С. Задействуем контекст окна HTML, чтобы вызвать функцию updateText(), объявленную в модуле JavaScript:
&НаКлиенте Процедура ОбновитьHTMLИндикатор() Если Не HTMLЭлементыИнициализированы Тогда Возврат; КонецЕсли; ТекДлина = СтрДлина(Элементы.ДополнительнаяИнформация.ТекстРедактирования); КонтекстОкнаHTML.updateText(ТекДлина); КонецПроцедуры
Изменяем стили на лету
Далее рассмотрим, что мы можем сделать, чтобы цветовой индикатор при изменении длины строки менял свою длину и цвет? Для этого нам нужно повлиять на значения параметров стилей, которые сейчас находятся в отдельном модуле CSS. Однако, как и многое в веб-технологиях, есть и другие варианты изменить стиль элемента.
Так, стили можно непосредственно задать в HTML-элементе в виде атрибута тега style. Причем такие стили будут иметь более высокий приоритет, чем те, что находятся в подключенном модуле. А нам это как раз на руку.
Среди стилей нашего класса fillbar нас интересуют два: width (ширина) и background-color (цвет заливки). Если их прописать непосредственно в коде HTML, то определение тега будет выглядеть так:
<div class="fillbar" style="width: 45px; background-color: #aa0">
Для работы со стилями из JS-кода у элемента есть служебное свойство style, от которого через точку можно задать значение ��юбого CSS-свойства. С одной оговоркой: если имя свойства составное (как background-color), то в языке JavaScript оно преобразуется в camel-case нотацию и превращается в backgroundColor. Полный текст JS-функции, который управляет цветовым индикатором, будет выглядеть следующим образом:
&НаСервере Функция ТекстJavaScript() Возврат " |// ... | |function fillColor(num) { | // получаем элемент цветового индикатора | var item = document.querySelector('.fillbar'); | // рассчитываем параметры | var count = 100 - Math.round((maxLenght - num) / maxLenght * 100); | var color = ""#0f0""; | if (count > 70) {color = ""#ff0""} | if (count > 90) {color = ""#f00""} | // задаем новые стили заливки | item.style.width = count + ""px""; | item.style.backgroundColor = color; |}"; КонецФункции
Остается только вставить его вызов в процедуру обновления индикатора и наслаждаться результатом.
&НаКлиенте Процедура ОбновитьHTMLИндикатор() //... КонтекстОкнаHTML.updateText(ТекДлина); КонтекстОкнаHTML.fillColor(ТекДлина); КонецПроцедуры
Еще один элемент
Наконец, добавим еще один элемент к нашему индикатору, заодно познакомимся с несколькими дополнительными приемами JS и CSS.
Теперь под нашим индикатором появится вот такой спидометр, стрелка которого будет указывать, насколько мы близки к пределу.

Фон спидометра будет украшать приятная глазу градиентная заливка, а края - отбрасывать тень, придавая элементу объем. Стрелка будет не просто перемещаться, но еще плавно менять цвет от зеленого к красному, в зависимости от положения.
Для этого дополним код HTML новыми элементами, а в CSS опишем стили для новых классов:
Функция ТекстHTML() Возврат " | ... | <div class=""arrow_wrap""> // подложка спидометра | <div class=""arrow""> // из этого сделаем стрелку | </div> | </div> |</div>"; КонецФункции Функция ТекстCSS() Возврат "... |.arrow_wrap { | position: relative; | margin-top: 50px; | width: 100px; | height: 50px; | min-width: 104px; | min-height: 27px; | border: 1px solid #aaa; | border-radius: 50% 50% 0 0; | box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2), // тень | 5px 5px 10px rgba(0, 0, 0, 0.1); | background: linear-gradient(217deg, // градиент | rgba(255, 150, 150, 0.8), | rgba(255, 150, 150, 0) 70.71%), | linear-gradient(127deg, | rgba(150, 255, 150, 0.8), | rgba(150, 255, 150, 0) 70.71%), | linear-gradient(336deg, | rgba(150, 150, 255, 0.8), | rgba(150, 150, 255, 0) 70.71%); |} |.arrow { | position: absolute; | width: 30px; | height: 5px; | border-radius: 10px; | top: 45px; | left: 20px; | transform-origin: right center 0; | | background-color: rgb(0, 200, 0); // эти два свойства будем менять из кода | transform: rotate(90deg); |}"; КонецФункции
Суть движения стрелки — в использование CSS-трансформаций:
transform-origin задает опорную точку элемента, относительно которой он будет двигаться;
transform указывает функцию трансформации, в нашем случае это вращение с указанием значения угла.
Осталось добавить код на JS, который будет «двигать» стрелку:
Функция ТекстJavaScript() Возврат " | ... |function duePersent(num) { | return Math.round((maxLenght - num) / maxLenght * 100); |} |function updateArrow(num) { | var item = document.querySelector('.arrow'); | | var due = duePersent(num); | var deg = 180 - Math.round(due*180/100); | var rr = 200 - Math.round(due*200/100); | var gg = Math.round(due*200/100); | | var transformValue = `rotate(${deg}deg)`; | var bgcValue = `rgb(${rr}, ${gg}, 0)`; | | item.style.backgroundColor = bgcValue; | item.style.transform = transformValue; |} |function updateAll(num) { | var count = num; | if (num > maxLenght) { | count = maxLenght; | } | | updateText(count); | fillColor(count); | updateArrow(count); |}"; КонецФункции
Поведением стрелки управляет функция updateArrow(). Цвет и угол наклона устанавливаются из рассчитанных значений CSS-свойств через style. А сложное представление самих значений формируется путем шаблонизации строк. Такое возможно, если заключить строки не в кавычки, а в обратные бэктики (клавиша «Ё» на клавиатуре).
Наконец, все функции управления поведением мы объединили в одну updateAll(), в которой дополнительно выполняем контроль переполнения значения.
&НаКлиенте Процедура ОбновитьHTMLИндикатор() Если Не HTMLЭлементыИнициализированы Тогда Возврат; КонецЕсли; ТекДлина = СтрДлина(Элементы.ДополнительнаяИнформация.ТекстРедактирования); КонтекстОкнаHTML.updateAll(ТекДлина); КонецПроцедуры
CSS-анимации
В заключении познакомимся с анимацией. Существует несколько способов заставить что-то двигаться с помощью CSS и/или JS. Мы выбрали CSS-анимации с использованием keyframes. Этот метод довольно прост, но в то же время достаточно гибкий, т. к. позволяет задать произвольное значение трансформации в произвольные отметки времени («кадры» — отсюда и название).
Добавим два дополнительных класса CSS, отвечающих за анимацию:
Функция ТекстCSS() Возврат "... |@keyframes bounce { | 0% { | transform: translateY(-2px); | } | | 20% { | transform: translateY(2px); | } | | 40% { | transform: translateY(-1px); | } | | 60% { | transform: translateY(1px); | } | | 80% { | transform: translateY(-1px); | } | | 100% { | transform: translateY(0); | } |} | |.modal-error { | animation: bounce 0.3s; // общая продолжительность сценария анимации |}"; КонецФункции
Теперь в JS-коде, в функции контроля переполнения присвоим класс modal-error классу-основанию спидометра, чтобы заставить его немного потрястись. Это дополнительно привлечет внимание пользования при переполнении.
Функция ТекстJavaScript() Возврат " |var arrowBody = document.querySelector("".arrow_wrap""); // переменная модуля для доступа к элементу | | ... |function updateAll(num) { | | ... | if (num > maxLenght) { | arrowBody.classList.remove(""modal-error""); // удаляем класс, если он был присвоен ранее | arrowBody.offsetWidth = arrowBody.offsetWidth; // делаем что-то с элементом, чтобы браузер его обновил | arrowBody.classList.add(""modal-error""); // снова присваиваем класс, чтобы возбудить анимацию | } |}"; КонецФункции
Результат:



Заключение
Конечно, в рамках двух статей невозможно описать все тонкости веб-технологий для поля HTML-документа. Ибо они практически безграничны! Моя цель: на простом рабочем примере показать, что из себя представляют новые для 1С-ника языки HTML, CSS и JavaScript. И как их применить при разработке новых интерфейсных элементов, если возможностей 1С недостаточно.
P.S. Весь представленный в статье веб-код можно посмотреть и опробовать по ссылке.
