Вставка гиперссылки в форматированный документ

Да, форматированный документ это умеет и сам, но возможности можно расширить!

Поводом стала вот эта тема: //infostart.ru/public/74958/
Поскольку мне пришлось немного повозиться с форматированным документом в ходе текущих работ, накидал вариант решения проблемы.

Что позволяет сделать: позволяет превратить указанный (например, выделенный в форме) фрагмент форматированного документа в гиперссылку. При этом сохранив его форматирование. Сразу предупрежу: для случая параграфов и превращения картинок в гиперссылки это годится только как основа для дальнейшей доработки, а вот для форматированного текста это уже готовое решение. Если в обрабатываемом фрагменте уже есть ссылки, сносит их и ставит указанную.

Встроенный в платформу механизм даёт простенький диалог ввода ссылки, не имеет события его обработки/перехвата, и не имеет программного аналога. Значит, сделаем.

Вот полный текст механизма:

// вспомогательная к ВставитьСсылкуВВыделениеФорматированногоДокумента
&НаКлиентеНаСервереБезКонтекста
Процедура СоздатьЭлементПозиции(ФДокумент, рЗакладкаВставки, рДанныеЭлемента)
рЭлемент=ФДокумент.Вставить(рЗакладкаВставки,рДанныеЭлемента.Текст,рДанныеЭлемента.Элемент.ТипЭлемента);
ЗаполнитьЗначенияСвойств(рЭлемент,рДанныеЭлемента.Элемент);
рЭлемент.НавигационнаяСсылка=?(рДанныеЭлемента.Свойство("Ссылка"),рДанныеЭлемента.Ссылка,"");
рЭлемент.Текст=рДанныеЭлемента.Текст;
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Функция ВставитьСсылкуВВыделениеФорматированногоДокумента(ФДокумент, рВыделенныйТекст, рСсылка)
Попытка
рОбласть=ФДокумент.НайтиТекст(рВыделенныйТекст); // ищем везде
Если рОбласть=Неопределено Тогда
Возврат "Вставка ссылки невозможна, не определена область выделенного текста!";
КонецЕсли;
мЭлементов=ФДокумент.ПолучитьЭлементы(рОбласть.ЗакладкаНачала,рОбласть.ЗакладкаКонца);
Если мЭлементов.Количество()=0 Тогда
Возврат "Вставка ссылки невозможна, не определён выделенный текст!";
КонецЕсли;
//
// проверим, чтобы там уже не было ссылок
Для каждого рЭлемент Из мЭлементов Цикл
Если ТипЗнч(рЭлемент)<>Тип("ТекстФорматированногоДокумента") Тогда
Возврат "Выделенный фрагмент захватывает не только текстовые фрагменты, вставка ссылки невозможна!";
КонецЕсли;
Если Не ПустаяСтрока(рЭлемент.НавигационнаяСсылка) Тогда
Возврат "В выделенном фрагменте уже фигурирует ссылка, необходимо сначала её убрать!";
КонецЕсли;
КонецЦикла;

// конструируем последовательность новых элементов по их позициям согласно выделенной области
рВесьТекст=ФДокумент.ПолучитьТекст();
позиНачВыделения=СтрНайти(рВесьТекст,рВыделенныйТекст); // нумерация с 0!
позиКонВыделения=позиНачВыделения+СтрДлина(рВыделенныйТекст)-1;
//
мНовыхЭлементов=Новый Массив;
позиНачРаб=позиНачВыделения; // позиционирование элементов ФТ идёт встык, без +1
позиНачЧтен=позиНачВыделения;
рПозицияВставки=ФДокумент.ПолучитьПозициюПоЗакладке(мЭлементов[0].ЗакладкаНачала);
//
Для каждого рЭлемент Из мЭлементов Цикл
позиНачЭлемента=ФДокумент.ПолучитьПозициюПоЗакладке(рЭлемент.ЗакладкаНачала);
позиКонЭлемента=ФДокумент.ПолучитьПозициюПоЗакладке(рЭлемент.ЗакладкаКонца);
//
// на будущее, доработать, если кому понадобится, в т.ч. сопоставление ссылок картинкам
рТипЭлемента=ТипЗнч(рЭлемент);
//Если рТипЭлемента=Тип("ТекстФорматированногоДокумента") Тогда
рСвойстваЭлемента=Новый Структура("ЦветТекста,ЦветФона,Шрифт,Текст");
//ИначеЕсли рТипЭлемента=Тип("ПараграфФорматированногоДокумента") Тогда
// рСвойстваЭлемента=Новый Структура("ГоризонтальноеПоложение,МеждустрочныйИнтервал,Отступ,ТипПараграфа");
//ИначеЕсли рТипЭлемента=Тип("КартинкаФорматированногоДокумента") Тогда
// рСвойстваЭлемента=Новый Структура("Ширина,Высота,Картинка");
//КонецЕсли;
//
ЗаполнитьЗначенияСвойств(рСвойстваЭлемента,рЭлемент);
рСвойстваЭлемента.Вставить("ТипЭлемента",рТипЭлемента);
//
Если позиНачЭлемента<позиНачРаб Тогда
Если позиКонЭлемента>позиКонВыделения Тогда
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент",позиНачЭлемента,позиНачВыделения-1,рСвойстваЭлемента));
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент,Ссылка",позиНачВыделения,позиКонВыделения,рСвойстваЭлемента,рСсылка));
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент",позиКонВыделения,позиКонЭлемента,рСвойстваЭлемента));
Прервать; // вся выделенная область целиком поместилась в один элемент
Иначе
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент",позиНачЭлемента,позиНачЧтен-1,рСвойстваЭлемента));
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент,Ссылка",позиНачЧтен,позиКонЭлемента,рСвойстваЭлемента,рСсылка));
позиНачРаб=позиКонЭлемента; // именно так, без +1
позиНачЧтен=позиКонЭлемента+1;
КонецЕсли;
ИначеЕсли позиНачЭлемента=позиНачРаб Тогда
Если позиКонЭлемента>позиКонВыделения Тогда
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент,Ссылка",позиНачЧтен,позиКонВыделения,рСвойстваЭлемента,рСсылка));
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент",позиКонВыделения+1,позиКонЭлемента,рСвойстваЭлемента));
Прервать; // конечный хвостовой элемент, на котором закончилось выделение
Иначе
мНовыхЭлементов.Добавить(Новый Структура("Начало,Конец,Элемент,Ссылка",позиНачЧтен,позиКонЭлемента,рСвойстваЭлемента,рСсылка));
позиНачРаб=позиКонЭлемента; // именно так, без +1
позиНачЧтен=позиКонЭлемента+1;
КонецЕсли;
КонецЕсли;
//
КонецЦикла;

// получаем тексты "кусочками"
Для каждого знч Из мНовыхЭлементов Цикл
знч.Вставить("Текст",Сред(рВесьТекст,знч.Начало,знч.Конец-знч.Начало+1));
КонецЦикла;

// удаляем все попавшие под обработку старые элементы
Для й=-1*(мЭлементов.Количество()-1) По 0 Цикл
рЭлемент=мЭлементов.Получить(-й);
ФДокумент.Удалить(рЭлемент.ЗакладкаНачала,рЭлемент.ЗакладкаКонца);
КонецЦикла;

// создаём новые согласно указанным позициям и настройкам
рЗакладкаВставки=ФДокумент.ПолучитьЗакладкуПоПозиции(рПозицияВставки);
Для й=-1*(мНовыхЭлементов.Количество()-1) По 0 Цикл
СоздатьЭлементПозиции(ФДокумент, рЗакладкаВставки, мНовыхЭлементов.Получить(-й));
КонецЦикла;

Возврат "";
Исключение
Возврат "ВставитьСсылкуВВыделениеФорматированногоДокумента, общая ошибка: "+ОписаниеОшибки();
КонецПопытки;
КонецФункции

Вызывать это можно, например, так:

ВыдТекст=Элементы.ВашДокумент.ВыделенныйТекст;
ВашаСсылка="http://www.1c.ru";
Результат=ВставитьСсылкуВВыделениеФорматированногоДокумента(ВашДокумент,ВыдТекст,ВашаСсылка);
Если не ПустаяСтрока(Результат) Тогда
ПоказатьПредупреждение(,рРезультат);
КонецЕсли;

Напомню, чтобы ФД не приписывал спереди e1c:// и прочую ересь, указывайте протокол, например, "http://", причём, если вы хотите использовать ФД в своих целях, туда можно напихать свои адресообразные данные, например какие-нибудь гуиды, главное, чтобы протокол был. Ну и, конечно, ловить щелчок лучше не в поле ФД, а закинув содержимое ФД в html-поле, и уж там по Click’у смотреть href.

Кстати ещё на заметку: форматирование ФД не совсем wisiwig применительно к html-полю, т.е. иногда прямо разительно отличается вид. Но писать xslt-преобразование и пытаться понять, что он каким образом показывает — это уже удовольствие отдельное.

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *