Разработчики при проектировании интерфейсов 1С часто сталкиваются с задачей копирования текстовой информации в буфер обмена операционной системы по нажатию одной кнопки. Если в тонком или толстом клиенте под управлением ОС Windows можно было обойтись простым использованием COM-объекта htmlfile, то в веб-клиенте (особенно в различных браузерах) этот подход не работает. Браузерные политики безопасности накладывают жесткие ограничения на прямой доступ к системному буферу обмена.
В данной статье мы подробно разберем, как решить проблему копирования текста в буфер обмена в веб-клиенте. Мы рассмотрим несколько подходов: от классического обходного пути с использованием Поля HTML-документа и JavaScript до современного нативного механизма, появившегося в платформе 1С:Предприятие.
Если вы работаете на современных версиях платформы 1С:Предприятие (начиная с 8.3.24), вам больше не требуются сложные манипуляции с HTML-полями и сторонним кодом JavaScript. Фирма «1С» добавила полноценный встроенный механизм для работы с системным буфером обмена, который функционирует во всех типах клиентов, включая веб-клиент.
Давайте разберем пример реализации этого метода по шагам. Для копирования используется глобальный встроенный объект СредстваБуфераОбмена. Поскольку работа с буфером в веб-среде является потенциально длительной и требует подтверждения прав безопасности у пользователя, вызовы выполняются асинхронно.
Проанализируем следующий пример программного кода:
&НаКлиенте
Асинх Процедура СкопироватьВБуферНативно(ТекстДляКопирования)
// Шаг 1. Проверяем доступность буфера в текущем окружении
Если СредстваБуфераОбмена.ИспользованиеДоступно() Тогда
// Шаг 2. Создаем элемент буфера обмена с указанием формата данных
ДанныеБуфера = Новый ЭлементБуфераОбмена(СтандартныйФорматДанныхБуфераОбмена.Текст, ТекстДляКопирования);
// Шаг 3. Асинхронно помещаем данные в буфер обмена
Попытка
Результат = Ждать СредстваБуфераОбмена.ПоместитьДанныеАсинх(ДанныеБуфера);
ПоказатьПредупреждение(, "Текст успешно скопирован в буфер обмена!");
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
ПоказатьПредупреждение(, "Не удалось скопировать данные: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
КонецПопытки;
Иначе
ПоказатьПредупреждение(, "Работа с буфером обмена не поддерживается в данном клиенте или браузере.");
ЕслиКонец;
КонецПроцедуры
Использование встроенного объекта СредстваБуфераОбмена — это наиболее надежный, безопасный и перспективный метод. Он автоматически учитывает особенности безопасности браузеров и не требует создания фиктивных элементов на форме.
Если ваша база работает на платформе версии ниже 8.3.24, вам придется использовать обходной путь через интеграцию JavaScript в контексте управляемой формы 1С. Для этого применяется элемент формы Поле HTML документа.
Давайте выясним причину, почему простая попытка вызвать JS-код напрямую из 1С может завершиться ошибкой вида 'document' - определение отсутствует. Дело в том, что объект document существует только внутри контекста веб-страницы (DOM-модели браузера). Из программного кода 1С напрямую обратиться к нему нельзя. Нам нужно загрузить HTML-страницу со встроенной JS-функцией внутрь Поля HTML-документа и вызывать ее через обращение к документу этого поля.
Выполним интеграцию по шагам:
ДанныеHTML (тип: Строка, длина: неограниченная).ПолеHTMLБуфер.ПриСозданииНаСервере или ПриОткрытии заполните этот реквизит базовой HTML-разметкой со скриптом копирования.Рассмотрим структуру загружаемого HTML-документа. Мы применим классический сценарий создания временного элемента ввода input, программного фокуса на нем, вызова команды копирования и последующего удаления элемента:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Заполняем HTML-код со встроенной JS-функцией
ДанныеHTML =
"<!DOCTYPE HTML>" +
"<html>" +
"<head>" +
" <meta charset=""utf-8"">" +
" <script>" +
" function copyToClipboard(text) {" +
" var copytext = document.createElement('textarea');" +
" copytext.value = text;" +
" document.body.appendChild(copytext);" +
" copytext.select();" +
" try {" +
" document.execCommand('copy');" +
" } catch (err) {" +
" console.error('Ошибка копирования:', err);" +
" }" +
" document.body.removeChild(copytext);" +
" }" +
" </script>" +
"</head>" +
"<body style=""margin:0; padding:0; overflow:hidden;"">" +
"</body>" +
"</html>";
КонецПроцедуры
Теперь для копирования текста нам достаточно вызвать JS-функцию copyToClipboard из модуля управляемой формы 1С. Разберем, как выглядит этот вызов при нажатии кнопки на форме:
&НаКлиенте
Процедура КомандаКопироватьТекст(Команда)
ТекстДляКопирования = "Этот текст попадет в буфер обмена из веб-клиента!";
// Получаем DOM-документ Поля HTML документа и вызываем функцию
ДокументHTML = Элементы.ПолеHTMLБуфер.Документ;
Если ДокументHTML <> Неопределено Тогда
// Обращаемся к родительскому окну (window) для вызова глобальной JS-функции
ДокументHTML.defaultView.copyToClipboard(ТекстДляКопирования);
КонецЕсли;
КонецПроцедуры
Важное примечание по совместимости: В коде выше вместо устаревшего свойства ParentWindow мы использовали стандартное свойство defaultView, которое поддерживается всеми современными браузерами и старым IE 11.
При использовании Метода 2 разработчики часто сталкиваются со следующей проблемой: Поле HTML-документа нужно только как «технический контейнер» для запуска JS-скрипта. Показывать его пользователю на форме нет никакой необходимости. Однако, если у элемента формы установить свойство Видимость = Ложь, то платформа 1С в целях оптимизации рендеринга вообще не будет создавать данный элемент в DOM-дереве веб-страницы. В результате свойство Элементы.ПолеHTMLБуфер.Документ вернет Неопределено, и вызвать функцию копирования станет невозможно.
Проанализируем способы обхода этого ограничения. Нам нужно сделать элемент невидимым для глаз пользователя, но сохранить его присутствие в интерфейсе для платформы. Выделим три эффективных варианта:
Видимость в значении Истина. В конфигураторе или программно сожмите элемент до минимальных размеров. Установите свойства:
Ширина = 1;Высота = 1;РастягиватьПоГоризонтали = Ложь;РастягиватьПоВертикали = Ложь.
<body style="display: none;">
Или задайте абсолютное позиционирование контейнера за пределами видимого экрана:
<body style="position: absolute; left: -9999px;">
Если вы хотите использовать современный веб-стандарт, то следует помнить, что метод document.execCommand('copy') официально признан устаревшим (хотя и поддерживается большинством браузеров ради обратной совместимости). Современным стандартом является асинхронный Clipboard API.
Его использование делает JS-код значительно чище, так как отпадает необходимость создавать временные теги input или textarea в документе. Вместо этого применяется метод navigator.clipboard.writeText().
Посмотрим на пример современной функции JavaScript, которую вы можете встроить в свое Поле HTML-документа:
async function copyToClipboardModern(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Текст успешно скопирован через Clipboard API');
} catch (err) {
console.error('Не удалось скопировать данные: ', err);
// Резервный вариант на случай ограничений безопасности
fallbackCopyToClipboard(text);
}
}
function fallbackCopyToClipboard(text) {
var copytext = document.createElement('textarea');
copytext.value = text;
document.body.appendChild(copytext);
copytext.select();
document.execCommand('copy');
document.body.removeChild(copytext);
}
Важное предупреждение (HTTPS-ограничение): Современный Clipboard API в целях безопасности работает исключительно в безопасном контексте (Secure Context). Это означает, что браузер разрешит его использование только в том случае, если ваш веб-клиент 1С запущен по протоколу HTTPS или на локальном сервере (localhost). Если публикация информационной базы использует обычный протокол HTTP, свойство navigator.clipboard вернет undefined. Именно поэтому в коде выше рекомендуется использовать конструкцию try-catch с откатом к классическому (резервному) методу создания временного поля ввода.
Подводя итог, при разработке конфигураций 1С рекомендуется всегда проверять версию платформы. Если у вас развернута версия 8.3.24 и выше — используйте нативный объект СредстваБуфераОбмена. Если же приходится поддерживать более ранние релизы, оптимальным решением станет интеграция HTML-поля со скрытием его размеров и вызовом гибридной JavaScript-функции.