//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирКлиент Экспорт;

#Если Клиент Тогда

Перем мРедакторHTML; // Кэш
Перем НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка; // Временные переменные для всех методов
Перем мПлатформа; 
Перем мСлужебнаяФорма;
Перем мСтарыйСыройТекстТела;

// Получает интерфейс редактора MonacoBSL
Функция РедакторHTML() Экспорт
	Если Истина
		И мРедакторHTML = Неопределено 
		И ЛиПолеHTMLДокумента()
	Тогда
		мРедакторHTML = ЭлементФормы.Документ.defaultView; // COMОбъект
		Попытка
			Если Не ЗначениеЗаполнено(мРедакторHTML.version1C) Тогда 
				мРедакторHTML = Неопределено;
			КонецЕсли; 
		Исключение
			мРедакторHTML = Неопределено;
		КонецПопытки;
	КонецЕсли;
	Возврат мРедакторHTML;
КонецФункции

Функция ЛиПолеHTMLДокумента()
	
	Результат = Ложь
		Или ТипЗнч(ЭлементФормы) = Тип("ПолеHTMLДокумента")
		Или (Истина
			И ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			И (Ложь
				Или ЭлементФормы.Вид = ВидПоляФормы.ПолеHTMLДокумента));
	Возврат Результат;

КонецФункции

// Процедура - Установить границы выделения
// Параметры:
//   НачальнаяСтрокаИлиПозиция -  - 
//   НачальнаяКолонкаИлиКонечнаяПозиция -  - 
//   КонечнаяСтрока -  - 
//   КонечнаяКолонка -  - 
//   Активировать -  - 
//   ЭтаФорма - Форма - нужно передавать для формы и поля и исправления ошибки платформы 8.3.22 с прокруткой
//   ОшибкаПриВыходеЗаКонец -  - 
//   ПоказатьНачальнуюГраницу - Булево - если Истина, то показать начальную границу, иначе - конечную; только для HTML
Процедура УстановитьГраницыВыделения(Знач НачальнаяСтрокаИлиПозиция, Знач НачальнаяКолонкаИлиКонечнаяПозиция, Знач КонечнаяСтрока = Неопределено, Знач КонечнаяКолонка = Неопределено,
	Знач Активировать = Ложь, Знач ЭтаФорма = Неопределено, Знач ОшибкаПриВыходеЗаКонец = Истина, Знач ПоказатьНачальнуюГраницу = Ложь) Экспорт 

	Если Не ОшибкаПриВыходеЗаКонец Тогда
		Если КонечнаяСтрока = Неопределено Тогда
			ДлинаТекста = Макс(1, СтрДлина(ПолучитьТекст()) + 1);
			НачальнаяСтрокаИлиПозиция = Мин(ДлинаТекста, НачальнаяСтрокаИлиПозиция);
			НачальнаяКолонкаИлиКонечнаяПозиция = Мин(ДлинаТекста, НачальнаяКолонкаИлиКонечнаяПозиция);
		КонецЕсли;
	КонецЕсли;
	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Выделение = Новый Структура; 
			Если КонечнаяСтрока = Неопределено Тогда
				Выделение.Вставить("Начало", НачальнаяСтрокаИлиПозиция);
				Выделение.Вставить("Конец", НачальнаяКолонкаИлиКонечнаяПозиция);
			Иначе                                                               
				Выделение.Вставить("Начало", ПозицияВПолеТекстаПоНомеруСтрокиИКолонки(НачальнаяСтрокаИлиПозиция, НачальнаяКолонкаИлиКонечнаяПозиция));
				Выделение.Вставить("Конец", ПозицияВПолеТекстаПоНомеруСтрокиИКолонки(КонечнаяСтрока, КонечнаяКолонка));
			КонецЕсли;
			
			// Для 8.3.13-
			Выделение.Вставить("НачалоБезПереносов", Выделение.Начало);
			Выделение.Вставить("КонецБезПереносов", Выделение.Конец);
			
			УстановитьВыделениеВДокументеHTML(Выделение);
		Иначе
			Если КонечнаяСтрока = Неопределено Тогда
				РедакторHTML.setSelectionByLength(НачальнаяСтрокаИлиПозиция, НачальнаяКолонкаИлиКонечнаяПозиция, ПоказатьНачальнуюГраницу);
			Иначе
				РедакторHTML.setSelection(НачальнаяСтрокаИлиПозиция, НачальнаяКолонкаИлиКонечнаяПозиция, КонечнаяСтрока, КонечнаяКолонка, ПоказатьНачальнуюГраницу);
			КонецЕсли; 
			Если Активировать Тогда
				РедакторHTML.editor.focus();
			КонецЕсли;
		КонецЕсли; 
	Иначе
		Если КонечнаяСтрока = Неопределено Тогда
			ЭлементФормы.УстановитьГраницыВыделения(НачальнаяСтрокаИлиПозиция, НачальнаяКолонкаИлиКонечнаяПозиция);
		Иначе
			ЭлементФормы.УстановитьГраницыВыделения(НачальнаяСтрокаИлиПозиция, НачальнаяКолонкаИлиКонечнаяПозиция, КонечнаяСтрока, КонечнаяКолонка);
		КонецЕсли; 
		Если Истина
			// Похоже эта проверка не улучшает логику работы, а только лишь немного ускоряет
			И ЭтаФорма <> Неопределено
			И ЭтаФорма.ТекущийЭлемент = ЭлементФормы
			И ирКэш.НомерИзданияПлатформыЛкс() > "82" 
		Тогда 
			// https://www.hostedredmine.com/issues/934802 исправлено в 8.3
			// https://www.hostedredmine.com/issues/929519 исправлено в 8.3.19
			Если ирКэш.НомерВерсииПлатформыЛкс() < 803023 Тогда // Проблема актуальна и для 8.3.24?
				ирКлиент.УстановитьФокусВводаФормеЛкс();
			КонецЕсли;
			#Если Сервер И Не Сервер Тогда
				мПлатформа = Обработки.ирПлатформа.Создать()
			#КонецЕсли
			Если Истина
				И мПлатформа.ИспользоватьЭмуляциюНажатияКлавиш 
				И ирКэш.НомерВерсииПлатформыЛкс() = 803022 
			Тогда
				// Антибаг платформы 8.3.22 https://www.hostedredmine.com/issues/958530
				ирКлиент.ОтправитьНажатияКлавишЛкс("+{right}");
				ирКлиент.ОтправитьНажатияКлавишЛкс("+{left}");
			КонецЕсли;
		КонецЕсли; 
	КонецЕсли; 

КонецПроцедуры

Функция ДвухмернаяПозицияИзОдномерной(Позиция)
	
	Результат = Новый Структура("НомерСтроки, НомерКолонки");
	// TODO
	//УстановитьГраницыВыделения(1, Позиция);
	//Текст = ВыделенныйТекст();
	//Результат.НомерСтроки = СтрЧислоВхождений(Текст, Символы.ПС);
	//Результат.НомерКолонки = СтрДлина(СтрПолучитьСтроку(Текст, Результат.НомерСтроки));
	Возврат Результат;
	
КонецФункции

Процедура ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка, Знач ДляИсходногоТекстаСравнения = Ложь) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			// TODO отличить монако и обычный редакторы
			//ВыделениеТекста = ПолучитьВыделениеВДокументеHTML();
			//КоординатыПозиции = ДвухмернаяПозицияИзОдномерной(ВыделениеТекста.Начало);
			//НачальнаяСтрока = КоординатыПозиции.НомерСтроки;
			//НачальнаяКолонка = КоординатыПозиции.НомерКолонки;
			//КоординатыПозиции = ДвухмернаяПозицияИзОдномерной(ВыделениеТекста.Начало);
			//КонечнаяСтрока = КоординатыПозиции.НомерСтроки;
			//КонечнаяКолонка = КоординатыПозиции.НомерКолонки;
		Иначе
			Если ДляИсходногоТекстаСравнения Тогда
				ВыделениеТекста = РедакторHTML.getActiveEditor().getSelection();
			Иначе
				ВыделениеТекста = РедакторHTML.getSelection();
			КонецЕсли;
			НачальнаяСтрока = ВыделениеТекста.startLineNumber;
			НачальнаяКолонка = ВыделениеТекста.startColumn;
			КонечнаяСтрока = ВыделениеТекста.endLineNumber;
			КонечнаяКолонка = ВыделениеТекста.endColumn;
		КонецЕсли; 
	Иначе
		ЭлементФормы.ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
	КонецЕсли; 

КонецПроцедуры

Функция ПолучитьТекст(Знач ЛиСырой = Ложь, Знач ДляПоиска = Ложь) Экспорт

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если Истина
			И РедакторHTML = Неопределено 
			И ирКэш.ДоступноБраузерWebKitЛкс()
			И ЭлементФормы.Документ.ЭтоРедактор = Истина 
		Тогда
			Возврат "";
		ИначеЕсли РедакторHTML = Неопределено Тогда
			Если ирКэш.ДоступноБраузерWebKitЛкс() Тогда
				ДокументHtml = ЭлементФормы.Документ;
				//Текст = ДокументHtml.body.textContent;
			Иначе
				Текст = ЭлементФормы.ПолучитьТекст();
				ДокументHtml = ирОбщий.ПолучитьHtmlFileИзТекстаHtmlЛкс(Текст); // Тут переносы строк другое количество символов дают. Скорее всего из-за Символы.ВК
			КонецЕсли;
			Если Истина
				И ЛиСырой 
				И (Ложь
					Или ирКэш.ДоступноБраузерWebKitЛкс()
					Или ЭлементФормы.Документ.ЭтоРедактор <> Истина)
			Тогда
				Если ТипЗнч(ЭлементФормы) = Тип("ПолеHTMLДокумента") Тогда
					//Если ТолькоПросмотр() Тогда
					//	Текст = ДокументHtml.documentElement.innerText; /// Криво
					//Иначе
					//	Текст = ЭлементФормы.ПолучитьТекст();
					//КонецЕсли;
					Если ДляПоиска Тогда
						Если ЗначениеЗаполнено(мСтарыйСыройТекстТела) Тогда
							Текст = мСтарыйСыройТекстТела;
						Иначе
							Текст = ДокументHtml.documentElement.lastChild.innerHTML;
						КонецЕсли;
					Иначе
						Текст = ЭлементФормы.ПолучитьТекст();
					КонецЕсли;
				Иначе
					Текст = ирОбщий.ДанныеЭлементаФормыЛкс(ЭлементФормы);
				КонецЕсли;
			Иначе
				Текст = ДокументHtml.documentElement.innerText;
			КонецЕсли;
		Иначе
			Текст = РедакторHTML.getText();
		КонецЕсли; 
	ИначеЕсли ТипЗнч(ЭлементФормы) = Тип("ПолеВвода") Тогда
		Текст = ЭлементФормы.Значение;
	ИначеЕсли ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") Тогда
		Текст = ирОбщий.ДанныеЭлементаФормыЛкс(ЭлементФормы);
	Иначе
		Текст = ЭлементФормы.ПолучитьТекст();
	КонецЕсли; 
	Возврат Текст;

КонецФункции

// Для не редактора устанавливает всегда сырой текст
//
// Параметры:
//  Текст						 - 	 -  
//  Активировать				 - 	 - 
//  ИсходныйТекст	 - 	 - для отображения изменений
//  СохранитьГраницыВыделения	 - 	 - 
// 
// Возвращаемое значение:
//   - 
//
Функция УстановитьТекст(Знач Текст, Активировать = Ложь, ИсходныйТекст = Неопределено, СохранитьГраницыВыделения = Ложь) Экспорт 

	Если СохранитьГраницыВыделения Тогда
		СтруктураВыделения = ВыделениеДвумерное();
	КонецЕсли; 
	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если Истина
			И РедакторHTML = Неопределено 
			И ирКэш.ДоступноБраузерWebKitЛкс()
			И ЭлементФормы.Документ.ЭтоРедактор = Истина 
		Тогда
			Возврат Ложь;
		ИначеЕсли РедакторHTML = Неопределено Тогда
			ЭлементФормы.УстановитьТекст(Текст);
			//УстановитьТелоHTML(ирОбщий.КодироватьТекстВXMLЛкс(Текст));
		Иначе
			Если СтрЧислоСтрок(Текст) <> СтрЧислоСтрок(ПолучитьТекст()) Тогда
				РедакторHTML.removeAllBookmarks();
			КонецЕсли; 
			Если Активировать Тогда
				РедакторHTML.editor.focus();
			КонецЕсли;
			// https://github.com/salexdv/bsl_console/issues/141#issuecomment-852355305
			РедакторHTML.updateText(Текст);
			//РедакторHTML.editor.setValue(Текст); // Так история редактирования сбрасывается и устанавливается модифицированность
			Если ИсходныйТекст <> Неопределено Тогда
				РедакторHTML.setOriginalText(ИсходныйТекст);
			КонецЕсли;
			УстановитьДекорации();
		КонецЕсли; 
	ИначеЕсли ТипЗнч(ЭлементФормы) = Тип("ПолеВвода") Тогда
		ЭлементФормы.Значение = Текст;
	ИначеЕсли ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") Тогда
		ЭтаФорма = Неопределено;
		ПутьКДанным = "";
		ирОбщий.ДанныеЭлементаФормыЛкс(ЭлементФормы, ПутьКДанным, ЭтаФорма);
		Если ЗначениеЗаполнено(ПутьКДанным) Тогда
			Выполнить("ЭтаФорма." + ПутьКДанным + " = Текст");
		КонецЕсли; 
	Иначе
		ЭлементФормы.УстановитьТекст(Текст);
	КонецЕсли; 
	Если СохранитьГраницыВыделения Тогда
		УстановитьВыделениеДвумерное(СтруктураВыделения);
	КонецЕсли;
	мСтарыйСыройТекстТела = "";
	Возврат Истина;

КонецФункции

Процедура УстановитьДекорации(Знач МассивСтрок = Неопределено) Экспорт 
	
	Если МассивСтрок = Неопределено Тогда
		МассивСтрок = Новый Массив;
	КонецЕсли;
	РедакторHTML = РедакторHTML();
	РедакторHTML.setLineNumbersDecorations(ирОбщий.ОбъектВТекстЖСОНЛкс(МассивСтрок));

КонецПроцедуры

Функция ПолучитьСтроку(Знач НомерСтроки) Экспорт 

	Если ТипЗнч(ЭлементФормы) = Тип("ПолеВвода") Тогда
		ТекстовыйДокумент =  Новый ТекстовыйДокумент;
		ТекстовыйДокумент.УстановитьТекст(ЭлементФормы.Значение);
		Текст = ТекстовыйДокумент.ПолучитьСтроку(НомерСтроки);
	ИначеЕсли ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли; 
		Текст = РедакторHTML.getLineContent(НомерСтроки);
	Иначе
		Текст = ЭлементФормы.ПолучитьСтроку(НомерСтроки);
	КонецЕсли; 
	Возврат Текст;

КонецФункции

Функция КоличествоСтрок() Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли; 
		Текст = РедакторHTML.getLineCount();
	Иначе
		Текст = ЭлементФормы.КоличествоСтрок();
	КонецЕсли; 
	Возврат Текст;

КонецФункции

Функция ВыделенныйТекст(НовыйТекст = Неопределено) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли; 
		Если НовыйТекст = Неопределено Тогда
			Результат = РедакторHTML.selectedText();
		Иначе
			РедакторHTML.selectedText(НовыйТекст);
			//// https://github.com/salexdv/bsl_console/issues/64#issue-873784658
			//ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
			//УстановитьГраницыВыделения(КонечнаяСтрока, КонечнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
		КонецЕсли;
	Иначе
		Если НовыйТекст = Неопределено Тогда
			Результат = ЭлементФормы.ВыделенныйТекст;
		Иначе
			ЭлементФормы.ВыделенныйТекст = НовыйТекст;
		КонецЕсли; 
	КонецЕсли; 
	Возврат Результат;

КонецФункции

Функция ТолькоПросмотр(НовыйРежим = Неопределено) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат Истина;
		КонецЕсли; 
		Если НовыйРежим = Неопределено Тогда
			Результат = РедакторHTML.getReadOnly();
		Иначе
			РедакторHTML.setReadOnly(НовыйРежим);
		КонецЕсли;
	Иначе
		Если НовыйРежим = Неопределено Тогда
			Результат = ЭлементФормы.ТолькоПросмотр;
		Иначе
			ЭлементФормы.ТолькоПросмотр = НовыйРежим;
		КонецЕсли; 
	КонецЕсли; 
	Возврат Результат;

КонецФункции

Процедура ЗаменитьСтроку(НомерСтроки, Текст) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		РедакторHTML.setLineContent(НомерСтроки, Текст);  // https://github.com/salexdv/bsl_console/issues/90
		//УстановитьГраницыВыделения(НомерСтроки, 1 , НомерСтроки, СтрДлина(ПолучитьСтроку(НомерСтроки)) + 1);
		//ВыделенныйТекст(Текст);
	Иначе
		ЭлементФормы.ЗаменитьСтроку(НомерСтроки, Текст); // Баг платформы. Вызывает выделение всего предшествующего текста на 8.3.18
	КонецЕсли; 

КонецПроцедуры

Процедура ВставитьСтроку(НомерСтроки, Текст) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		РедакторHTML.insertLine(НомерСтроки, Текст);
	Иначе
		ЭлементФормы.ВставитьСтроку(НомерСтроки, Текст);
	КонецЕсли; 

КонецПроцедуры

Процедура ДобавитьСтроку(Текст) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		//ДлинаТекста = СтрДлина(ПолучитьТекст());
		//РедакторHTML.setText(Символы.ПС + Текст, ДлинаТекста);
		РедакторHTML.AddLine(Текст);
	Иначе
		ЭлементФормы.ДобавитьСтроку(Текст);
	КонецЕсли; 

КонецПроцедуры

Процедура УдалитьСтроку(НомерСтроки) Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		РедакторHTML.deleteLine(НомерСтроки);
	Иначе
		ЭлементФормы.УдалитьСтроку(НомерСтроки);
	КонецЕсли; 

КонецПроцедуры

// Заменяет выделенный текст новым
Процедура ВставитьТекст(Знач НовыйТекст, Знач ДобавитьНовуюСтрокуПосле = Истина) Экспорт 
	
	ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
	ВыделенныйТекст(НовыйТекст);
	Если ДобавитьНовуюСтрокуПосле Тогда
		// Антибаг 8.3.12 https://partners.v8.1c.ru/forum/t/1719342/m/1719342, http://www.hostedredmine.com/issues/882423
		ВыделенныйТекст(Символы.ПС);
	КонецЕсли;
	УстановитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, НачальнаяСтрока, НачальнаяКолонка); // Антибаг платформы https://www.hostedredmine.com/issues/1007564
	УстановитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);

КонецПроцедуры

Процедура Очистить() Экспорт 

	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		РедакторHTML.eraseText();
	Иначе
		ЭлементФормы.Очистить();
	КонецЕсли; 

КонецПроцедуры

Процедура ПоказатьОшибку(НомерСтроки, НомерКолонки = 1, ЭтаФорма = Неопределено) Экспорт 
	Если ЛиПолеHTMLДокумента() Тогда
		РедакторHTML = РедакторHTML();
		Если РедакторHTML = Неопределено Тогда
			Возврат;
		КонецЕсли; 
		УстановитьГраницыВыделения(НомерСтроки, 1, НомерСтроки, 1,, ЭтаФорма);
		РедакторHTML.markError(НомерСтроки, НомерКолонки);
	Иначе
		УстановитьГраницыВыделения(НомерСтроки, 1, НомерСтроки, 150,, ЭтаФорма);
	КонецЕсли; 
КонецПроцедуры

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

		// Стало необходимо в 8.3.19, иначе фокус не переходил в это поле сразу и координаты каретки получались пустые
		//Форма.Обновить(); 
		Форма.Открыть(); 
		
		ВКОбщая.ПолучитьПозициюКаретки(Координаты.left + СмещениеГориз, Координаты.top + 8 + СмещениеВерт);
		Форма.ТекущийЭлемент = ЭлементФормы;
		Форма.ЭлементыФормы.Удалить(ВременноеПолеВвода);
	Иначе 
		Если Форма <> Неопределено Тогда
			Форма.Активизировать();
		КонецЕсли;
		//ЧерезUIAutomation = ирКэш.НомерИзданияПлатформыЛкс() = "85"; // Для 8.5 требуется
		ЧерезUIAutomation = Истина;
		ВКОбщая.ПолучитьПозициюКаретки(СмещениеГориз, СмещениеВерт, ЧерезUIAutomation);
	КонецЕсли; 
	
КонецПроцедуры

Функция КоординатыКурсора() Экспорт 
	ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
	Результат = Новый Структура("НомерСтроки, НомерКолонки", КонечнаяСтрока, КонечнаяКолонка);
	Возврат Результат;
КонецФункции

// Для HTML
Процедура Инициировать(ФормаВладелец) Экспорт 
	// Настройки шрифта и окна автодополнения тут
	#Если Сервер И Не Сервер Тогда
		Обработки.ирПлатформа.Создать().БазовыйФайлРедактораКода();
	#КонецЕсли
	
	мРедакторHTML = ЭлементФормы.Документ.defaultView;
	ЭлементСтиля = мРедакторHTML.document.createElement("style");
	ЭлементСтиля.setAttribute("type", "text/css");
	ЭлементСтиля.innerHTML = "
	// Убираем полосы прокрутки 1С. Комментарий нельзя вставлять в стиль!
	|body {
	|	overflow: hidden; 
	|}
	// Цвета статусной строки
	|.statusbar-widget {
	|	background: #c2dfef;
	|	color: #000;
	|}
	// Окно подсказки по вызову метода
	|.editor-widget.parameter-hints-widget .code {
	|	font-size: 13px !important;
	|	line-height: 15px;
	|}
	|.editor-widget.parameter-hints-widget .docs {
	|	font-size: 13px !important;
	|	line-height: 15px;
	|}
	|.editor-widget.parameter-hints-widget.visible {
	|  max-width: 600px;
	|}
	|.monaco-editor .parameter-hints-widget > .wrapper {
	|  max-width: 600px;
	|}
	|.monaco-editor-hover .monaco-editor-hover-content {
	|	max-width: 600px;
	|}
	// Подсказка удержания
	|.monaco-editor-hover .hover-row {
	|	font-size: 13px !important;
	|	line-height: 15px;
	|}
	// Подсказка автодополнения
	|.monaco-editor .suggest-widget {
	|	width: 500px;
	|}
	// Подсказка автодополнения вместе с окном детальной инфы
	|.monaco-editor .suggest-widget.docs-side {
	|	width: 1000px;
	|}
	|.monaco-editor .suggest-widget.docs-side > .details {
	|	width: 60%;
	|	max-height: 800px !important;
	|}
	|.monaco-editor .suggest-widget.docs-side > .tree {
	|	width: 40%;
	|	float: left;
	|}
	// Уменьшаем насыщенность цвета фона изменных строк. Не работает.
	|.monaco-diff-editor .insert .view-line {
	|	filter: saturate(0.9);
	|}
	|";
	мРедакторHTML.document.head.appendChild(ЭлементСтиля);
	мРедакторHTML.showStatusBar(Ложь); // параметр Ложь - отображаем снизу справа
	мРедакторHTML.renderWhitespace(Истина);
	мРедакторHTML.setFontSize(13);
	мРедакторHTML.setLineHeight(15);
	мРедакторHTML.disableContextMenu();
	мРедакторHTML.setOption("autoResizeEditorLayout", Истина); // https://github.com/salexdv/bsl_console/issues/185
	//мРедакторHTML.setOption("lineHeight", 15);  // Высота строки редактора https://github.com/salexdv/bsl_console/issues/195
	//мРедакторHTML.setOption("suggestFontSize", 13); // шрифт окна автодополнения https://github.com/salexdv/bsl_console/issues/194
	//мРедакторHTML.setOption("suggestLineHeight", 15); // шрифт окна автодополнения https://github.com/salexdv/bsl_console/issues/194
	//ИмяШрифта = ирКэш.ИмяШрифтаРедактораМодуляКонфигуратораЛкс();
	//Если ЗначениеЗаполнено(ИмяШрифта) Тогда
	//	мРедакторHTML.setFontFamily(ИмяШрифта);
	//Иначе
		мРедакторHTML.setFontFamily("Lucida Console");
	//КонецЕсли; 
	Если ирКэш.НомерВерсииПлатформыЛкс() >= 803025 Тогда
		// Антибаг Аварийное завершение https://www.hostedredmine.com/issues/984781 
	Иначе
		ИмяОбработчика = ЭлементФормы.ПолучитьДействие("onclick");
		Если Истина
			И ИмяОбработчика <> Неопределено 
			И ирОбщий.МетодРеализованЛкс(ФормаВладелец, ИмяОбработчика)
		Тогда
			ИмяОбработчика = "" + ИмяОбработчика + "Динамический";
			ЭлементФормы.УстановитьДействие("onclick", Неопределено);
			// Обходим неоправданное обновление формы https://www.hostedredmine.com/issues/984784
			Выполнить("ДобавитьОбработчик мРедакторHTML.onclick, ФормаВладелец." + ИмяОбработчика); 
		КонецЕсли;
	КонецЕсли;
КонецПроцедуры

Процедура ИнициироватьПоле(Знач НовыйЭлементФормы) Экспорт 
	Если НовыйЭлементФормы = Неопределено Тогда
		мСлужебнаяФорма = мПлатформа.ПолучитьФорму("Служебная");
		НовыйЭлементФормы = мПлатформа.НовоеСлужебноеПолеТекста(мСлужебнаяФорма);
	КонецЕсли;
	ЭтотОбъект.ЭлементФормы = НовыйЭлементФормы;
КонецПроцедуры

Процедура Перерисовать() Экспорт 
	РедакторHTML = РедакторHTML();
	РедакторHTML.editor.layout();
КонецПроцедуры

Процедура ЗагрузитьСостояниеИзПоляТекстаЛкс(Знач ПолеИсточник, Знач ИсходныйТекст) Экспорт 
	#Если Сервер И Не Сервер Тогда
		ПолеИсточник = ЭтотОбъект;
	#КонецЕсли
	ПолеИсточник.ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
	УстановитьТекст(ПолеИсточник.ПолучитьТекст(), Истина, ИсходныйТекст);
	УстановитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка);
	ТолькоПросмотр(ПолеИсточник.ТолькоПросмотр());
КонецПроцедуры

Функция СостояниеИсторииИзменения() Экспорт 
	РедакторHTML = РедакторHTML();
	Результат = РедакторHTML.editor.saveViewState();
	Возврат Результат;
КонецФункции

Процедура ВосстановитьСостояниеИсторииИзменения(Состояние) Экспорт 
	РедакторHTML = РедакторHTML();
	РедакторHTML.editor.restoreViewState(Состояние);
КонецПроцедуры

// Процедура - Показать последнюю строку
//
// Параметры:
//  ЭтаФорма	- Форма - нужно передавать для активации поля и для исправления ошибки платформы 8.3.22 с прокруткой
//
Процедура ПоказатьПоследнююСтроку(ЭтаФорма = Неопределено) Экспорт 
	НомерСтроки = Макс(1, КоличествоСтрок()); // https://www.hostedredmine.com/issues/891268
	Если НомерСтроки > 1 Тогда
		УстановитьГраницыВыделения(НомерСтроки, 1, НомерСтроки, 1,, ЭтаФорма);
	КонецЕсли; 
КонецПроцедуры

Функция ОбработатьКликНаГиперссылке(Событие) Экспорт 
	СобытиеОбработано = Ложь;
	ЗаголовокГиперссылки = Событие.params.label;
	ЗначениеГиперссылки = Событие.params.href;
	Если Ложь
		Или ЗаголовокГиперссылки = "перейти по ссылке" 
		Или ирОбщий.СтрНачинаетсяСЛкс(ЗначениеГиперссылки, "http")
	Тогда
		ЗапуститьПриложение(ЗначениеГиперссылки);
		СобытиеОбработано = Истина;
	КонецЕсли;
	Возврат СобытиеОбработано;
КонецФункции

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

Функция ВыделениеДвумерное(Знач ДляИсходногоТекстаСравнения = Ложь) Экспорт
	
	Структура = НоваяСтруктураДвумерногоВыделения();
	ПолучитьГраницыВыделения(Структура.НачальнаяСтрока, Структура.НачальнаяКолонка, Структура.КонечнаяСтрока, Структура.КонечнаяКолонка, ДляИсходногоТекстаСравнения);
	Возврат Структура;
	
КонецФункции

Функция УстановитьВыделениеДвумерное(Знач Структура, знач ПоказатьНачальнуюГраницу = Ложь) Экспорт
	Если Структура.НачальнаяКолонка <= 0 Тогда
		Структура.НачальнаяКолонка = 1;
	КонецЕсли; 
	Если Структура.НачальнаяСтрока <= 0 Тогда
		Структура.НачальнаяСтрока = 1;
	КонецЕсли; 
	Если Структура.КонечнаяСтрока <= 0 Тогда
		Структура.КонечнаяСтрока = 1;
	КонецЕсли; 
	УстановитьГраницыВыделения(Структура.НачальнаяСтрока, Структура.НачальнаяКолонка, Структура.КонечнаяСтрока, Структура.КонечнаяКолонка,,,, ПоказатьНачальнуюГраницу);
	Возврат Неопределено;
КонецФункции

// Функция - Позиция в поле текста по номеру строки и колонки. Портит текущее незаконченное выделение мышкой!
//
// Параметры:
//  КонечнаяСтрока	 - 	 - 
//  КонечнаяКолонка	 - 	 - 
// 
// Возвращаемое значение:
//  - Число - начиная с 1
//
Функция ПозицияВПолеТекстаПоНомеруСтрокиИКолонки(Знач КонечнаяСтрока, Знач КонечнаяКолонка, Знач СлужебноеПолеТекста = Неопределено) Экспорт 
	
	Если СлужебноеПолеТекста = Неопределено Тогда
		СлужебноеПолеТекста = СлужебноеПолеТекста();
	КонецЕсли;
	СлужебноеПолеТекста.УстановитьГраницыВыделения(1, 1, КонечнаяСтрока, КонечнаяКолонка);
	Результат = СтрДлина(СлужебноеПолеТекста.ВыделенныйТекст) + 1;
	Возврат Результат;

КонецФункции

Функция СлужебноеПолеТекста()
	
	#Если Сервер И Не Сервер Тогда
		мПлатформа = Обработки.ирПлатформа.Создать()
	#КонецЕсли
	СлужебноеПолеТекста = мПлатформа.СлужебноеПолеТекста;
	СлужебноеПолеТекста.УстановитьТекст(ПолучитьТекст());
	Возврат СлужебноеПолеТекста;

КонецФункции

Процедура Прочитать(Знач ИмяФайла) Экспорт 
	Если ТипЗнч(ЭлементФормы) = Тип("ТекстовыйДокумент") Тогда
		ЭлементФормы.Прочитать(ИмяФайла);
	Иначе
		ТекстовыйДокумент = Новый ТекстовыйДокумент;
		ТекстовыйДокумент.Прочитать(ИмяФайла);
		УстановитьТекст(ТекстовыйДокумент.ПолучитьТекст());
	КонецЕсли;
КонецПроцедуры

// Процедура - Выделение одномерное
//
// Параметры:
//  выхНачальнаяПозиция	 - Число - начиная с 1
//  выхКонечнаяПозиция	 - Число - начиная с 1
//
Функция ВыделениеОдномерное(выхНачальнаяПозиция = Неопределено, выхКонечнаяПозиция = Неопределено, Знач ДляИсходногоТекстаСравнения = Ложь) Экспорт 
	
	ПолучитьГраницыВыделения(НачальнаяСтрока, НачальнаяКолонка, КонечнаяСтрока, КонечнаяКолонка, ДляИсходногоТекстаСравнения);
	СлужебноеПолеТекста = СлужебноеПолеТекста();
	выхНачальнаяПозиция = ПозицияВПолеТекстаПоНомеруСтрокиИКолонки(НачальнаяСтрока, НачальнаяКолонка, СлужебноеПолеТекста);
	выхКонечнаяПозиция = ПозицияВПолеТекстаПоНомеруСтрокиИКолонки(КонечнаяСтрока, КонечнаяКолонка, СлужебноеПолеТекста);
	Возврат Новый Структура("Начало, Конец", выхНачальнаяПозиция, выхКонечнаяПозиция);

КонецФункции

//.
// Возвращаемое значение:
//    - дублирует см. Обработка.ирКонструкторРегулярногоВыражения.Форма.Форма.ВхожденияГруппы
Функция НайтиРегВыражение(Текст, РегВыражение) Экспорт
	РезультатыПоиска = ирОбщий.НайтиРегВыражениеЛкс(Текст, РегВыражение,,, Истина,, Ложь);
	РезультатыПоиска.Сортировать("ПозицияВхождения");
	РезультатыПоиска.Колонки.ПозицияВхождения.Имя = "ПозицияГруппы";
	РезультатыПоиска.Колонки.ДлинаВхождения.Имя = "ДлинаГруппы";
	РезультатыПоиска.Колонки.ТекстВхождения.Имя = "Значение";
	РезультатыПоиска.Колонки.Добавить("Длина", Новый ОписаниеТипов("Число"));
	Возврат РезультатыПоиска;
КонецФункции

//.
// Параметры:
//   Текст -  - 
//   РезультатыПоиска - см. НайтиРегВыражение - 
//   ИндексГруппы -  - 
//   ПереносСлов -  - 
//   Стили -  - 
//   ЛиСыройТекст -  - 
// Возвращаемое значение:
//    - 
Функция РазметитьТекстРезультатамиПоискаИУстановитьВПоле(Знач Текст = "", Знач РезультатыПоиска, Знач ИндексГруппы = -1, Знач ПереносСлов = Истина, Знач Стили = "", Знач ЛиСыройТекст = Ложь) Экспорт
	Если Не ЛиПолеHTMLДокумента() Тогда
		ВызватьИсключение "Доступно только в поле HTML";
	КонецЕсли;
	Если Не ЗначениеЗаполнено(Текст) Тогда
		Текст = ПолучитьТекст(ЛиСыройТекст, Истина);
	КонецЕсли;
	Если ЛиСыройТекст Тогда
		мСтарыйСыройТекстТела = Текст;
	КонецЕсли;
	Результат = РазметитьТекстРезультатамиПоиска(Текст, РезультатыПоиска, ИндексГруппы, ЛиСыройТекст);
	УстановитьТелоHTML(Результат, ПереносСлов, Стили,, ЛиСыройТекст);
КонецФункции

//.
// Параметры:
//   Текст - Строка - 
//   РезультатыПоиска - см. Обработка.ирКонструкторРегулярногоВыражения.Форма.Форма.ВхожденияГруппы - 
//   ИндексГруппы - Число - 
// Возвращаемое значение:
//   Строка - 
Функция РазметитьТекстРезультатамиПоиска(Знач Текст, Знач РезультатыПоиска, Знач ИндексГруппы = -1, Знач ЛиСыройТекст = Ложь) Экспорт
	ЭтотОбъект.РезультатыПоиска = РезультатыПоиска;
	#Если Сервер И Не Сервер Тогда
		РезультатыПоиска = Новый ТаблицаЗначений;
	#КонецЕсли
	МаркерКонецГруппы = "</SPAN>";
	Результат = Новый ЗаписьXML;
	Результат.УстановитьСтроку("");
	Старт = Истина;
	Финиш = 0;
	ЗначениеЧередования = Ложь;
	МаксРаскашиваемыхВхождений = 1000;
	//МассивЦветов = Новый Массив;
	//МассивЦветов.Добавить("yellow");
	//МассивЦветов.Добавить("cyan");
	//МассивЦветов.Добавить("#CCFF66"); // светло-зеленый
	//МассивЦветов.Добавить("orange");
	РаскрашеноВхождений = 0;
	ЕстьКолонкаГиперссылки = РезультатыПоиска.Колонки.Найти("ЛиГиперссылка") <> Неопределено;
	Для каждого Вхождение Из РезультатыПоиска Цикл
		Если Вхождение.ПозицияГруппы = Неопределено Или РаскрашеноВхождений > МаксРаскашиваемыхВхождений Тогда
			Продолжить;
		КонецЕсли;
		Если ИндексГруппы = -1 Тогда
			ТекстГруппы = Вхождение.Значение;
			ПозицияВнутриВхождения = 0;
		Иначе
			ТекстГруппы = Вхождение.Группы[ИндексГруппы];
			Если ТипЗнч(ТекстГруппы) <> Тип("Строка") Тогда
				ТекстГруппы = ТекстГруппы.Значение;
			КонецЕсли;
			ПозицияВнутриВхождения = Найти(Вхождение.Значение, ТекстГруппы) - 1;
		КонецЕсли;
		Если ТекстГруппы = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ПозицияГруппы = Вхождение.ПозицияГруппы + ПозицияВнутриВхождения;
		ДлинаГруппы = СтрДлина(ТекстГруппы);
		Если Старт Тогда
			Если Вхождение.ПозицияГруппы <> 0 Тогда
				ДобавитьРазмеченныйФрагмент(Результат, Сред(Текст, 1, ПозицияГруппы), ЛиСыройТекст);
			КонецЕсли;
			Старт = Ложь;
		ИначеЕсли Финиш <> 0 Тогда
			ДобавитьРазмеченныйФрагмент(Результат, Сред(Текст, Финиш, ПозицияГруппы - Финиш + 1), ЛиСыройТекст);
		КонецЕсли;
		ЗначениеГруппы = ТекстГруппы;
		Если Не ЛиСыройТекст Тогда
			ЗначениеГруппы = ирОбщий.КодироватьТекстВXMLЛкс(ЗначениеГруппы); // Мультиметка250726_113722
		КонецЕсли;
		Если ЗначениеЧередования Тогда
			ИмяЦвета = "cyan";
		Иначе
			ИмяЦвета = "yellow";
		КонецЕсли;
		Если ЕстьКолонкаГиперссылки И Вхождение.ЛиГиперссылка Тогда
			// https://stackoverflow.com/questions/42692953/make-hyperlinks-selectable
			ТегВхождения = "<A data-href=""" + "" + """ style=""text-decoration: underline"">" + ЗначениеГруппы + "</A>";
		Иначе
			ТегВхождения = "<SPAN id=""" + ИдентификаторГруппыВРазмеченномТексте(Вхождение.Номер, ИндексГруппы) + """ style=""background-color: " + ИмяЦвета + """>" + ЗначениеГруппы + "</SPAN>";
		КонецЕсли;
		Результат.ЗаписатьБезОбработки(ТегВхождения);
		РаскрашеноВхождений = РаскрашеноВхождений + 1;
		Финиш = ПозицияГруппы + ДлинаГруппы + 1;
		ЗначениеЧередования = Не ЗначениеЧередования;
	КонецЦикла;
	ДобавитьРазмеченныйФрагмент(Результат, Сред(Текст, Финиш), ЛиСыройТекст);
	Результат = Результат.Закрыть();

	Возврат Результат;
КонецФункции

Функция ПозицияГруппы(Вхождение, ИндексГруппы) Экспорт
	Если ИндексГруппы = -1 Тогда
		ПозицияВнутриВхождения = 0;
	Иначе
		ТекстГруппы = Вхождение.Группы[ИндексГруппы];
		Если ТипЗнч(ТекстГруппы) <> Тип("Строка") Тогда
			ТекстГруппы = ТекстГруппы.Значение;
		КонецЕсли;
		ПозицияВнутриВхождения = Найти(Вхождение.Значение, ТекстГруппы) - 1;
	КонецЕсли;
	Возврат Вхождение.ПозицияГруппы + ПозицияВнутриВхождения;
КонецФункции

Процедура ДобавитьРазмеченныйФрагмент(Знач Результат, Знач Текст, Знач ЛиСыройТекст) Экспорт          
	Если Не ЛиСыройТекст Тогда
		Текст = ирОбщий.КодироватьТекстВXMLЛкс(Текст); // Мультиметка250726_113722
	КонецЕсли;
	Результат.ЗаписатьБезОбработки(Текст);
КонецПроцедуры

Процедура УстановитьТелоHTML(Знач ТекстHTML, Знач ПереносСлов = Истина, Знач Стили = "", Знач ЧерезСвойство = Истина, Знач ЛиСыройТекст = Ложь) Экспорт
	
	РаскрашенныйТекст = ТекстHTML;
	Если Не ЛиСыройТекст Или Не ирОбщий.СтрНачинаетсяСЛкс(ТекстHTML, "<HTML>") Тогда
		ОформлениеТекста = "<pre style=""FONT-SIZE: 10pt; FONT-FAMILY: Courier New; color: #000000; tab-size: 4;";
		Если ПереносСлов Тогда                              
			// https://developer.mozilla.org/ru/docs/Web/CSS/overflow-wrap
			// normal, keep-all и остальные вебкит не поддерживает, т.к. в нем используется режим совместимости IE7.0 https://forum.mista.ru/topic.php?id=884540
			ОформлениеТекста = ОформлениеТекста + " word-wrap: break-word; white-space: pre-wrap;"; 
		КонецЕсли; 
		ОформлениеТекста = ОформлениеТекста + """>";
		РаскрашенныйТекст = ОформлениеТекста + РаскрашенныйТекст;
		РаскрашенныйТекст = "<HTML lang=""ru-Ru"">
		|<HEAD>
		|	<style>" + Стили + "</style>
		|</HEAD>
		|<BODY>"+ РаскрашенныйТекст + "</BODY></HTML>";
	КонецЕсли;
	ДокументHtml = ЭлементФормы.Документ; 
	Если ЧерезСвойство Тогда
		// Так функции документа будут недоступны. Может некорректно установиться фокус, если поле не имеет фокус в этом момент.
		Если Истина
			И ДокументHtml.documentElement = Неопределено
			И ПустаяСтрока(ТекстHTML)
		Тогда
			//
		ИначеЕсли ЛиСыройТекст Тогда
			ДокументHtml.body.innerHTML = РаскрашенныйТекст;
		Иначе
			Попытка
				ДокументHtml.documentElement.innerHTML = РаскрашенныйТекст;
			Исключение
				// В IE нельзя устанавливать значение свойству
				ирОбщий.УстановитьТекстВКомХтмлЛкс(ДокументHtml, ТекстHTML);
			КонецПопытки;
		КонецЕсли;
	Иначе
		// Так функции документа будут доступны
		ЭлементФормы.УстановитьТекст(РаскрашенныйТекст); // Так в форме "Текст" будет некорректно работать
	КонецЕсли;

КонецПроцедуры

Процедура УстановитьОтображаемыйТекст(Знач Текст, Знач ПереносСлов = Истина) Экспорт 
	
	УстановитьТелоHTML(ирОбщий.КодироватьТекстВXMLЛкс(Текст), ПереносСлов);

КонецПроцедуры

Функция ИдентификаторГруппыВРазмеченномТексте(Знач НомерГруппы, Знач ИндексГруппы = -1) Экспорт 
	
	Если ИндексГруппы < 0 Тогда
		ИндексГруппы = "";
	Иначе
		ИндексГруппы = XMLСтрока(ИндексГруппы);
	КонецЕсли;
	Возврат НачалоИдентифкатораРезультатПоиска() + НомерГруппы + "_SubMatch" + ИндексГруппы;

КонецФункции

Функция НачалоИдентифкатораРезультатПоиска() Экспорт
	Возврат "Match";
КонецФункции

Процедура ВыделитьРезультатПоиска(Знач РезультатПоиска, Знач ИндексГруппы = -1, Знач Центрировать = Ложь) Экспорт 
	
	#Если Сервер И Не Сервер Тогда
		РезультатПоиска = РезультатыПоиска.Добавить();
	#КонецЕсли
	ДокументHtml = ЭлементФормы.Документ;
	ИДНужныйУзел = ИдентификаторГруппыВРазмеченномТексте(РезультатПоиска.Номер, ИндексГруппы);
	ТегГруппы = Неопределено;
	//ТегГруппы = ДокументHtml.getElementByID(ИДНужныйУзел); // начиная с 8.3.14 так не работает
	ТегГруппы = ДокументHtml.querySelector("[id = " + ИДНужныйУзел + "]");
	Если ТегГруппы <> Неопределено Тогда
		ВыделитьУзелХМТЛ(ТегГруппы, Центрировать);
	КонецЕсли;

КонецПроцедуры

Процедура ВыделитьУзелХМТЛ(Знач ТегГруппы, Знач Центрировать) Экспорт
	ДокументHtml = ЭлементФормы.Документ;
	ТелоДокумента = ДокументHtml.body;
	Если ирКэш.ДоступноБраузерWebKitЛкс() Тогда
		ВыделениеВТексте = Новый Структура;
		ВыделениеВТексте.Вставить("Начало", 0);
		ВыделениеВТексте.Вставить("НачалоБезПереносов", 0);
		ВыделениеВТексте.Вставить("Конец", СтрДлина(ТегГруппы.innerText));
		ВыделениеВТексте.Вставить("КонецБезПереносов", 0);
		УстановитьВыделениеВДокументеHTML(ВыделениеВТексте, ТегГруппы, Центрировать);
	Иначе
		Диапазон = ТелоДокумента.createTextRange();
		Диапазон.moveToElementText(ТегГруппы);
		Диапазон.scrollIntoView();
		Диапазон.Select();
	КонецЕсли;
КонецПроцедуры

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

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

Функция НайтиСледующийУзелПоНачалуИдентификатора(Знач НачальныйУзел, Знач НачалоИдентификатора) Экспорт
	Стек = Новый Массив;
	Стек.Добавить(НачальныйУзел);
	Пока Стек.Количество() > 0 Цикл
		ТекущийУзел = Стек[Стек.ВГраница()]; // имитация рекурсии
		Стек.Удалить(Стек.ВГраница());
		Если Стек.Количество() = 0 Тогда
			Родитель = ТекущийУзел;
			Пока Родитель <> Неопределено И Родитель.nextSibling = Неопределено Цикл
				Родитель = Родитель.parentNode;
			КонецЦикла;
			Если Родитель <> Неопределено Тогда
				Стек.Добавить(Родитель.nextSibling);
			КонецЕсли;
		КонецЕсли;
		Идентификатор = ТекущийУзел.id;
		Если Идентификатор <> Неопределено И ирОбщий.СтрНачинаетсяСЛкс(Идентификатор, НачалоИдентификатора) Тогда
			Возврат ТекущийУзел;
		КонецЕсли;
		ДочерниеУзлы = ТекущийУзел.childNodes;
		Для Счетчик = 1 По ДочерниеУзлы.length Цикл 
			Стек.Добавить(ДочерниеУзлы[ДочерниеУзлы.length - Счетчик]);
		КонецЦикла;
	КонецЦикла;
	Возврат Неопределено;
КонецФункции   

Функция НайтиПредыдущийУзелПоНачалуИдентификатора(Знач НачальныйУзел, Знач НачалоИдентификатора) Экспорт
	Стек = Новый Массив;
	Стек.Добавить(НачальныйУзел);
	Пока Стек.Количество() > 0 Цикл
		ТекущийУзел = Стек[Стек.ВГраница()]; // имитация рекурсии
		Стек.Удалить(Стек.ВГраница());
		Если Стек.Количество() = 0 Тогда
			Родитель = ТекущийУзел;
			Пока Родитель <> Неопределено И Родитель.previousSibling = Неопределено Цикл
				Родитель = Родитель.parentNode;
			КонецЦикла;
			Если Родитель <> Неопределено Тогда
				Стек.Добавить(Родитель.previousSibling);
			КонецЕсли;
		КонецЕсли;
		Идентификатор = ТекущийУзел.id;
		Если Идентификатор <> Неопределено И ирОбщий.СтрНачинаетсяСЛкс(Идентификатор, НачалоИдентификатора) Тогда
			Возврат ТекущийУзел;
		КонецЕсли;
		ДочерниеУзлы = ТекущийУзел.childNodes;
		Для Счетчик = 1 По ДочерниеУзлы.length Цикл 
			Стек.Добавить(ДочерниеУзлы[Счетчик - 1]);
		КонецЦикла;
	КонецЦикла;
	Возврат Неопределено;
КонецФункции   

Функция ПолучитьВыделениеВДокументеHTML(выхТекст = "") Экспорт  
	ВыделениеВТексте = Новый Структура;
	ДокументHtml = ЭлементФормы.Документ;
	ТелоДокумента = ДокументHtml.body;
	Если ирКэш.ДоступноБраузерWebKitЛкс() Тогда
		ТекущееВыделение = ДокументHtml.getSelection();
		Диапазон = ДокументHtml.createRange();
		Диапазон.setStart(ДокументHtml.body, 0); // !!! Без этой строки начало диапазона может захватывать какой то мусор. Видимо ошибка платформы
		Диапазон.setEnd(ТекущееВыделение.anchorNode, ТекущееВыделение.anchorOffset);
		ТекстВыделения = Диапазон.toString();
		Начало = СтрДлина(ТекстВыделения);
		ТекстВыделения = СтрЗаменить(ТекстВыделения, Символы.ПС, "");
		НачалоБезПереносов = СтрДлина(ТекстВыделения);
		Диапазон = ДокументHtml.createRange();
		Диапазон.setStart(ТекущееВыделение.anchorNode, ТекущееВыделение.anchorOffset);
		Диапазон.setEnd(ТекущееВыделение.focusNode, ТекущееВыделение.focusOffset);
		ТекстВыделения = Диапазон.toString();
		Конец = Начало + СтрДлина(ТекстВыделения);
		выхТекст = ТекстВыделения;
		ТекстВыделения = СтрЗаменить(ТекстВыделения, Символы.ПС, "");
		КонецБезПереносов = НачалоБезПереносов + СтрДлина(ТекстВыделения);
		ВыделениеВТексте.Вставить("Начало", Начало);
		ВыделениеВТексте.Вставить("НачалоБезПереносов", НачалоБезПереносов);
		ВыделениеВТексте.Вставить("Конец", Конец);
		ВыделениеВТексте.Вставить("КонецБезПереносов", КонецБезПереносов);
		ВыделениеВТексте.Вставить("Узел", ТекущееВыделение.focusNode);
	Иначе
		ТекущееВыделение = ДокументHtml.Selection.createRange();
		Диапазон = ТелоДокумента.createTextRange();
		Диапазон.setEndPoint("EndToStart", ТекущееВыделение);
		ВыделениеВТексте.Вставить("Начало", СтрДлина(Диапазон.Text));
		ВыделениеВТексте.Вставить("НачалоБезПереносов", СтрДлина(СтрЗаменить(Диапазон.Text, Символы.ПС, "")));
		Диапазон.setEndPoint("EndToEnd", ТекущееВыделение);
		ВыделениеВТексте.Вставить("Конец", СтрДлина(Диапазон.Text));
		ВыделениеВТексте.Вставить("КонецБезПереносов", СтрДлина(СтрЗаменить(Диапазон.Text, Символы.ПС, "")));
		ВыделениеВТексте.Вставить("Узел", Неопределено);
		выхТекст = Диапазон.Text;
	КонецЕсли;
	Возврат ВыделениеВТексте;
КонецФункции

//.
// Параметры:
//   ВыделениеВТексте -  - 
//   РодительскийУзел -  - 
//   Центрировать - Булево - по родительскому элементу, если он передан
Процедура УстановитьВыделениеВДокументеHTML(Знач ВыделениеВТексте, РодительскийУзел = Неопределено, Знач Центрировать = Ложь) Экспорт 
	
	ДокументHtml = ЭлементФормы.Документ;
	ТелоДокумента = ДокументHtml.body;
	Если РодительскийУзел = Неопределено Тогда
		РодительскийУзел = ТелоДокумента;
	КонецЕсли; 
	Если ирКэш.ДоступноБраузерWebKitЛкс() Тогда
		//ВыделенныйТекст = Диапазон.toString(); // Для отладки
		//Если ДокументHtml.defaultView.scrollIntoViewMy(РодительскийУзел.id) = Неопределено Тогда
		//	РодительскийУзел.scrollIntoView(); // Агрессивный вариант, пока документ не инициировался
		//КонецЕсли;
		Если Центрировать Тогда
			Прямоугольник = РодительскийУзел.getBoundingClientRect();
			ДокументHtml.defaultView.scrollTo(0, Прямоугольник.top + ДокументHtml.defaultView.scrollY - (ДокументHtml.defaultView.innerHeight / 2) + (Прямоугольник.height / 2));
		Иначе
			РодительскийУзел.scrollIntoViewIfNeeded();
		КонецЕсли;
		Диапазон = ДокументHtml.createRange();
		Диапазон.selectNodeContents(РодительскийУзел);
		НачалоНайдено = Ложь;
		СчетчикСимволов = 0;
		ОбходчикУзлов = ДокументHtml.createTreeWalker(РодительскийУзел, 4, null, false);
		Пока Истина Цикл
			ТекстовыйУзел = ОбходчикУзлов.nextNode();
			Если ТекстовыйУзел = Неопределено Тогда
				Прервать;
			КонецЕсли;
			endCharCount = СчетчикСимволов + СтрДлина(ТекстовыйУзел.textContent);
			Если Истина
				И Не НачалоНайдено 
				И ВыделениеВТексте.Начало >= СчетчикСимволов
				И ВыделениеВТексте.Начало <= endCharCount
			Тогда 
				Диапазон.setStart(ТекстовыйУзел, ВыделениеВТексте.Начало - СчетчикСимволов);
				НачалоНайдено = Истина;
			КонецЕсли; 
			Если НачалоНайдено И ВыделениеВТексте.Конец <= endCharCount Тогда 
				Диапазон.setEnd(ТекстовыйУзел, ВыделениеВТексте.Конец - СчетчикСимволов);
				Прервать;
			КонецЕсли; 
			СчетчикСимволов = endCharCount;
		КонецЦикла; 
		ТекущееВыделение = ДокументHtml.getSelection();
		ТекущееВыделение.removeAllRanges();
		ТекущееВыделение.addRange(Диапазон);
		Если РодительскийУзел = ТелоДокумента Тогда
			Диапазон.startContainer.parentElement.scrollIntoViewIfNeeded();
		КонецЕсли;
	Иначе
		Диапазон = РодительскийУзел.createTextRange();
		Диапазон.Collapse();
		Диапазон.moveStart("character", ВыделениеВТексте.НачалоБезПереносов);
		Диапазон.moveEnd("character", ВыделениеВТексте.КонецБезПереносов - ВыделениеВТексте.НачалоБезПереносов);
		Диапазон.select();
	КонецЕсли;

КонецПроцедуры

Функция НайтиФрагментТекста(Знач ИскомыйТекст) Экспорт
	ДокументХТМЛ = ЭлементФормы.Документ.defaultView;
	Если ДокументХТМЛ.getSelection <> Неопределено Тогда
		ДокументХТМЛ.getSelection().removeAllRanges();
	КонецЕсли;	
	ДокументХТМЛ.find(ИскомыйТекст);
КонецФункции

#КонецЕсли

//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный 	Контейнер = Новый Структура();
//ирПортативный 	Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный 	Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный 		ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный 		ирПортативный.Открыть();
//ирПортативный 	КонецЕсли; 
//ирПортативный #Иначе
//ирПортативный 	ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ОбщийМодульЛкс("ирСервер");
//ирПортативный ирКлиент = ирПортативный.ОбщийМодульЛкс("ирКлиент");

мПлатформа = ирКэш.Получить();
#Если Сервер И Не Сервер Тогда
	РезультатыПоиска = 0; // см. ОбработкаОбъект.ирОболочкаПолеТекста.НайтиРегВыражение
	ФиксированноеВыделениеДвумерное = НоваяСтруктураДвумерногоВыделения();
	Если 1 Тогда
		ЭлементФормы = 0; // ПолеТекстовогоДокумента
	Иначе
		ЭлементФормы = 0; // ПолеHTMLДокумента 
	КонецЕсли; 
#КонецЕсли 
