Учим БСП печатать активные ссылки и подложку в документе WORD

13.03.23

Разработка - БСП (Библиотека стандартных подсистем)

Небольшое расширение БСП для печати в WORD. Добавлена печать активных ссылок, подложки документа, и фона страницы.

Скачать файлы

Наименование Файл Версия Размер
Учим БСП печатать активные ссылки и подложку в документе WORD:
.cfe 10,05Kb
4
.cfe 1.0.1 10,05Kb 4 Скачать

Стандартный функционал БСП при печати делает все гиперссылки неактивными, оставляя их оформление, а также теряет оформление страницы документа (фон и подложку). Данное расширение исправляет эти проблемы. Для чего это нужно, например для красивых прайсов, с последующим их преобразование в 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.

См. также

Создать на основании - своя кнопка (БСП). Проблема двух подменю Создать на основании

БСП (Библиотека стандартных подсистем) Адаптация типовых решений Платформа 1С v8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

Понадобилось в подменю "Создать на основании" добавить свою команду, которая открывает обработку. В процессе доработок появилась проблема двух подменю "Создать на основании". В статье о том, как решились проблемы.

01.03.2024    1282    dimanich70    6    

13

Заполнение поля адреса в своей обработке [БСП]

Механизмы платформы 1С БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Небольшая шпаргалка по функциям БСП касательно адреса. Так скажем, еще один способ помимо https://infostart.ru/1c/articles/1060970/

12.02.2024    687    FilippovRI    0    

15

Расширяем возможности дополнительных обработок и настраиваем их отладку

БСП (Библиотека стандартных подсистем) Механизмы типовых конфигураций Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Уже не одна веб-страница исписана знаниями о дополнительных обработках, как создать, как подключить. Есть масса вариантов, как их можно отладить. Я разобрался в кишках работы библиотеки и покажу, как можно расширить возможности дополнительных отчетов, а также покажу удобный способ отладки.

07.02.2024    2351    YA_418728146    11    

40

1С:БСП Дополнительные реквизиты и сведения

БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Бесплатно (free)

В этой статье расскажем об архитектуре, использовании и особенностях реализации подсистемы «Свойства» из инструментария разработчика «1С:Библиотека стандартных подсистем» (1С: БСП).

19.01.2024    5161    PROSTO-1C    5    

45

Бесплатный митап 9 февраля «Библиотеки и фреймворки на 1С и всё, что с этим связано»

БСП (Библиотека стандартных подсистем) Мероприятия Бесплатно (free)

Митап посвящен вопросам создания, использования и поддержке переиспользуемого кода при разработке решений на платформе 1С:Предприятие 8.

15.01.2024    3798    0    Infostart    0    

20

Шаблоны новых объектов 1С для 1С:Бухгалтерии предприятия

Инструментарий разработчика БСП (Библиотека стандартных подсистем) Механизмы типовых конфигураций Платформа 1С v8.3 1С:Бухгалтерия 3.0 Бесплатно (free)

Используются для создания новых объектов в конфигурации, чтобы не забыть, что нужно сделать. Сделано на примере 1С:Бухгалтерия предприятия, в других конфигурациях могут быть другие, а могут быть и похожие объекты.

28.12.2023    4831    mrXoxot    11    

99
Оставьте свое сообщение