Приветствуем вас, коллеги! Сегодня мы разберем крайне интересную и распространенную архитектурную задачу, с которой часто сталкиваются разработчики при создании гибких интерфейсов. Представьте сценарий: в вашей системе есть макеты текстовых документов (например, договоров, протоколов или соглашений). В этих макетах содержатся параметры вида [ИмяПараметра]. По нажатию кнопки система считывает макет, заполняет параметры актуальными данными из базы, переводит результат в строки таблицы значений и выводит их пользователю на форму для редактирования.
Пользователь изучает полученные строки и по условию задачи имеет полное право изменять непараметризованный (статический) текст вручную прямо на форме. Но что происходит, когда пользователь возвращается к заполнению данных, меняет какой-то реквизит на форме и снова нажимает кнопку заполнения? Если мы просто перезаполним строки заново из макета, все ручные правки пользователя бесследно исчезнут. Если же мы попытаемся применить функцию СтрЗаменить напрямую к измененному пользователем тексту, то столкнемся с проблемой: маркеры параметров (квадратные скобки) после первой замены уже исчезли, превратившись в обычные слова. Простой поиск подстроки начнет приводить к ложным срабатываниям и портить пользовательский текст. Выясним, как элегантно и надежно решить эту проблему несколькими способами.
Разберем самый надежный классический подход, предложенный участниками обсуждения. Чтобы не терять структуру исходного текста и иметь возможность обновлять только нужные переменные, нам необходимо разделить отображаемые данные и логику их хранения.
Для этого мы добавим в нашу таблицу значений скрытую колонку (например, ДанныеШаблона) или заведем параллельную структуру на сервере формы. В этой структуре для каждой строки таблицы мы будем хранить исходный шаблон с маркерами, текущие значения параметров и уникальный идентификатор строки (номер пункта).
Рассмотрим алгоритм по шагам:
Посмотрим на пример реализации инициализации структуры хранения шаблонов:
// Создаем структуру для хранения исходного состояния шаблонов строк
СтруктураКэша = Новый Структура;
Для Каждого СтрокаТЗ Из ТаблицаНаФорме Цикл
ИдентификаторСтроки = СтрокаТЗ.НомерПункта; // Уникальный ключ строки
ДанныеСтроки = Новый Структура;
ДанныеСтроки.Вставить("Шаблон", "Кооператив создается за счет [ОбязательныеВзносы] взносов, осуществляет [ВидыДеятельности] деятельность.");
СтруктураПараметров = Новый Структура;
СтруктураПараметров.Вставить("ОбязательныеВзносы", "вступительных");
СтруктураПараметров.Вставить("ВидыДеятельности", "инновационную");
ДанныеСтроки.Вставить("Параметры", СтруктураПараметров);
СтруктураКэша.Вставить("К_" + ИдентификаторСтроки, ДанныеСтроки);
КонецЦикла;
При повторном обновлении параметров мы выполняем сопоставление по ключу ИдентификаторСтроки. Мы берем старое значение параметра из кэша, ищем его в отредактированной пользователем строке и заменяем на новое значение параметра, после чего обновляем кэш параметров новыми значениями. Это исключает необходимость заново перечитывать макет и полностью затирать изменения пользователя.
Проанализируем изящный способ, который позволяет отказаться от хранения сложных скрытых структур и работать непосредственно с текстом в таблице значений. Проблема обычного текста в том, что после замены параметра [ОбязательныеВзносы] на значение вступительных мы теряем границы этого значения. Программа больше не знает, где заканчивается параметр и где начинается статический текст.
Мы можем программно «пометить» границы заменяемых параметров невидимыми для пользователя символами Юникода. Отличным кандидатом для этого является символ пробела нулевой ширины — Zero-Width Space (код U+200B, в 1С его можно получить как СтрСимвол(8203)).
Посмотрим, как это работает на практике:
СтрСимвол(8203) + ЗначениеПараметра + СтрСимвол(8203).за счет вступительных взносов. Спецсимволы абсолютно невидимы в стандартных текстовых полях.8203 и заменяем только содержимое между ними.Рассмотрим пример кода для обработки строки с невидимыми маркерами:
Функция ОбновитьПараметрВТексте(Знач ТекстоваяСтрока, Знач СтароеЗначение, Знач НовоеЗначение) Экспорт
Маркер = СтрСимвол(8203);
// Формируем строгие границы старого и нового параметров с маркерами
СтарыйШаблонПоиска = Маркер + СтароеЗначение + Маркер;
НовыйШаблонЗамены = Маркер + НовоеЗначение + Маркер;
// Выполняем замену только внутри маркированных зон
Возврат СтрЗаменить(ТекстоваяСтрока, СтарыйШаблонПоиска, НовыйШаблонЗамены);
КонецФункции
Этот метод чрезвычайно прост в реализации, не требует поддержки громоздких таблиц соответствия и надежно защищает статический текст пользователя от случайных замен, так как вероятность ввода пользователем символа U+200B вручную стремится к нулю.
Если специфика вашей задачи допускает изменение элемента управления на форме, настоятельно рекомендуем рассмотреть переход от стандартной Таблицы значений к Полю HTML-документа. Это веб-ориентированный стандарт для работы с динамическими шаблонами.
Этот подход решает проблему на уровне самого интерфейса ввода:
contenteditable="true". Это позволяет пользователю кликать на текст и редактировать его прямо на форме.<span> с уникальными идентификаторами (id="ИмяПараметра") и атрибутом contenteditable="false", который полностью запрещает пользователю редактировать эти области.При повторном обновлении данных вам достаточно программно обратиться к DOM-модели HTML-документа в 1С и обновить содержимое конкретных тегов по их id. Пользовательский текст при этом гарантированно останется нетронутым.
Рассмотрим пример формирования HTML-строки:
HTMLТекст = "
|<html>
|<body>
| <span contenteditable=""true"">Кооператив создается за счет </span>
| <span id=""ОбязательныеВзносы"" contenteditable=""false"" style=""background-color: #e0f0ff;"">вступительных</span>
| <span contenteditable=""true""> взносов, осуществляет </span>
| <span id=""ВидыДеятельности"" contenteditable=""false"" style=""background-color: #e0f0ff;"">инновационную</span>
| <span contenteditable=""true""> деятельность.</span>
|</body>
|</html>";
Пользователь сможет редактировать любые части предложений, но области с параметрами (подсвеченные нежно-голубым цветом для юзабилити) останутся защищенными от ручного изменения и будут мгновенно обновляться кодом 1С при изменении связанных реквизитов.
Для реализации аналогичного разделения прав редактирования в рамках чисто объектной модели платформы 1С без написания HTML-кода можно использовать встроенный объект ФорматированныйДокумент.
Мы можем разбить исходный шаблон на коллекцию элементов документа. Статические блоки текста добавляются как обычные текстовые элементы, доступные для интерактивного редактирования в поле форматированного документа на форме. Динамические же параметры оформляются в виде отдельных элементов со специфическим оформлением (например, подчеркиванием или другим цветом текста).
При необходимости обновления параметров мы программно обходим коллекцию элементов форматированного документа, находим элементы параметров по их позиции или метаданным и меняем их текстовое представление. Этот подход более сложен в программной реализации контроля удаления элементов пользователем, но обеспечивает отличный нативный внешний вид.
Если вы хотите сохранить простоту хранения данных в обычной строковой колонке таблицы значений и не хотите использовать спецсимволы, можно применить алгоритм контекстных якорей.
Для каждого параметра в скрытых служебных колонках строки таблицы значений мы сохраняем уникальные «якоря» — несколько символов текста, находящихся непосредственно слева и справа от параметра в оригинальном шаблоне.
Рассмотрим, как работает поиск параметра по якорям:
[ОбязательныеВзносы] левым якорем будет подстрока: "за счет "." взносов".Этот метод требует аккуратной обработки исключений на случай, если пользователь полностью удалил фрагменты текста, содержащие сами якоря. В такой ситуации система должна выдать предупреждение или мягко откатиться к исходному шаблону строки.
Выбор конкретного метода зависит от требований к интерфейсу вашей задачи. Если вам важна простота доработки существующего кода — используйте Решение 1 (скрытый кэш шаблонов) или Решение 2 (невидимые Юникод-маркеры). Если же вы проектируете систему с нуля и хотите предоставить пользователю максимальное удобство редактирования с четким визуальным разделением переменных и статического текста — смело выбирайте Решение 3 (Поле HTML-документа). Удачи в разработке!