Учим БСП печатать активные ссылки и подложку в документе 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 Конфигурации 1cv8 Абонемент ($m)

Расширения для внедрения консоли кода в обработку подсистемы БСП Групповое изменение реквизитов. Просто, чтобы было удобнее.

2 стартмани

вчера в 21:30    347    1    vandalsvq    1    

9

Настройка истории изменений. Подключение новых объектов (которых нет в списке) к системе версионирования (БСП) без изменения конфигурации

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

Много материалов и видео в сети о том, как подключить объект, которого нет в списке настроек, к системе версионирования БСП. Суть сводится к изменению определяемого типа, на который все завязано. Но это предполагает изменение конфигурации. Недавно встала задача подключить объект, которого нет в определяемом типе без снятия замков. Пришлось изучить вопрос глубже. Здесь пояснения и краткая инструкция с картинками. Как подключиться, используя только расширение.

20.11.2023    679    user1374747    0    

22

Как включить привилегированный режим для дополнительных отчетов и обработок

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

Как отключить безопасный режим для дополнительных отчетов и обработок РазрешениеНаИспользованиеПривилегированногоРежима

14.10.2023    2161    SpecRam    15    

31

Справочник по методам БСП

Инструментарий разработчика БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Абонемент ($m)

Данная конфигурация представляет собой инструмент для изучения документации и набора методов для стандартных подсистем БСП (Библиотека стандартных подсистем) в среде 1С:Предприятие. Может помочь разработчикам для быстрого поиска кода и переноса его в другие конфигурации, а также изучения БСП. Это конфигурация не в является заменой сервиса ИТС , а только помогает разработчикам в изучении БСП.

2 стартмани

11.10.2023    4725    105    plm    13    

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