Стандартный функционал БСП при печати делает все гиперссылки неактивными, оставляя их оформление, а также теряет оформление страницы документа (фон и подложку). Данное расширение исправляет эти проблемы. Для чего это нужно, например для красивых прайсов, с последующим их преобразование в PDF и рассылки клиентам.
В расширении были модифицированы следующие общего модуля "УправлениеПечатьюСлужебный":
- ОбработатьРазделДокумента()
- РазбитьТекстШаблонаНаОбласти()
- СобратьФайлДокументаDOCX()
- ИнициализироватьСтруктуруПечатнойФормы()
Разберем доработки в порядке вызова их при печати.
При инициализации макета происходит вызов процедуры РазбитьТекстШаблонаНаОбласти() именно в ней теряется вся "магия" ссылок. Проблема в том, что БСП при разборе текста делит его на два типа "параграф" и все остальное. Научим ее понимать ссылки, комментариям с "{","}" обозначен доработанный код.
&Вместо("РазбитьТекстШаблонаНаОбласти")
Процедура Расш1_РазбитьТекстШаблонаНаОбласти(ЧтениеXML, СтруктураДокумента, ПараметрыАнализа)
УровеньТэгаБлок = -1;
УровеньТэгаОбласть = -1;
УровеньАбзаца = "0";
ТекущийУровень = 0;
ПропуститьТэг = Ложь;
ТекстРаздела = "";
//{
ЭтоСсылка = Ложь; // Флаг разбора ссылки
текБлокРазбора = ""; // возможные значения "Блок", "АбзацХ", где Х - порядковый номер
//}
СтруктураРазбораXML = ИнициализироватьРазборXML();
СброситьСтатусыТэгов1С(СтруктураРазбораXML);
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Заголовок", "");
Если ПараметрыАнализа.ТипАнализа <> 1 Тогда
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок", "");
УровеньТэгаБлок = 0;
КонецЕсли;
Пока ЧтениеXML.Прочитать() Цикл
...
Если ЧтениеНачалаРаздела(СтруктураРазбораXML, ЧтениеXML) Тогда
СтруктураРазбораXML.БлокирующийПоток = "Раздел";
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Раздел", "", Ложь);
ПеренестиОткрывающиеТэгиЗаписиВПоток(СтруктураРазбораXML, "Заголовок", "Раздел", "w:body");
КонецЕсли;
// начало разбора ссылки {
Если ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");
//ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
ОстановитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
ЭтоСсылка = Истина;
КонецЕсли;
// }
Если ЧтениеНачалаЛюбогоБлокаКромеПараграфа(СтруктураРазбораXML, ЧтениеXML) И ТекущийУровень = УровеньТэгаБлок Тогда
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок");
текБлокРазбора = "Блок"; // укажем текущий блок {}
КонецЕсли;
Если ЧтениеНачалаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
УровеньАбзаца = Формат(Число(УровеньАбзаца) + 1, "ЧН=0; ЧГ=0");
СтруктураРазбораXML.ТекущийУровеньАбзаца = УровеньАбзаца;
СброситьСтатусыТэгов1С(СтруктураРазбораXML, Истина);
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
текБлокРазбора = "Абзац" + УровеньАбзаца; // укажем текущий блок {}
КонецЕсли;
...
// учтем флаг разбора ссылки {
//Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
// }
ВозобновитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "СтрокаПарам" + УровеньАбзаца);
ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
СтруктураРазбораXML.ИмяПотокаФормата = "СтрокаПарам" + УровеньАбзаца;
КонецЕсли;
...
// учтем флаг разбора ссылки {
//Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
// }
Если СтруктураРазбораXML.СтатусТэга1С = 0 И СтруктураРазбораXML.РазобранныеСтроки.Количество() = 0 Тогда
ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца, "Абзац" + УровеньАбзаца);
ИначеЕсли СтруктураРазбораXML.РазобранныеСтроки.Количество() > 0 Тогда
...
КонецЕсли;
...
КонецЕсли;
Если ЧтениеКонцаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
...
КонецЕсли;
// завершение разбора ссылки {
Если ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда
Если текБлокРазбора = "" Тогда
текБлокРазбора = "Строки" + УровеньАбзаца;
КонецЕсли;
ВозобновитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
ЗавершитьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");
ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Ссылка", текБлокРазбора);
ЭтоСсылка = Ложь;
КонецЕсли;
// }
...
КонецПроцедуры
Функция ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
Возврат Ложь;
КонецЕсли;
Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "w:hyperlink";
КонецФункции
Функция ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
Возврат Ложь;
КонецЕсли;
Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И ЧтениеXML.Имя = "w:hyperlink";
КонецФункции
После инициализации макета, происходит инициализация печатной формы, в процессе которой данные макета копируются.
В процедуре ИнициализироватьСтруктуруПечатнойФормы() нужно закомментировать очистку текста колонтитулов получаемую из макета. Это нужно чтобы не потерять подложку страницы, т.к. она хранится в колонтитулах. БСП учитывает только те колонтитулы которые привязаны к разделам документа, а остальные безжалостно очищает.
&Вместо("ИнициализироватьСтруктуруПечатнойФормы")
Процедура Расш1_ИнициализироватьСтруктуруПечатнойФормы(ПечатнаяФорма, Макет)
ИмяКаталога = ПечатнаяФорма.ИмяКаталога;
СтруктураДокумента = ПечатнаяФорма.СтруктураДокумента;
...
Для Каждого Колонтитул Из Макет.СтруктураДокумента.Колонтитулы Цикл
ДобавитьВСтруктуруДокументаКолонтитул(СтруктураДокумента, Колонтитул.Значение);
СтруктураКолонтитула = СтруктураДокумента.Колонтитулы.Получить(Колонтитул.Ключ);
////Если СтруктураКолонтитула <> Неопределено Тогда
//// СтруктураКолонтитула.Текст = "";
////КонецЕсли;
КонецЦикла;
...
КонецПроцедуры
После того, как мы сформируем макет, и заполним его данными произойдет вызов функции СобратьФайлДокументаDOCX(). Внутри нее происходит формирование структуры документа. Здесь нужно заменить обработку колонтитулов из разделов документа на структуру. Так же здесь происходит вызов последней интересующей нас функции ОбработатьРазделДокумента()
&Вместо("СобратьФайлДокументаDOCX")
Функция Расш1_СобратьФайлДокументаDOCX(ПечатнаяФорма)
ИзменяемыеФайлы = Новый Соответствие;
ИзменяемыеФайлы.Вставить("СвязиКонтента", ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\_rels\document.xml.rels"));
ИзменяемыеФайлы.Вставить("ТипыКонтента", ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\[Content_Types].xml"));
ИзменяемыеФайлы.Вставить("Документ", ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\document.xml"));
// обработка колонтитулов {
КолонтитулВыведен = Новый Соответствие;
Для Каждого ЭлементКолонтитула Из ПечатнаяФорма.СтруктураДокумента.Колонтитулы Цикл
Колонтитул = ЭлементКолонтитула.Значение;
ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
Если ПустаяСтрока(Колонтитул.Текст) Тогда
Продолжить;
КонецЕсли;
ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
ЗаписьXML.Записать(Колонтитул.Текст);
ЗаписьXML.Закрыть();
КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
КонецЦикла;
////// Удаляем файлы пустых колонтитулов
////КолонтитулВыведен = Новый Соответствие;
////
////Для Каждого Раздел Из ПечатнаяФорма.СтруктураДокумента.Разделы Цикл
////
//// Для Каждого ЭлементКолонтитула Из Раздел.Значение.Колонтитулы Цикл
////
//// Колонтитул = ЭлементКолонтитула.Значение;
////
//// ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
//// Если ПустаяСтрока(Колонтитул.Текст) Тогда
//// Продолжить;
//// КонецЕсли;
////
//// ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
//// ЗаписьXML.Записать(Колонтитул.Текст);
//// ЗаписьXML.Закрыть();
////
//// КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
////
//// КонецЦикла;
////
////КонецЦикла;
// обработка колонтитулов }
...
ПечатнаяФорма.СтруктураДокумента.ТипыКонтента = ЗаписьXML.Закрыть();
// Формирование документа печатной формы
ПорядковыйНомер = 1;
ЗаписьXML = ИнициализироватьЗаписьXML("", ИзменяемыеФайлы.Получить("Документ"));
НомерРаздела = Неопределено;
КоличествоОбластей = ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти.Количество();
ИдентификаторДокумента = ПечатнаяФорма.СтруктураДокумента.ИдентификаторДокумента;
Для Каждого Область Из ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти Цикл
...
Если ВывестиПромежуточныйРаздел = Истина И ЭтоПоследняяОбласть = Ложь Тогда
РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(НомерРаздела);
Если РазделКВыводу <> Неопределено Тогда
ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
...
КонецЕсли;
КонецЕсли;
...
// Запись заключительного раздела
Если ЭтоПоследняяОбласть Тогда
РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(Область.НомерРаздела);
Если РазделКВыводу <> Неопределено Тогда
ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
ЗаписьXML.ЗаписатьБезОбработки(ТекстРаздела);
КонецЕсли;
КонецЕсли;
ПорядковыйНомер = ПорядковыйНомер + 1;
НомерРаздела = Область.НомерРаздела;
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:body>
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:document>
ЗаписьXML.Закрыть();
ПутьКДокументу = ПолучитьИмяВременногоФайла("DOCX");
СобратьКонтейнерДокументаDOCX(ПутьКДокументу, ПечатнаяФорма.ИмяКаталога);
Возврат ПутьКДокументу;
КонецФункции
В этой функции нужно добавить пропуск обработки тэгов background. Формирование итогового документа происходит из xml-блоков, количество которых равно количеству областей добавленных в макете при выводе. А каждый такой блок представляет собой полноценный xml-документ, xml-заголовок которого формируется путем копирования заголовка макета. Сам тег background отвечающий за фон страницы располагается до секции body, и если его не удалять, то нарушается xml-структура получаемого документа.
&Вместо("ОбработатьРазделДокумента")
Функция Расш1_ОбработатьРазделДокумента(СтруктураДокумента, Раздел)
ТипыКолонтитулов = ТипыКолонтитулов();
ЧтениеXML = ИнициализироватьЧтениеXML(Раздел.Текст);
ЗаписьXML = ИнициализироватьЗаписьXML("",,,Ложь);
ПропуститьТэг = Ложь;
Пока ЧтениеXML.Прочитать() Цикл
Если ПропуститьТэг = Истина Тогда
ПропуститьТэг = Ложь;
Продолжить;
КонецЕсли;
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
Продолжить;
КонецЕсли;
// обработка цвета фона {
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
Продолжить;
КонецЕсли;
// }
...
Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
Продолжить;
КонецЕсли;
// обработка цвета фона {
Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
Продолжить;
КонецЕсли;
// }
ЗаписатьЭлементXML(ЧтениеXML, ЗаписьXML);
КонецЦикла;
ТекстРаздела = ЗаписьXML.Закрыть();
Возврат ТекстРаздела;
КонецФункции
В результате на выходе мы можем получить документ с любым цветом фона и фоновым рисунком, а также активными ссылками, по которым можно перейти с помощью CTRL.
PS. Не проверял работоспособность при использовании колонтитулов в макете.
Проверено на БСП 3.1.5.306.