При разработке интерфейсов в «1С:Предприятие 8» перед разработчиками нередко возникает задача жесткого ограничения ввода текста пользователем. Типичный пример — ограничение многострочного поля ввода, где необходимо контролировать как общую длину текста (например, до 400 символов), так и формат строк (например, не более 8 строк, каждая из которых должна содержать максимум 50 символов). Такая задача часто встречается при интеграции 1С со сторонними сервисами (API банков, логистических операторов, маркетплейсов или государственных систем), где установлены жесткие лимиты на длину текстовых полей.
Попытка решить эту задачу с помощью стандартного свойства «Маска» у поля ввода быстро заводит в тупик. Свойство Маска в платформе 1С предназначено исключительно для однострочных структурированных данных фиксированной длины (например, для ввода номеров телефонов, ИНН, СНИЛС или кодов). Для динамического многострочного текста маска не применима.
В этой статье мы подробно разберем четыре эффективных способа реализации такого ограничения на управляемых формах 1С:Предприятия. Мы проанализируем преимущества и недостатки каждого подхода, а также приведем готовые примеры кода.
Это самый простой в реализации и самый надежный с точки зрения стабильности платформы способ. Мы не мешаем пользователю вводить текст так, как ему удобно, но при попытке сохранить документ или нажать кнопку «ОК» выполняем жесткую проверку введенных данных. Если текст нарушает правила, мы выводим понятное сообщение об ошибке и отменяем действие.
Разберем, как реализовать этот алгоритм. Нам понадобятся стандартные функции работы со строками: СтрЧислоСтрок(), СтрПолучитьСтроку() и СтрДлина().
Добавим на форму проверку перед записью объекта:
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
// Вызываем функцию проверки на клиенте
Если НЕ ПроверитьМногострочныйТекст(Объект.МногострочноеПоле) Тогда
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Теперь напишем саму функцию валидации. Разместим ее на клиенте без контекста для максимального быстродействия:
&НаКлиентеБезКонтекста
Функция ПроверитьМногострочныйТекст(Знач Текст) Экспорт
МаксимальноеКоличествоСтрок = 8;
МаксимальнаяДлинаСтроки = 50;
МаксимальнаяОбщаяДлина = 400;
ОбщаяДлина = СтрДлина(Текст);
// Проверка 1: Ограничение на общую длину текста
Если ОбщаяДлина > МаксимальнаяОбщаяДлина Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Общая длина текста не должна превышать " + МаксимальнаяОбщаяДлина + " символов (сейчас " + ОбщаяДлина + ")!'"),
,
"Объект.МногострочноеПоле"
);
Возврат Ложь;
КонецЕсли;
КоличествоСтрок = СтрЧислоСтрок(Текст);
// Проверка 2: Ограничение на количество строк
Если КоличествоСтрок > МаксимальноеКоличествоСтрок Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Допускается вводить не более " + МаксимальноеКоличествоСтрок + " строк!'"),
,
"Объект.МногострочноеПоле"
);
Возврат Ложь;
КонецЕсли;
// Проверка 3: Построчный анализ длины
Для НомерСтроки = 1 По КоличествоСтрок Цикл
ТекущаяСтрока = СтрПолучитьСтроку(Текст, НомерСтроки);
ДлинаСтроки = СтрДлина(ТекущаяСтрока);
Если ДлинаСтроки > МаксимальнаяДлинаСтроки Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Строка № " + НомерСтроки + " слишком длинная (" + ДлинаСтроки + " симв.). Максимум: " + МаксимальнаяДлинаСтроки + ".'"),
,
"Объект.МногострочноеПоле"
);
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Преимущества метода:
Недостатки: плохой UX (пользовательский опыт). Пользователь узнает об ошибке только в самом конце, когда нажимает кнопку сохранения, что может вызывать раздражение при частой работе с формой.
Для улучшения UX мы можем контролировать ввод пользователя непосредственно в процессе написания текста. Для этого в платформе 1С управляемых форм предусмотрено событие ИзменениеТекстаРедактирования у элемента формы «Поле ввода».
При использовании этого метода крайне важно правильно настроить свойства элемента формы. По умолчанию свойство «Обновление текста редактирования» установлено в значение «Всегда». Если оставить его в таком состоянии, то при любой программной модификации текста (например, при обрезке лишних символов в коде) курсор пользователя будет сбрасываться в начало или конец поля, делая ввод невозможным. Нам необходимо установить это свойство в значение «При изменении значения».
Рассмотрим код обработчика события:
&НаКлиенте
Процедура МногострочноеПолеИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
МаксСтрок = 8;
МаксДлинаСтроки = 50;
КоличествоСтрок = СтрЧислоСтрок(Текст);
ТекстМодифицирован = Ложь;
МассивНовыхСтрок = Новый Массив;
// Если пользователь превысил лимит строк, отсекаем лишние строки
РабочееКоличествоСтрок = Мин(КоличествоСтрок, МаксСтрок);
Если КоличествоСтрок > МаксСтрок Тогда
ТекстМодифицирован = Истина;
КонецЕсли;
Для НомерСтроки = 1 По РабочееКоличествоСтрок Цикл
ТекущаяСтрока = СтрПолучитьСтроку(Текст, НомерСтроки);
// Если длина строки превышает 50 символов, обрезаем ее
Если СтрДлина(ТекущаяСтрока) > МаксДлинаСтроки Тогда
ТекущаяСтрока = Лев(ТекущаяСтрока, МаксДлинаСтроки);
ТекстМодифицирован = Истина;
КонецЕсли;
МассивНовыхСтрок.Добавить(ТекущаяСтрока);
КонецЦикла;
// Если текст претерпел изменения, принудительно обновляем его в поле ввода
Если ТекстМодифицирован Тогда
СтандартнаяОбработка = Ложь;
Текст = СтрСоединить(МассивНовыхСтрок, Символы.ПС);
КонецЕсли;
КонецПроцедуры
Важное предупреждение: Внутри обработчика ИзменениеТекстаРедактирования категорически запрещено делать вызовы процедур или функций с директивой &НаСервере. Серверные вызовы в момент ввода текста вызовут микрозадержки («фризы») интерфейса, что сделает работу пользователя некомфортной.
Преимущества метода: интерактивность. Система физически не позволяет пользователю ввести некорректные данные в поле.
Недостатки: при достижении лимитов автообрезка текста может «скачкообразно» влиять на положение курсора в зависимости от версии платформы 1С и используемого браузера (в веб-клиенте).
Интересный альтернативный подход, предложенный участниками форума, заключается в разделении интерфейсного ввода и хранения данных. На форме мы создаем не одно многострочное поле, а ровно 8 отдельных независимых полей ввода (каждое с ограничением длины в 50 символов в свойствах элемента формы — свойство «Длина»). Для пользователя это будет выглядеть как структурированный бланк.
При записи эти поля собираются в единую строку с разделителями, а при открытии формы — автоматически разбираются обратно.
Рассмотрим реализацию этого механизма на сервере:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Разбираем сохраненную многострочную строку в отдельные реквизиты формы
ТекстИсточник = ТекущийОбъект.МногострочноеПоле;
Для НомерСтроки = 1 По 8 Цикл
ЭтотОбъект["СтрокаФормы" + НомерСтроки] = СтрПолучитьСтроку(ТекстИсточник, НомерСтроки);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Собираем данные из полей формы обратно в один реквизит базы данных
МассивСтрок = Новый Массив;
Для НомерСтроки = 1 По 8 Цикл
ТекущееЗначение = ЭтотОбъект["СтрокаФормы" + НомерСтроки];
МассивСтрок.Добавить(ТекущееЗначение);
КонецЦикла;
ТекущийОбъект.МногострочноеПоле = СтрСоединить(МассивСтрок, Символы.ПС);
КонецПроцедуры
Преимущества метода:
Недостатки: плохой UX при непрерывном вводе текста. Пользователю приходится вручную переключаться (клавишей Tab или мышкой) на следующую строчку, когда текущая заполнилась, что неудобно для ввода связного текста.
Для достижения идеального результата и бесшовного контроля ввода можно использовать элемент формы «Поле HTML-документа». Вместо стандартного текстового поля мы внедряем на форму мини-страницу со стандартным HTML-тегом textarea, логика поведения которого гибко контролируется скриптом на JavaScript.
Этот метод гарантирует, что курсор не будет «прыгать», а лишние символы и новые строки будут мягко блокироваться непосредственно в момент нажатия клавиш на стороне клиента.
Посмотрим, как настроить такую интеграцию. При создании формы на сервере инициализируем HTML-содержимое:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартноеОформление)
// Формируем HTML-код текстового поля с JS-обработчиком
ТекстHTML =
"<html>
|<head>
|<style>
| body { margin: 0; padding: 0; overflow: hidden; }
| textarea {
| width: 100%;
| height: 100%;
| box-sizing: border-box;
| font-family: Arial, sans-serif;
| font-size: 14px;
| resize: none;
| }
|</style>
|</head>
|<body>
|<textarea id='inputArea' oninput='validateText(this)'></textarea>
|<script>
| function validateText(ta) {
| var maxLines = 8;
| var maxChars = 50;
| var lines = ta.value.split('\n');
| var modified = false;
|
| if (lines.length > maxLines) {
| lines = lines.slice(0, maxLines);
| modified = true;
| }
|
| for (var i = 0; i < lines.length; i++) {
| if (lines[i].length > maxChars) {
| lines[i] = lines[i].substring(0, maxChars);
| modified = true;
| }
| }
|
| if (modified) {
| var selStart = ta.selectionStart;
| var selEnd = ta.selectionEnd;
| ta.value = lines.join('\n');
| ta.setSelectionRange(selStart, selEnd);
| }
| // Отправляем данные обратно в 1С через событие
| window.location.href = 'v8code://textchanged?data=' + encodeURIComponent(ta.value);
| }
|</script>
|</body>
|</html>";
ПолеHTMLКод = ТекстHTML;
КонецПроцедуры
Для передачи измененного текста обратно в реквизит 1С мы перехватываем навигацию в Поле HTML-документа через стандартное событие ПриНажатии (или обработку навигации в зависимости от версии платформы):
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Перехватываем специальную схему URL, которую мы сформировали в JS
АдресПерехода = ДанныеСобытия.Document.location.href;
Если Найти(АдресПерехода, "v8code://textchanged") > 0 Тогда
СтандартнаяОбработка = Ложь;
// Извлекаем и декодируем текст
ПараметрыСтроки = Сред(АдресПерехода, Найти(АдресПерехода, "?data=") + 6);
Объект.МногострочноеПоле = ДекодироватьСтроку(ПараметрыСтроки, СпособКодированияСтроки.КодировкаURL);
КонецЕсли;
КонецПроцедуры
Преимущества метода: безупречный UX. Веб-технологии позволяют управлять поведением текстового курсора и вводимых символов гораздо плавнее и точнее, чем платформенные механизмы 1С.
Недостатки: относительная сложность отладки и поддержки кода, необходимость знания JavaScript и особенностей работы движка рендеринга HTML на различных клиентах.
Мы проанализировали различные методы решения задачи ограничения многострочного ввода в 1С. Выбор конкретного метода зависит от требований к интерфейсу вашего прикладного решения: