Разработчики систем на платформе 1С:Предприятие часто сталкиваются с необходимостью кастомизации справочной информации. Например, когда требуется вывести стандартную справку объекта метаданных в своем собственном интерфейсном окне, добавить интерактивные элементы управления или динамически скрывать конфиденциальные разделы справки в зависимости от прав текущего пользователя.
При попытке решить эту задачу "в лоб" через встроенный язык мы неизбежно сталкиваемся с жестким ограничением платформы. Свойство Справка у любого объекта метаданных в режиме выполнения всегда возвращает Неопределено. Официальная документация подтверждает: программный доступ к этому свойству во встроенном языке не предусмотрен.
В этой статье мы подробно разберем, как обойти это ограничение, рассмотрим несколько альтернативных технических подходов, проанализируем их плюсы и минусы, а также предложим наиболее гибкое архитектурное решение.
Если нам необходимо получить текст оригинальной справки без выгрузки конфигурации, мы можем использовать интерактивный перехват. Платформа предоставляет метод ОткрытьСправку(), который открывает стандартное окно. Мы можем программно обратиться к коллекции открытых окон приложения, найти окно справки и извлечь его содержимое.
Рассмотрим пример реализации этого подхода:
// Открываем стандартное окно справки для нужного объекта
ОткрытьСправку("Справочник.Номенклатура.Форма.ФормаЭлемента");
// Получаем коллекцию всех открытых окон в сеансе
ОкнаПриложения = ПолучитьОкна();
Для Каждого ТекОкно Из ОкнаПриложения Цикл
// Находим окно справки по специфическим признакам
Если ТекОкно.Основное = Ложь И ТекОкно.Заголовок = "Справка" Тогда
Попытка
// Получаем доступ к содержимому HTML-документа окна
ДокументHTML = ТекОкно.Содержимое[0];
СсылкиОкна = ДокументHTML.HLinks;
// Здесь мы можем прочитать HTML-текст справки
ТекстСправки = ДокументHTML.Document.body.innerHTML;
// Закрываем окно, чтобы пользователь не заметил его открытия
ТекОкно.Закрыть();
Прервать;
Исключение
ЗаписьЖурналаРегистрации("ПолучениеСправки", УровеньЖурналаРегистрации.Предупреждение, , , "Не удалось получить содержимое окна справки.");
КонецПопытки;
КонецЕсли;
КонецЦикла;
Особенности метода: Этот способ отлично работает в режиме толстого клиента (обычные формы). Однако у него есть существенные недостатки: кратковременное мерцание экрана при открытии и закрытии окна, а также нестабильность работы в веб-клиенте и тонком клиенте управляемого приложения. Для решения проблемы мерцания некоторые разработчики используют запуск фонового сеанса на сервере, который в скрытом режиме открывает окно и забирает текст, но такой подход крайне ресурсоемок.
Стандартный способ получения текстов справки, заложенный создателями платформы, заключается в выгрузке файлов конфигурации. При запуске Конфигуратора из командной строки с параметром /DumpConfigFiles и ключом -Help все тексты встроенных справок сохраняются на диск в формате HTML.
Для оптимизации этого процесса, чтобы не выгружать терабайты файлов всей конфигурации, мы можем настроить выборочную выгрузку только необходимых объектов. Разберем по шагам, как настроить этот процесс:
list.txt).ЗапуститьПриложение().Посмотрим на пример кода автоматизации выгрузки:
ПутьККаталогуВыгрузки = "C:\HelpExport\";
ПутьКПлатформе = "C:\Program Files\1cv8\8.3.20.1613\bin\1cv8.exe";
ПараметрыСоединения = "/F ""C:\Bases\Trade"" /N ""Администратор"" /P ""Пароль""";
ПараметрыВыгрузки = "DESIGNER " + ПараметрыСоединения + " /DumpConfigFiles """ + ПутьККаталогуВыгрузки + """ -Help";
КодВозврата = Неопределено;
ЗапуститьПриложение(ПутьКПлатформе + " " + ПараметрыВыгрузки, , Истина, КодВозврата);
Если КодВозврата = 0 Тогда
// Файлы выгружены. Считываем HTML-файл нужного объекта
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ПутьККаталогуВыгрузки + "Справочник.Номенклатура.html", КодировкаТекста.UTF8);
ТекстHTML = ТекстовыйДокумент.ПолучитьТекст();
Иначе
ВызватьИсключение "Ошибка выполнения выгрузки конфигурации пакетом.";
КонецЕсли;
Особенности метода: Метод является официальным и гарантирует получение точного текста оригинальной справки. Главный минус — медленная скорость выполнения. Рекомендуется запускать эту процедуру регламентным заданием в ночное время (или в процессе обновления конфигурации), кэшируя результаты работы в базу данных. Для автоматизации процесса частичного экспорта объектов подойдёт обработка для выборочной выгрузки метаданных в файлы.
Если база данных работает в клиент-серверном режиме, наиболее быстрым и технологичным решением является прямое чтение таблиц СУБД. Вся конфигурация, включая справки, хранится в бинарном виде в таблице Config.
Выясним логику хранения данных в СУБД:
Config, где поле FileName содержит внутренний идентификатор (UUID) объекта справки.BinaryData в сжатом формате (обычно используется сжатие deflate/zlib).Проанализируем алгоритм извлечения справки через SQL:
Посмотрим на пример реализации запроса:
// Строка подключения к SQL Server
СтрокаПодключения = "Provider=SQLOLEDB.1;Data Source=SQL_SERVER;Initial Catalog=Trade_DB;User ID=sa;Password=secret;";
Connection = Новый COMОбъект("ADODB.Connection");
Connection.Open(СтрокаПодключения);
// Имя файла справки для объекта с известным UUID
ИмяФайлаСправки = "meta/help/8cb433de-c9d3-4e63-8ef1-944d1567bc94.html";
Query = "SELECT BinaryData FROM Config WHERE FileName = '" + ИмяФайлаСправки + "'";
Recordset = Connection.Execute(Query);
Если Не Recordset.EOF Тогда
СжатыеДанные = Recordset.Fields("BinaryData").Value;
// Выполняем распаковку и перевод бинарных данных в строку HTML
ТекстСправкиHTML = РаспаковатьБинарныйПоток(СжатыеДанные);
КонецЕсли;
Особенности метода: Это самый быстрый способ получения справки "на лету" без блокировок и запуска тяжелых процессов Конфигуратора. Однако данный метод требует прав администратора СУБД, усложняет архитектуру (привязка к конкретному типу SQL) и не работает в файловом режиме базы данных.
Если перед вами стоит задача не просто показать справку, но и гибко управлять ее выводом (например, скрывать разделы в зависимости от прав доступа пользователей), лучшим решением будет отказаться от стандартного реквизита "Справка" объектов метаданных.
Вместо этого мы можем использовать собственную подсистему хранения и вывода справок. Это типовой подход, используемый во многих современных тиражных решениях и библиотеках (таких как БСП). Проанализируем этот подход по шагам.
Вместо заполнения свойства "Справочная информация" в окне редактирования объекта, мы создаем у этого же объекта макет с типом HTML-документ. Назовем его, например, МакетСправки.
В коде макета мы можем использовать специальную разметку (теги или классы), чтобы разграничить доступ к контенту. Посмотрим на пример разметки макета справки справочника "Контрагенты":
<html>
<head><title>Справка: Контрагенты</title></head>
<body>
<h1>Работа со справочником "Контрагенты"</h1>
<p>Этот раздел справки предназначен для всех менеджеров по продажам.</p>
<div class="for-admins-only">
<h3>Техническая информация (Только для Администраторов)</h3>
<p>Внимание! Изменение счетов учета расчетов может нарушить проведение документов.</p>
</div>
</body>
</html>
При вызове справки на сервере мы считываем текст макета и проверяем роли текущего пользователя. Если у пользователя нет административных прав, мы программно вырезаем закрытые блоки из HTML-текста перед его показом на клиенте.
&НаСервере
Функция ПолучитьОтфильтрованныйТекстСправки()
// Получаем текст макета HTML напрямую из метаданных
МакетСправки = Справочники.Контрагенты.ПолучитьМакет("МакетСправки");
ИсходныйТекстHTML = МакетСправки.ПолучитьТекст();
// Проверяем права доступа текущего пользователя
Если РольДоступна("ПолныеПрава") Тогда
// Администратор видит весь текст справки полностью
Возврат ИсходныйТекстHTML;
Иначе
// Обычным пользователям вырезаем блок с классом "for-admins-only"
// Используем объект Регулярные Выражения для удаления закрытого тега
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Pattern = "<div class=""for-admins-only"">[\s\S]*?</div>";
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;
РезультатТекст = RegExp.Replace(ИсходныйТекстHTML, "");
Возврат РезультатТекст;
КонецЕсли;
EndFunction
Создаем общую форму ФормаСправки. Добавляем на нее реквизит с типом Строка (например, ТекстСправкиHTML) и связываем его на форме с элементом управления Поле HTML документа.
При открытии формы инициализируем поле подготовленным текстом справки:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Заполняем поле HTML-документа на клиенте
Элементы.ПолеСправки.УстановитьТекст(ПолучитьОтфильтрованныйТекстСправки());
КонецПроцедуры
Преимущества архитектурного обхода: Этот способ является максимально гибким. Он стабильно работает на любых типах клиентов (тонкий, веб, мобильный), позволяет легко форматировать текст, внедрять интерактивные JS-скрипты и надежно защищает скрытые данные, так как не прошедший проверку прав текст физически не передается на сторону клиента. Для быстрого внедрения пользовательской документации в типовые формы БСП можно использовать расширение для создания контекстной справки.