Предисловие
Интерфейс управляемых форм в мобильном приложении сильно контрастирует с внешним видом большинства привычных мобильных приложений. Используя HTML-документ в качестве рабочей области, можно достаточно серьёзно прокачать визуальную составляющую своего программного продукта.
Понятно, что этот вариант хоть и рабочий, но далеко не идеальный. Вероятно, для мобильной разработки правильней было бы использовать язык, который под неё лучше заточен, но лично для меня камнем преткновения становится время, которое необходимо затратить на изучение механизмов хранения структурированных данных, работы с файлами, взаимодействия с другими базами, формирования отчётов и прочих привычных вещей. При этом 1С предоставляет довольно широкий функционал для написания движка мобильного приложения, а поверхностных знаний HTML, CSS, JS и имеющихся в сети готовых библиотек вполне достаточно для возможности отрисовки красивой картинки.
В общем, у каждого самурая свой путь.
HTML-документ
Итак, в данном подходе рабочей областью является HTML-страница или HTML-документ.
Его содержимое представляет собой набор тэгов, который интерпретируется в интерфейс. На текущий момент в 1С за это отвечает встроенная в платформу библиотека WebKit.
Для формирования рабочей области создадим обработку, в форме которой добавим строковый реквизит (ниже в примерах - ТекстHtml) и выведем его на форму в качестве поля вида Поле HTML документа (ПолеHtml). Саму форму укажем в качестве рабочей области начальной страницы конфигурации.
Вкратце для тех, кто не работал ещё с HTML
Содержимое на странице структурируется с помощью тегов (текст в угловых скобках, вроде <имя>)
Теги бывают парные (например: <html></html>) или одиночные (<br>). В некоторых случаях парные теги записывают без закрывающей части (<hr/>)
Текст между тегами называется содержимым. Совокупность тега с содержимым называется контейнером. Содержимое может включать, как обычный текст, предназначенный для отображения на странице, так и программный код, понятный интерпретатору (например JS или CSS), и другие теги (что делает структуру страницы иерархической):
<body><div>Первая строка<br>Вторая строка</div></body>
В теге могут быть расположены атрибуты, которые определяют его свойства. Для каждого тега определён свой состав атрибутов. В них описывается реакция на действия пользователя, вид содержимого, свойства страницы в целом и пр. (пример - атрибут href гиперссылки, в котором указан адрес перехода: <a href="//infostart.ru">Главная страница Инфостарт</a>)
Совокупность тегов и их атрибутов являются инструкцией интерпретатору по работе с содержимым. За что отвечает каждый из них можно посмотреть в описаниях стандартов (да, их несколько, это можно сравнить с разными версиями платформы 1С).
Если тег системе незнаком, то она его (инструкцию) просто игнорирует.
Часть тегов являются техническими (например, содержат информацию о свойствах страницы в целом, описание стилей, теги верхнего уровня (<html>, <head> и <body>) и пр.), а часть нацелена на вывод информации на странице (я их назову визуальными, т.к. обобщающего термина для них я не нашёл).
Визуальные можно разделить на
- блочные - те, которые занимают всю ширину (строки) родительского контейнера и как следствие всегда начинаются с новой строки
- строчные - которые являются частью строки и могут влиять только на своё содержимое (например, выделение текста жирным шрифтом или перенос строки)
Важно понимать, что строчные теги могут содержать либо текст, либо другие строчные элементы, а блочные - другие блочные элементы, строчные и текст.
Для вставки комментария используется конструкция:
<!-- любой текст -->
Чтобы система вывела угловую скобку в виде текста, используются спецсимволы < и >
Из тех которые будут встречаться в примерах ниже:
- <div>, <p> - блочные элементы
- <span> - строчный элемент
- <a> - гиперссылка, текст, при нажатии на который, выполняется переход на область документа или на другую страницу
- <button> - кнопка, предполагается, что должна располагаться внутри тега <form>, но воспринимается системой и как самостоятельный элемент
- <input> - универсальный элемент, обеспечивающий разностороннее взаимодействие с пользователем. В зависимости от типа может быть кнопкой, набором флагов/переключателей, полем ввода текста/пароля, полем выбора файла, изображением.
- <br> - перенос строки
HTML-документ формируется
- при изменении содержимого реквизита ТекстHtml
- интерактивном переходе на страницу группы, где расположено поле HTML
- при изменении содержимого страницы через свойства HTML-документа
- при переходе по гиперссылке
При этом срабатывает событие поля ДокументСформирован. В обработчике события можно, в том числе, изменять свойства HTML-документа не затрагивая содержимое ТекстаHtml.
ТекстHtml должен содержать описание структуры документа на языке HTML. И чтобы система восприняла его таковым, он обязательно должен содержать тег <html>. То есть система вполне нормально воспринимает
ТекстHtml = "<html>Привет мир!</html>" или даже ТекстHtml = "<html>Привет мир!"
при этом на страницу просто будет выведена надпись Привет мир!
В общем-то, интерпретатор очень адаптивен и сам подстраивает содержимое под нужный формат. Но всё же лучше придерживаться определённых стандартов, т.к. никто не любит плохо написанный код.
К стандарту, например, относится наличие тегов head и body.
Body преимущественно содержит видимый пользователю контент страницы, но может включать скрипты, скрытые и неотображаемые элементы и т.п. Подробно писать о нём, особого смысла нет. Если для реализации ваших идей не хватает тех элементов, которые были описаны выше, смело берите справочник HTML и подбирайте теги и атрибуты, которые отвечают вашим потребностям. Главное помните, что html – это только инструкция, поэтому итоговый вид интерфейса будет зависеть как минимум от движка, который будет её обрабатывать, и форм-фактора устройства. В общем, не забывайте делать проверку результата на гаджетах, для которых выполняете разработку.
Head хранит служебную (скрытую от пользователя) информацию о странице. Из тех данных, что нас сейчас интересуют это:
- метатеги <meta />
- скрипты <script></script>
- описание стилей <style></style>
Метатеги содержат краткое описание страницы вроде её размера, кодировки, ключевых слов и прочего. Крайне полезным для создания рабочей области является метатег viewport, который определяет размер страницы:
<meta content="width=device-width, initial-scale=1.0" name="viewport">
Если он не задан, то размер страницы устанавливается по умолчанию в зависимости от браузера (например, для Android WebKit ширина будет равна 800px). На практике это означает, что страница не будет ограничена размерами видимого поля, и будет прокручиваться.
Скрипт содержит текст программы на JavaScript, что обеспечивает динамику страницы без обращения к внешним ресурсам и перерисовки всей страницы. Плюс ко всему это может расширить число действий пользователя, на которое сможет среагировать система (для 1С доступно только нажатие, но об этом дальше)
С одной стороны бессмысленно даже пытаться сделать краткий обзор на язык в целом (тем более он мне не "родной"), но с другой - основную часть функционала можно смело отдать 1С, поэтому для большинства задач вполне достаточно понимания общего синтаксиса.
______________________________________________________________________________________
Пример таймера:
<html>
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<script>
// объявление глобальных переменных
let count1 = null; // присваиваем пустое значение
let interval_id; // если значение не присвоено, то в переменной хранится undefined
let input_count_H;
let input_count_M;
let input_count_S;
function startTimer(){
fillTitle('Начало');
if (interval_id == undefined) { // сравниваем (на равенство) со значением undefined
// таким образом исключаем повторный запуск таймера
interval_id = setInterval(countDown, 1000);
/* запускаем таймер асинхронным методом setInterval,
в первом параметре указывается имя выполняемой функции,
во втором - период выполнения в миллисекундах
значение записываем в глобальную переменную для возможности остановки таймера
*/
}
}
function countDown(){
// если таймер остановлен, выходим из функции
if (interval_id == undefined) return;
/* синтаксис позволяет описывать if без явных скобок, если тело состоит из одной строки,
но такой вариант не рекомендуется
*/
if (count1 == null) {
let locValue = getCurrentValue(); // объявление локальной переменной, которая видна в рамках своего блока
count1 = isNaN(locValue) ? null : locValue; // "? :" аналог "?()" из 1С, назначение параметров аналогичное
/* NaN - значение которое возвращает система,
если в результате преобразования к числу произошла ошибка
метод isNaN() проверяет параметр на равенство NaN, возвращая Истину или Ложь
*/
}
if (count1 == null) {
stopTimer();
return;
}
else if (count1 > 0){
let message = 'осталось: ' + count1 + ' с'; // пример конкатенации и неявного преобразования типа
fillTitle(message);
count1--; // декремент - уменьшение числового значения на единицу, обратная операция инкремент "++"
}
else {
stopTimer("Время закончилось");
}
}
function stopTimer(message="", clearCount=true){
fillTitle(message);
if (interval_id != undefined){ // сравнение на неравенство
clearInterval(interval_id); // останавливаем таймер по идентификатору
interval_id = undefined; // возвращаем значение переменной в исходное положение
}
if (clearCount){
count1 = null;
}
}
function fillTitle(message){
let divTitle = document.querySelector('.infoStyle');
/* объект document используется для доступа к свойствам и методам страницы
querySelector возвращает первый элемент, соответствующий указанному в параметре CSS-селектору
подробнее о селекторах в блоке про CSS
конкретно в этом случае выполняется поиск по имени класса (атрибут class)
*/
divTitle.innerHTML = message; // устанавливаем содержимое тега через свойство innerHTML
}
function resetTimer(){
stopTimer();
input_count_H.value = ""; // очищаем значения input-тегов
input_count_M.value = "";
input_count_S.value = "";
}
function getCurrentValue(){
let value_H = input_count_H.value; // считываем значения input-тегов
let value_M = input_count_M.value;
let value_S = input_count_S.value;
if (! onlyNumbers(value_H) // восклицательный знак - логическое НЕ
|| ! onlyNumbers(value_M) // || - логическое ИЛИ
|| ! onlyNumbers(value_S)){
stopTimer("Введите числовое значение");
return;
}
return Number(value_H)*60*60+Number(value_M)*60+Number(value_S);
}
function onlyNumbers(value){
let stringWithNumbers = '0123456789'; // строка может быть выделена двойными или одинарными кавычками
let result = true;
for (var i = 0; i < value.length; i++){ // запускаем цикл для перебора символов строки
/* for близок 1С-овскому циклу "Для",
но здесь есть третий параметр, в котором указывается выражение изменения счетчика
*/
let outputSign = value[i]; // работа со строкой во многом похожа на работу с массивом
if (! stringWithNumbers.includes(outputSign)){ // проверяем, входит ли символ в заданный строкой набор
result = false; breack;
} ;
};
return result;
}
</script>
</head>
<body>
<div class="infoStyle"></div>
<div id="block_of_numbers">
<div class="divNum">
<span>Ч</span><br>
<input class="count" id="input_count_H" type="text" maxlength="2"/>
</div>
<div class="divNum">
<span>М</span><br>
<input class="count" id="input_count_M" type="text" maxlength="2"/>
</div>
<div class="divNum">
<span>С</span><br>
<input class="count" id="input_count_S" type="text" maxlength="2"/>
</div>
</div>
<div><button id="butStart" ontouchstart="startTimer(); ">Запустить таймер</button></div>
<div><button id="butStop" ontouchstart="stopTimer('Пауза: '+count1+' с',false)">Пауза</button></div>
<div><button id="butReset" ontouchstart="resetTimer();">Обнулить таймер</button></div>
<script>
/* получаем элементы, которые находятся выше по коду,
т.е. после того, как они были "считаны" интерпретатором */
input_count_H = document.getElementById('input_count_H'); // получаем элемент по id
input_count_M = document.getElementById('input_count_M');
input_count_S = document.getElementById('input_count_S');
</script>
</body>
</html>
______________________________________________________________________________
Что хочется отметить
Регистр в JS важен.
В качестве логических скобок блоков кода здесь используются фигурные скобки {}
Явным концом строки является точка с запятой. Неявным - перенос строки, но он не во всех случаях срабатывает корректно.
Объявление переменных является обязательным. Для этого используются ключевые слова let (обычная переменная), const (неизменяемая), var (устаревший аналог let, не рекомендуется к использованию).
Помимо обычных математических операторов здесь есть: % (остаток от деления), ** (возведение в степень), ++ (инкремент, увеличение на единицу), -- (декремент, уменьшение на единицу)
Операторы сравнения: > (больше), < (меньше), >= (больше или равно), <= (меньше или равно), == (равно), != (не равно)
Логические операторы: || (ИЛИ), && (И), ! (НЕ)
Циклы:
- wile (условие) {тело} - цикл с предусловием, аналогичен 1С-овскому циклу Пока
- do {тело} wile (условие) - цикл с постусловием, отличается тем, что сначала выполняется код, а потом происходит проверка, т.е. хотя бы раз код из тела будет выполнен
- for (установка счётчика; условие; операция изменения счётчика) {тело} - близок 1С-овскому Для, но
- в качестве счётчика можно использовать внешнюю переменную
- условие может быть любым, главное, чтобы результат был булево
- операция изменения счётчика может быть явно прописана в условии и естественно, как увеличивать, так и уменьшать его значение
- описание любой из частей цикла можно пропустить, т.е. система воспримет for(;;){let a=0}
Для прерывания цикла используется breack. Для перехода к следующей итерации - continue.
Кроме метода таймера setInterval (и его компаньона clearInterval) в JS есть метод отсрочки setTimeout (синтаксис у них аналогичный), отличие которого в том, что он выполняется только один раз. Для прерывания используется метод clearTimeout.
Диалоговые модальные окна:
- alert(текст сообщения) - выводит сообщение (налог в 1С - Предупреждение).
- promt(заголовок, значение по умолчанию) - выводит сообщение и ждёт, пока пользователь введёт текст, а затем возвращает введённое значение или null, если ввод отменён (CANCEL/Esc).
- confirm(текст вопроса) - выводит сообщение и ждёт, пока пользователь нажмёт «OK» или «CANCEL» и возвращает true/false.
Код JS выполняется по ходу формирования страницы и, столкнувшись с тегом script, интерпретатор сразу пошагово выполнит содержащийся в нём код. Поэтому в случае обращения к элементам документа можно использовать только те, которые находятся выше по коду.
В рамках этой статьи JS рассматривается как обработчик действий пользователя. В частности нажатий, которые описываются атрибутами тегов onclick и ontouchstart.
Описание стилей содержит таблицу стилей на языке CSS, иными словами набор правил оформления внешнего вида элементов страницы: размер, форму, цвет, шрифт, положение на странице и т.п.
CSS - Cascading Style Sheets - «каскадные таблицы стилей» - язык иерархических правил (таблиц стилей), используемый для представления внешнего вида документа.
В состав каждого правила входят:
- селектор, который указывает на то, к каким элементам должны применяться правила оформления
- CSS-свойство - характеристика, описывающая внешний вид элемента (цвет фона, положение, ширина и т.п.)
- значения свойства
Синтаксис: селектор(ы) {свойство1: значение1; свойство2: значение2;...}
В коде может быть несколько правил, применимых к одному и тому же элементу. Приоритет применения зависит от положения (чем ниже, тем приоритетней) и специфичности (какой из селекторов более точечно описывает элемент). Приоритет определяется только по пересекающимся свойствам, а не по набору в целом.
Кроме того правила обладают наследуемостью, т.е. могут быть применены к дочерним элементам. Свойства при этом разделяются на те, которые могут быть унаследованы (например, цвет текста) и на те, что применяются только к указанному элементу (например, свойство ширина)
Селекторы
- * - любой элемент
- типЭлемента - отбор по типу, например input, div и пр.
- .имяКласса - отбор по значению атрибута class (начинается с точки)
- типЭлемента.имяКласса - комбинированный вариант предыдущих двух селекторов
- #имяИдентификатора - отбор по значению атрибута id (начинается с #)
- типЭлемента:состояние - отбор по состоянию элемента, например особое отображение посещённой ссылки (a:visited) или наведение курсора (div:hover). Ключевое слово, описывающее состояние, называется псевдоклассом
- описаниеАтрибута - отбор по имени атрибута или имени и значению атрибута
- [attr] - элемент с атрибутом по имени attr
- [attr="value"] - элемент с именем атрибута attr и значением, в точности совпадающим с value
- [attr~="value"] - элемент с именем атрибута attr значением которого является набор слов разделённых пробелами, одно из которых в точности равно value
- [attr|="value"] - элемент с именем атрибута attr. Его значение при этом может быть или в точности равно "value" или может начинаться с "value" со сразу же следующим "-" (U+002D). Это может быть использовано, когда язык описывается с подходом
- [attr^="value"] - элемент с именем атрибута attr значение которого начинается с "value"
- [attr$="value"] - элемент с именем атрибута attr чьё значение заканчивается на "value"
- [attr*="value"] - элемент с именем атрибута attr чьё значение содержит, по крайней мере, одно вхождение строки "value" как подстроки
Если требуется
- применить один и тот же стиль по нескольким селекторам, то они указываются через запятую
Пример: h1,div
- применить стиль к вложенному элементу, то селекторы указываются через пробел
Пример: div button
- применить стиль к элементу, который расположен в конце определённой последовательности элементов одного уровня, то такая последовательность указывается через плюс
Пример: p + input
Набор свойств и их значений лучше посмотреть на соответствующих ресурсах
Пример-дополнение для кода, описанного в блоке JS таймера.
<html>
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<script>
.....
</script>
<style type="text/css">
[id^="but"] {
display: block; /* display определяет поведение элемента. block - отображение, как блочных */
margin: auto; /* margin определяет внешние отступы элемента */
margin-top: 10px; /* отступ верхней границы */
border-top-width: 1px; /* семейство border описывает рамку элемента */
border-left-width: 1px; /* толщина левой части рамки */
border-radius: 20px; /* радиус скругления углов рамки */
font-weight: bold; /* насыщенность начертания текста */
width: 170px; /* ширина элемента */
text-shadow: 0px 1px 0px #ccc; /* тень текста */
}
.infoStyle, .divNum, #block_of_numbers, .count {
text-align: center; /* выравнивание содержимого по центру */
}
.divNum {
display: inline-block;
}
#block_of_numbers {
margin: 5px;
}
#butStart {
background-color: rgb(22, 216, 132); /* цвет фона в системе RGB */
}
#butStop {
background-color: rgb(198, 58, 24, 0.5); /* здесь последний параметр - прозрачность*/
}
#butReset {
background-color: rgb(144, 150, 202);
}
.count {
background-color: #eee; /* запись в сокращённой шестнадцатеричной системе, полная - #eeeeee */
margin-left: 10px;
width: 30px;
border-radius: 5px;
}
</style>
</head>
<body>
.....
</body>
</html>
И скрипты, и стили могут быть прописаны непосредственно в элементах (стили в атрибутах style, JS в атрибутах описания событий), а так же вынесены во внешние файлы (css подключается через тег link, JS указывается в атрибуте src тега script).
Назад к 1С
При нажатии на кнопку или гиперссылку может возникнуть событие поля ПриНажатии. Особенностью мобильного приложения является то, что событие возникает только в случае перехода на другую страницу (в тонком клиенте нажатие на любую область ПоляHtml вызывает это событие).
В случае с гиперссылкой, достаточно заполнить значение атрибута href.
Пример:
<a href="//infostart.ru">Инфостарт</a>
В качестве кнопки, по сути, может выступать любой элемент, для которого доступны атрибуты событий, воспринимаемые мобильным приложением. Т.е. подойдёт всё, что может вызвать выполнение скрипта: button, input типа button, img и пр. Для инициации перехода нужно присвоить значение свойству документа location.href.
Пример:
<button ontouchstart="location.href='//infostart.ru'">Инфостарт</button>
Стоит учитывать, что если адрес ссылки начинается с символа #, то обработчик события ПриНажатии не сработает, т.к. это не будет переходом на другую страницу. Такие ссылки считаются якорными. Они обеспечивают переход (прокрутку страницы) к элементу с указанным после решётки id.
Если адрес ссылки не соответствует стандарту URL, то система дополнит его адресом локальной директории, приводя к нужному формату, вроде такого (пример из эмулятора):
http://localhost:1250/144153773/ТекстСсылки
Обработчик ПриНажатии имеет три параметра:
- Элемент - поле формы - ПолеHTML
- ДанныеСобытия - фиксированная структура с ключами (описание из СП)
- Anchor - Неопределено или элемент А, если нажали на ссылку
- Element - элемент, на который нажали
- Button - Неопределено или элемент input c типом button или элемент button, если нажали на кнопку
- Event - передаётся информация о событии, специфичная для используемого браузера
- Document - документ, являющийся владельцем элемента, на котором было произведено нажатие
- Href - Неопределено или значение поля Href элемента А. При этом, если в событии браузера используется ссылка с закодированными символами, не являющимися символами латинского алфавита, то в данном свойстве строка будет содержать раскодированные символы
- СтандартнаяОбработка - булево - признак, определяющий, будет ли выполнена стандартная обработка события
На момент написания статьи в мобильном приложении у параметра ДанныеСобытия заполняются только значения ключей Document и Href.
Через Document происходит обращение к тому же объекту, что и через ПолеHtml.Документ. Это ВнешнийОбъект содержащий в себе свойства HTML-документа. К ним относятся различные счётчики, характеристики документа, коллекции элементов разбитые по типам (например forms, images), элементы верхнего уровня (body, head), обработчики событий и пр. Значения некоторых свойств доступны только для чтения, другие можно менять.
Пример чтения значения свойства:
Сообщить(Элементы.ПолеHTML.Документ.body.children["div1"].innerHTML)
Пример программной установки содержимого HTML-документа:
Элементы.ПолеHtml.Документ.documentElement.innerHTML = "<head></head><body><div id='div1'>Привет мир!</div></body>"
Из особенностей программной установки/чтения свойств HTML-документа можно выделить то, что система не выдаёт ошибок, если имя свойства написано неправильно. Она просто игнорирует действие.
ПриНажатии срабатывает до формирования документа и, соответственно, до события ДокументСформирован. В рамках обработчика можно отменить переход, установив СтандартнаяОбработка в значение Ложь, выполнить нужные действия средствами 1С и при необходимости изменить содержимое страницы.
Дополним пример таймера чтением заранее заданных значений
В конфигурацию добавим справочник События, для хранения данных.
На форму добавим реквизит ТекущееСобытие (СправочникСсылка.Событие) и ИдентификаторСобытия (УникальныйИдентификатор).
Добавим в код HTML следующий блок:
<div id="options"><button ontouchstart="location.href='@CMND_save'">Сохранить</button><a id="currentVersion" href="@CMND_openVersions">Произвольное значение</a><button ontouchstart="location.href='@CMND_download'">Загрузить</button></div>
Дополним CSS:
#currentVersion {
background-color: #eee;
border-color: #555;
border-style: solid;
border-radius: 3px;
border-width: 1px;
padding: 3px;
margin: 5px;
}
#options {
text-align: center;
margin: 5px;
}
Для упрощения идентификации имён команд они записаны с префиксом @CMND_
Таким образом, у нас на страницу добавлены три команды: save, openVersions, download
Их обработка выглядит следующим образом:
&НаКлиенте
Процедура ПолеHtmlПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекстКоманды = "";
ТекущаяСсылка = ДанныеСобытия.href;
Если ЗначениеЗаполнено(ТекущаяСсылка) Тогда
Идентификатор = СтрНайти(ТекущаяСсылка, "&CMND_",НаправлениеПоиска.СКонца);
Если Идентификатор > 0 Тогда
ТекстКоманды = Сред(ТекущаяСсылка, Идентификатор+6);
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ТекстКоманды) Тогда
Если ТекстКоманды = "save" Тогда
ПоказатьВводСтроки(Новый ОписаниеОповещения("СохранитьЗначениеЗавершение", ЭтотОбъект),,"Укажите наименование",150);
ИначеЕсли ТекстКоманды = "openVersions" Тогда
ОткрытьФорму("Справочник.События.ФормаВыбора",Новый Структура("ТекущаяСтрока",ТекущееСобытие), ЭтотОбъект);
ИначеЕсли ТекстКоманды = "download" Тогда
ЗаполнитьВремяНаСтранице();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Также добавим обработку выбора События:
Остальной код формы обработки
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
ТекущееСобытие = ВыбранноеЗначение;
ЗаполнитьВремяНаСтранице();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьВремяНаСтранице()
ВремяИзСправочника = ПолучитьВремяИзСправочника();
Часы = Час(ВремяИзСправочника);
Минуты = Минута(ВремяИзСправочника);
Секунды = Секунда(ВремяИзСправочника);
document = Элементы.ПолеHTML.Документ;
input_count_H = document.getElementById("input_count_H");
input_count_M = document.getElementById("input_count_M");
input_count_S = document.getElementById("input_count_S");
version = document.getElementById("currentVersion");
input_count_H.value = Часы;
input_count_M.value = Минуты;
input_count_S.value = Секунды;
version.text = Строка(ТекущееСобытие);
КонецПроцедуры
&НаСервере
Функция ПолучитьВремяИзСправочника()
Возврат ТекущееСобытие.Время;
КонецФункции
&НаКлиенте
Процедура СохранитьЗначениеЗавершение(Результат, ДопПараметры) Экспорт
Если ЗначениеЗаполнено(Результат) Тогда
document = Элементы.ПолеHTML.Документ;
Время = '00010101';
Попытка
Время = Время + Число(document.getElementById("input_count_H").value)*3600;
Исключение
КонецПопытки;
Попытка
Время = Время + Число(document.getElementById("input_count_M").value)*60;
Исключение
КонецПопытки;
Попытка
Время = Время + Число(document.getElementById("input_count_S").value);
Исключение
КонецПопытки;
ИдентификаторСобытия = Новый УникальныйИдентификатор;
ФормаСобытия = ОткрытьФорму("Справочник.События.ФормаОбъекта",Новый Структура("Идентификатор", ИдентификаторСобытия));
ФормаСобытия.Объект.Наименование = Результат;
ФормаСобытия.Объект.Время = Время;
ФормаСобытия.Открыть();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ЗакрытиеСобытия"
И Параметр.Свойство("Идентификатор")
И Параметр.Идентификатор <> Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000")
И Параметр.Идентификатор = ИдентификаторСобытия Тогда
ТекущееСобытие = Параметр.Ссылка;
ЗаполнитьВремяНаСтранице();
КонецЕсли;
КонецПроцедуры
Собственно, на этом всё. Надеюсь, что информация была полезной
В прикреплённом архиве: четыре мобильные сборки для Android (собственно, поэтому такой размер) и конфигурация с приведённым примером (на случай, если кому-то недостаточно только текста).
Разработка конфигурации велась на платформе 8.3.24.1586. Мобильная сборка выполнена на 8.3.25.52.
P.S.: Если будете копировать код HTML из статьи, то обратите внимание на то, что в нём могут присутствовать непереносимые пробелы (это особенность редактора). Замените их обычными пробелами, иначе система может проигнорировать часть кода.