Разработка под мобильную платформу 1С часто преподносит сюрпризы, особенно когда дело касается работы с богатым интерфейсом и форматированным текстом. Типичная задача: в базе данных на сервере хранится описание товара или задачи в формате HTML (со шрифтами, цветами и списками), и нам необходимо дать пользователю возможность редактировать этот текст прямо с экрана мобильного телефона.
Настольная версия 1С позволяет легко манипулировать объектной моделью документа (DOM) на клиенте через свойство Элементы.ИмяПоля.Документ. Однако на мобильной платформе и в мобильном клиенте этот функционал ограничен: прямого доступа к DOM-модели на клиенте нет. Попытка вызвать подобные методы на телефоне приведет к ошибке.
В этой статье мы подробно проанализируем, почему популярные «кустарные» методы работы со строками HTML опасны, и разберем три надежных профессиональных способа решения этой задачи.
Начинающие разработчики часто пытаются обойти ограничение платформы простым путем: раз мы не можем достучаться до документа программно, давайте отредактируем саму строку HTML как обычный текст. В исходном обсуждении на форуме было предложено следующее решение:
&НаКлиенте
Процедура ТекстОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
Если ЗначениеЗаполнено(Объект.Описание) Тогда
ДлинаТекстаHTML = СтрДлина(Объект.Описание);
ОкончаниеТекстаHTML = Прав(Объект.Описание,15);
КоличествоСимволовОкончание = СтрДлина(Прав(Объект.Описание,15));
ДлинаМинус = ДлинаТекстаHTML - КоличествоСимволовОкончание;
НовыйТекст = "<p>" + Текст + "</p>";
ПолучитьТекстHTML = Сред(Объект.Описание, 1,ДлинаМинус);
Объект.Описание = ПолучитьТекстHTML + НовыйТекст + ОкончаниеТекстаHTML;
Иначе
НачалоТекстаHTML = Строка ("<html><body>");
КонецТекстHTML = Строка ("</body></html>");
НовыйТекст = "<p>" + Текст + "</p>";
Объект.Описание = НачалоТекстаHTML + НовыйТекст + КонецТекстHTML;
КонецЕсли;
КонецПроцедуры
Почему этот код крайне опасен и его нельзя использовать в реальных проектах?
Алгоритм жестко завязан на то, что закрывающие теги документа (</body></html>) занимают ровно 15 символов в конце строки. Рассмотрим, почему это быстро сломает базу данных:
> </html>). В результате обрезки нарушится целостность тегов, документ перестанет открываться, а стили отображения «поплывут».Рассмотрим правильные подходы, которые предоставляет платформа 1С для решения этой задачи.
Начиная с современных версий мобильной платформы 1С, разработчикам доступен полноценный нативный инструмент — объект ФорматированныйДокумент. Он автоматически адаптирует панель форматирования под сенсорные экраны телефонов, предоставляя удобный интерфейс без написания сложного кода.
Разберем реализацию этого способа по шагам:
Шаг 1. Создание реквизитов формы
В управляемой форме мобильного приложения создадим новый реквизит. Назовем его ОписаниеФорматированное и установим для него тип данных ФорматированныйДокумент. Сам исходный текст (в формате HTML) будет по-прежнему храниться в реквизите объекта базы данных (например, Объект.Описание с типом Строка).
Шаг 2. Размещение на форме
Перетащим реквизит ОписаниеФорматированное на рабочую область формы. Платформа автоматически создаст элемент управления с видом Поле форматированного документа. На мобильном устройстве этот элемент превратится в полноценное поле ввода с кнопками форматирования (шрифт, цвет, списки, выравнивание).
Шаг 3. Чтение данных на сервере
При открытии формы или чтении объекта нам необходимо преобразовать текстовую строку HTML из базы данных в объект форматированного документа, понятный элементу формы. Напишем код в обработчике:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Преобразуем сохраненный HTML-код в объект форматированного документа
ОписаниеФорматированное.УстановитьHTML(ТекущийОбъект.Описание, Новый Структура);
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Если это новый документ, инициализируем пустое поле
Если Не ЗначениеЗаполнено(Объект.Ссылка) Тогда
ОписаниеФорматированное.УстановитьHTML("", Новый Структура);
КонецЕсли;
КонецПроцедуры
Шаг 4. Сохранение изменений на сервере
Перед записью объекта нам нужно выполнить обратную операцию — извлечь отформатированный текст из элемента формы, перевести его в стандартную HTML-строку и записать в базу данных:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
ТекстHTML = "";
// Выгружаем данные из форматированного документа в строку HTML
ОписаниеФорматированное.ПолучитьHTML(ТекстHTML, Новый Структура);
ТекущийОбъект.Описание = ТекстHTML;
КонецПроцедуры
Этот метод является самым простым, надежным и поддерживается платформой «из коробки». Пользователь получает интуитивно понятный мобильный интерфейс для редактирования.
Если перед нами стоит задача не ручного редактирования, а программного добавления системного текста (например, добавление подписи «Отправлено с мобильного устройства» или штампа времени) без повреждения структуры HTML, необходимо использовать полноценную работу с объектной моделью документа (DOM) на стороне сервера.
Посмотрим на пример функции, которая корректно разбирает HTML, находит тело документа <body>, добавляет новый абзац и собирает HTML обратно:
&НаСервере
Функция ДобавитьАбзацВHTMLДокумент(ИсходныйHTML, ТекстНовогоАбзаца) Экспорт
// Инициализируем чтение HTML-строки
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.УстановитьСтроку(ИсходныйHTML);
// Создаем построитель DOM и считываем документ
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеHTML);
ЧтениеHTML.Закрыть();
// Создаем новый элемент абзаца <p>
НовыйЭлементP = ДокументDOM.СоздатьЭлемент("p");
// Создаем текстовое содержимое для нашего абзаца
НовыйТекст = ДокументDOM.СоздатьТекст(ТекстНовогоАбзаца);
НовыйЭлементP.ДобавитьДочерний(НовыйТекст);
// Безопасно добавляем абзац строго внутрь тега <body>
Если ДокументDOM.Тело <> Неопределено Тогда
ДокументDOM.Тело.ДобавитьДочерний(НовыйЭлементP);
Иначе
// Если тег body отсутствует, добавляем в корень документа
ДокументDOM.ДобавитьДочерний(НовыйЭлементP);
КонецЕсли;
// Выполняем обратную запись структуры в строку HTML
ЗаписьHTML = Новый ЗаписьHTML;
ЗаписьHTML.УстановитьСтроку();
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьHTML);
ВозвращаемыйHTML = ЗаписьHTML.Закрыть();
Возврат ВозвращаемыйHTML;
КонецФункции
При использовании этого подхода структура вашего HTML гарантированно останется валидной. Никакие служебные теги не будут обрезаны или затерты.
Бывают ситуации, когда стандартный дизайн встроенной панели форматирования 1С не подходит под уникальный фирменный стиль вашего мобильного приложения. В этом случае мы можем встроить в обычное Поле HTML документа сторонний легковесный визуальный HTML-редактор, написанный на JavaScript (например, Quill, TinyMCE или NicEdit).
Основная сложность здесь — передать измененный текст из веб-разметки обратно в код 1С на мобильном устройстве, так как прямое чтение свойства Документ заблокировано на мобильном клиенте.
Для решения этой проблемы мы применим механизм перехвата навигации по специальным URI-схемам (протокол v8action://).
Шаг 1. Подготовка HTML-шаблона с JS-редактором
Внутри вашего HTML-кода, который загружается в поле, должен быть JS-скрипт. При изменении текста редактором (или при нажатии на кнопку сохранения в HTML) должен выполняться переход по специальной ссылке:
function sendDataTo1C(htmlContent) {
// Кодируем содержимое для передачи в URL
var safeContent = encodeURIComponent(htmlContent);
// Инициируем переход, который перехватит платформа 1С
window.location.href = "v8action://saveText?data=" + safeContent;
}
Шаг 2. Обработка события в модуле управляемой формы 1С
Для элемента формы Поле HTML документа определим событие ПриНажатии (в некоторых версиях платформы используется событие ПриРегулировании). Напишем код обработчика:
&НаКлиенте
Процедура ПолеHTMLОписаниеПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
АдресПерехода = ДанныеСобытия.ПереходСоСсылки;
// Проверяем, является ли ссылка нашей системной командой
Если Найти(АдресПерехода, "v8action://saveText") > 0 Тогда
// Отменяем стандартный переход браузера по ссылке
СтандартнаяОбработка = Ложь;
// Выделяем полезные данные из параметров URL
ПозицияДанных = Найти(АдресПерехода, "?data=");
Если ПозицияДанных > 0 Тогда
ЗакодированныйТекст = Сред(АдресПерехода, ПозицияДанных + 6);
// Декодируем полученную HTML-строку
ДекодированныйТекст = ДекодироватьСтроку(ЗакодированныйТекст, СпособКодированияСтроки.КодировкаURL);
// Записываем результат в реквизит объекта
Объект.Описание = ДекодированныйТекст;
ПоказатьПредупреждение(, "Текст успешно передан и сохранен в 1С!");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование протокола взаимодействия v8action:// позволяет выстраивать гибкие, красивые интерактивные интерфейсы мобильных приложений, объединяя мощь веб-технологий (HTML/CSS/JS) и надежность бизнес-логики платформы 1С.
Мы проанализировали проблему работы с форматированным текстом в мобильной среде 1С. Помните, что простые решения со строковыми функциями вроде Прав() и Сред() в случае с разметкой HTML приводят к неминуемому искажению данных. Используйте нативный объект ФорматированныйДокумент для стандартных задач, серверную обработку DOM для автоматических корректировок и интеграцию через v8action для нестандартных интерфейсных решений.