gifts2017

Вариант перевода модальных вызовов в немодальные

Опубликовал Франко Деллиани (Franco) в раздел Программирование - Практика программирования

Рассматривается вариант рефакторинга модальных вызовов в немодальные (асинхронные) в конфигурациях 8.3.5

Начиная с версии 8.3 в платформе 1С 'не-можно' использовать модальные вызовы: Вопрос, ВвестиЗначение, ВвестиЧисло, ОткрытьФормуМодально и проч. Читать здесь. Кажется, это связано с разработкой на iPad-ах. Но вот ещё какая незадача - и в веб-клиенте Google Chrome начиная с какой-то версии (?36, ?37 - не вспомню никак) эти модальные вызовы также прекратили свою работу.

Трудностей по переделке этих вызовов на не-модальные (или 'псевдомодальные') 'выше крыши'. Всё просто, если вызовы в процедуре последовательно - разделил её на 2 или более и порядок. А если вызов в процедуре в цикле?

Например, возьмём код:

[Вариант кода №0, включает только модальные вызовы]


#Область ОбработчикиСобытийФормы
#КонецОбласти

#Область ОбработчикиСобытийЭлементовШапкиФормы
#КонецОбласти

#Область ОбработчикиСобытийЭлементовТаблицыФормы
#КонецОбласти

#Область ОбработчикиКомандФормы

// По кн.Запуска
// Параметры:
//	Команда - КомандаФормы
&НаКлиенте
Процедура комЗапускВыбора(Команда)
	ЗапускВыбора();
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращает случайное число
// Параметры:
//	низ - Число
//	верх - Число
&НаКлиенте
Функция ПолучитьСлучайноеЧисло(низ, верх)
	Генератор = Новый ГенераторСлучайныхЧисел;
	Возврат Генератор.СлучайноеЧисло(низ, верх);
КонецФункции

// Запускает выбор
// Параметры: нет
&НаКлиенте
Процедура ЗапускВыбора()
	ВведеннаяСтрока = "";
	Если Не ВвестиСтроку(ВведеннаяСтрока, НСтр("ru='Введите строку'")) Тогда
		Возврат;
	КонецЕсли;
	Если Не Вопрос(
		НСтр("ru='Продолжить?'"), 
		РежимДиалогаВопрос.ДаНет, 
		10, 
		КодВозвратаДиалога.Да, 
		НСтр("ru='Вопрос о продолжении'"), 
		КодВозвратаДиалога.Нет
	) = КодВозвратаДиалога.Да Тогда
		Возврат;
	КонецЕсли;
	РезультатЗапросаПользователя = ОткрытьФормуМодально(
		"ВнешняяОбработка.ПробаПсевдомодальныхВызовов.Форма.ЗапроснаяФорма");
	Если РезультатЗапросаПользователя = Неопределено Тогда
		Возврат;
	КонецЕсли;
	ТекстПредупреждения = НСтр("ru='%ВведеннаяСтрока%%ПодставляемыеЗначения%'");
	ПодставляемыеЗначения = "";
	ЧислоСтрок = ПолучитьСлучайноеЧисло(2, 4);
	ТекстЗаголовка = НСтр("ru='Укажите %Что% для строки %Сч% (из %ЧислоСтрок%)'");
	ТекстЗаголовка = СтрЗаменить(ТекстЗаголовка, "%ЧислоСтрок%", Строка(ЧислоСтрок));
	Для Сч = 1 По ЧислоСтрок Цикл
		ПодставляемыеЗначенияСтроки = "%СимволыПС%";
		ТекстЗаголовкаСтроки = ТекстЗаголовка;
		ТекстЗаголовкаСтроки = СтрЗаменить(ТекстЗаголовкаСтроки, "%Сч%", Строка(Сч));
		Если РезультатЗапросаПользователя.ВвестиЧисло Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "число");
			ВведенноеЧисло = 0;
			Если ВвестиЧисло(ВведенноеЧисло, ТекстЗаголовкаВвода, 6, 0) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведенноеЧисло) + ", ";
			КонецЕсли;
		КонецЕсли;
		Если РезультатЗапросаПользователя.ВвестиДату Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "дату");
			ВведеннаяДата = Дата(1,1,1);
			Если ВвестиДату(ВведеннаяДата, ТекстЗаголовкаВвода) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведеннаяДата) + ", ";
			КонецЕсли;
		КонецЕсли;
		Если РезультатЗапросаПользователя.ВвестиБулево Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "булево");
			ВведенноеБулево = Ложь;
			Если ВвестиЗначение(
				ВведенноеБулево, ТекстЗаголовкаВвода, Новый ОписаниеТипов("Булево")) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведенноеБулево);
			КонецЕсли;
		КонецЕсли;
		ПодставляемыеЗначения = ПодставляемыеЗначения + ПодставляемыеЗначенияСтроки;
	КонецЦикла;
	
	ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, 
		"%ВведеннаяСтрока%", ВведеннаяСтрока);
	ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, 
		"%ПодставляемыеЗначения%", ПодставляемыеЗначения);
	ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, 
		"%СимволыПС%", Символы.ПС);
	Предупреждение(ТекстПредупреждения);
КонецПроцедуры

#КонецОбласти

Как, наверное, из кода ясно, обработка запрашивает строку, затем разрешение продолжения, открывает модально форму, в которой нужно указать, следует ли далее вводить число, дату и булево значения. Затем рандомно задаётся целое число, в каждом цикле до заданного числа запрашивается (если выбрано, что нужно вводить) число, дата и булево. И, наконец-то, формируется показ предупреждения.

Да, пример притянут за уши. Да, в работе будут другие примеры. Более сложные.

Делаем рефакторинг средствами 1С

Если мы сделаем рефакторинг средствами 1С: ставим курсор на любом модальном вызове, щёлкаем правую кнопку мыши, выбираем Рефакторинг - Модальные вызовы - Преобразовать модальные вызовы модулей.

И наступает пичалька:

Рефакторинг средствами 1С

А когда мы поймём, где не получилось хорошо - в блоке цикла - становится совсем грустно.

И ещё рефакторинг разбил нашу процедуру на 4 разные процедуры.

Рука-лицо...

А есть ли другая возможность? Если ли возможность эмулировать функции, как у нас было при модальных вызовах? Нет?

Конечно же есть!!!

Рефакторинг через структуру данных

Идея заключается в том, что все данные последовательно писать, а затем проверять имеющееся значение. Если его нет - вызывать ввод этого значения и завершать процедуру. После ввода проверять есть это значение или нет. Если есть, то идти к следующей проверке.

Алгоритм нашего примера будет таков:

1.Проверяем, есть ли структура для записи данных. Её нет - создаём.

2.Проверяем, есть ли в этой структуре введённая строка. Нет - уходим на вызов ввода (передав туда структуру), а эту процедуру завершаем. После ввода строки вновь вызываем нашу процедуру.

3.Проверяем, что введённая строка в структуре наших данных есть. И если значение строковое, идём далее. (Ну а если Неопределено - пользователь отказался от ввода строки - завершаем).

4.Проверяем, что нет в структуре ответа на вопрос. Вызываем ПоказатьВопрос, передав туда нашу структуру. А нашу процедуру завершаем.

5.По ответу проверяем, что пользователь нажал кнопку Да. Иначе уходим.

6.Открываем форму (передав туда структуру и завершив текущую процедуру).

7.После закрытия формы вновь вызываем процедуру.

8.Если нет в структуре числа строк цикла перебора - генерируем рандом и получаем число строк.

9.И вот теперь самое интересное - приходим на цикл: в нашу структуру пишем массив. Который будет содержать [ЧислоСтрок] структур 'табличных' данных.

10.Добавляем структуру - строку массива.

11.Если нужно вводить число (это мы выбрали в открытой форме п.6) и это число в данную структуру не введено - посылаем структуру (завершив эту процедуру) во ввод числа.

12.Если нужно вводить дату - повторяем как в пункте 11.

13.Если нужно вводить булево, опять повторяем как в п.11.

Не забываем после каждого ввода завершить нашу процедуру! Таким образом вызов вноь идёт с начала процедуры проверяя уже введённые данные.

nn.Для каждого из [ЧислоСтрок] повторяем пп.10-13.

Шаг 1. Создаём структуру:

[варинат кода №1. Есть структура для хранения данных] 

&НаКлиенте
Процедура ЗапускВыбора()
	СтруктураДанных = Новый Структура;							//!!!
	ВведеннаяСтрока = "";
	Если Не ВвестиСтроку(ВведеннаяСтрока, НСтр("ru='Введите строку'")) Тогда
		Возврат;
	КонецЕсли;
	СтруктураДанных.Вставить("ВведеннаяСтрока", ВведеннаяСтрока);	                        //!!!
	Ответ = Вопрос(                                                                         //!!!
		НСтр("ru='Продолжить?'"), 
		РежимДиалогаВопрос.ДаНет, 
		10, 
		КодВозвратаДиалога.Да, 
		НСтр("ru='Вопрос о продолжении'"), 
		КодВозвратаДиалога.Нет
	);					                                                //!!!
	Если Не Ответ = КодВозвратаДиалога.Да Тогда						//!!!
		Возврат;
	КонецЕсли;
	СтруктураДанных.Вставить("Ответ", Ответ);						//!!!
	
	РезультатЗапросаПользователя = 
		ОткрытьФормуМодально(
			"ВнешняяОбработка.ПробаПсевдомодальныхВызовов.Форма.ЗапроснаяФорма");
	Если РезультатЗапросаПользователя = Неопределено Тогда
		Возврат;
	КонецЕсли;
	СтруктураДанных.Вставить(								//!!!
		"РезультатЗапросаПользователя", 
		РезультатЗапросаПользователя);
	
	ЧислоСтрок = ПолучитьСлучайноеЧисло(2, 4);
	СтруктураДанных.Вставить("ЧислоСтрок", ЧислоСтрок);				        //!!!
	
	ТекстПредупреждения = НСтр("ru='%ВведеннаяСтрока%%ПодставляемыеЗначения%'");
	ПодставляемыеЗначения = "";
	ТекстЗаголовка = НСтр("ru='Укажите %Что% для строки %Сч% (из %ЧислоСтрок%)'");
	ТекстЗаголовка = СтрЗаменить(ТекстЗаголовка, "%ЧислоСтрок%", Строка(ЧислоСтрок));
	
	МассивДанныхСтрок = Новый Массив;							//!!!
	
	Для Сч = 1 По ЧислоСтрок Цикл
		СтруктураДанныхСтрок = Новый Структура;						//!!!
		ПодставляемыеЗначенияСтроки = "%СимволыПС%";
		ТекстЗаголовкаСтроки = ТекстЗаголовка;
		ТекстЗаголовкаСтроки = СтрЗаменить(ТекстЗаголовкаСтроки, "%Сч%", Строка(Сч));
		Если РезультатЗапросаПользователя.ВвестиЧисло Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "число");
			ВведенноеЧисло = 0;
			Если ВвестиЧисло(ВведенноеЧисло, ТекстЗаголовкаВвода, 6, 0) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведенноеЧисло) + ", ";
				СтруктураДанныхСтрок.Вставить(					//!!!
					"ВведенноеЧисло", 
					ВведенноеЧисло);
			КонецЕсли;
		КонецЕсли;
		Если РезультатЗапросаПользователя.ВвестиДату Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "дату");
			ВведеннаяДата = Дата(1,1,1);
			Если ВвестиДату(ВведеннаяДата, ТекстЗаголовкаВвода) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведеннаяДата) + ", ";
				СтруктураДанныхСтрок.Вставить(					//!!!
					"ВведеннаяДата", 
					ВведеннаяДата);
			КонецЕсли;
		КонецЕсли;
		Если РезультатЗапросаПользователя.ВвестиБулево Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "булево");
			ВведенноеБулево = Ложь;
			Если ВвестиЗначение(
				ВведенноеБулево, 
				ТекстЗаголовкаВвода, 
				Новый ОписаниеТипов("Булево")) Тогда
				ПодставляемыеЗначенияСтроки = 
					ПодставляемыеЗначенияСтроки + Строка(ВведенноеБулево);
				СтруктураДанныхСтрок.Вставить(					//!!!
					"ВведенноеБулево", 
					ВведенноеБулево);
			КонецЕсли;
		КонецЕсли;
		ПодставляемыеЗначения = ПодставляемыеЗначения + ПодставляемыеЗначенияСтроки;
		МассивДанныхСтрок.Добавить(СтруктураДанныхСтрок);			        //!!!
	КонецЦикла;
	
	СтруктураДанных.Вставить(								//!!!
		"МассивДанныхСтрок", 
		МассивДанныхСтрок);
	
	ТекстПредупреждения = 
		СтрЗаменить(ТекстПредупреждения, 
		"%ВведеннаяСтрока%", 
		ВведеннаяСтрока);
	ТекстПредупреждения = 
		СтрЗаменить(ТекстПредупреждения, 
		"%ПодставляемыеЗначения%", 
		ПодставляемыеЗначения);
	ТекстПредупреждения = 
		СтрЗаменить(ТекстПредупреждения, 
		"%СимволыПС%", 
		Символы.ПС);
	Предупреждение(ТекстПредупреждения);
КонецПроцедуры 

Шаг 2.Необходимость ввода чисел, дат и булево пишем в структуру. И выделяем показ предупреждения

	//СтруктураДанных.Вставить(
	//	"РезультатЗапросаПользователя", 
	//	РезультатЗапросаПользователя);
	СтруктураДанных.Вставить("ВвестиЧисло", РезультатЗапросаПользователя.ВвестиЧисло);           //!!!
	СтруктураДанных.Вставить("ВвестиДату", РезультатЗапросаПользователя.ВвестиДату);             //!!!
	СтруктураДанных.Вставить("ВвестиБулево", РезультатЗапросаПользователя.ВвестиБулево);         //!!!
	
	ЧислоСтрок = ПолучитьСлучайноеЧисло(2, 4);
	СтруктураДанных.Вставить("ЧислоСтрок", ЧислоСтрок);
	
	ТекстЗаголовка = НСтр("ru='Укажите %Что% для строки %Сч% (из %ЧислоСтрок%)'");
	ТекстЗаголовка = СтрЗаменить(ТекстЗаголовка, "%ЧислоСтрок%", Строка(ЧислоСтрок));
	
	МассивДанныхСтрок = Новый Массив;
	
	Для Сч = 1 По ЧислоСтрок Цикл
		СтруктураДанныхСтрок = Новый Структура;
		ТекстЗаголовкаСтроки = ТекстЗаголовка;
		ТекстЗаголовкаСтроки = СтрЗаменить(ТекстЗаголовкаСтроки, "%Сч%", Строка(Сч));
		Если СтруктураДанных.ВвестиЧисло Тогда                                               //!!!
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "число");
			ВведенноеЧисло = 0;
			Если ВвестиЧисло(ВведенноеЧисло, ТекстЗаголовкаВвода, 6, 0) Тогда
				СтруктураДанныхСтрок.Вставить("ВведенноеЧисло", ВведенноеЧисло);
			КонецЕсли;
		КонецЕсли;
		Если СтруктураДанных.ВвестиДату Тогда                                                //!!!
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "дату");
			ВведеннаяДата = Дата(1,1,1);
			Если ВвестиДату(ВведеннаяДата, ТекстЗаголовкаВвода) Тогда
				СтруктураДанныхСтрок.Вставить("ВведеннаяДата", ВведеннаяДата);
			КонецЕсли;
		КонецЕсли;
		Если СтруктураДанных.ВвестиБулево Тогда                                              //!!!
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "булево");
			ВведенноеБулево = Ложь;
			Если ВвестиЗначение(
				ВведенноеБулево, 
				ТекстЗаголовкаВвода, 
				Новый ОписаниеТипов("Булево")) Тогда
				СтруктураДанныхСтрок.Вставить("ВведенноеБулево", ВведенноеБулево);
			КонецЕсли;
		КонецЕсли;
		МассивДанныхСтрок.Добавить(СтруктураДанныхСтрок);
	КонецЦикла;
	СтруктураДанных.Вставить("МассивДанныхСтрок", МассивДанныхСтрок);
	ВывестиПредупреждение(СтруктураДанных);
КонецПроцедуры

//!!!
// Выводит предупреждение по введённым данным
// Параметры:
//	СтруктураДанных - Структура
&НаКлиенте
Процедура ВывестиПредупреждение(СтруктураДанных)
	ТекстПредупреждения = НСтр("ru='%ВведеннаяСтрока%%ПодставляемыеЗначения%'");
	ТекстПредупреждения = 
		СтрЗаменить(
			ТекстПредупреждения, 
			"%ВведеннаяСтрока%", 
			СтруктураДанных.ВведеннаяСтрока);
	ПодставляемыеЗначения = "";
	МассивДанныхСтрок = СтруктураДанных.МассивДанныхСтрок;
	Для Каждого СтруктураДанныхСтрок Из МассивДанныхСтрок Цикл
		ПодставляемыеЗначенияСтроки = "";
		Если СтруктураДанныхСтрок.Свойство("ВведенноеЧисло") И 
			Не СтруктураДанныхСтрок.ВведенноеЧисло = Неопределено Тогда
			ПодставляемыеЗначенияСтроки = 
				ПодставляемыеЗначенияСтроки + 
					Строка(СтруктураДанныхСтрок.ВведенноеЧисло) + ", ";
		КонецЕсли;
		Если СтруктураДанныхСтрок.Свойство("ВведеннаяДата") И 
			Не СтруктураДанныхСтрок.ВведеннаяДата = Неопределено Тогда
			ПодставляемыеЗначенияСтроки = 
				ПодставляемыеЗначенияСтроки + 
					Строка(СтруктураДанныхСтрок.ВведеннаяДата) + ", ";
		КонецЕсли;
		Если СтруктураДанныхСтрок.Свойство("ВведенноеБулево") И 
			Не СтруктураДанныхСтрок.ВведенноеБулево = Неопределено Тогда
			ПодставляемыеЗначенияСтроки = 
				ПодставляемыеЗначенияСтроки + 
					Строка(СтруктураДанныхСтрок.ВведенноеБулево) + ", ";
		КонецЕсли;
		Если СтрДлина(ПодставляемыеЗначенияСтроки) Тогда
			ПодставляемыеЗначенияСтроки = 
				Лев(ПодставляемыеЗначенияСтроки, 
					СтрДлина(ПодставляемыеЗначенияСтроки) - 2);
		КонецЕсли;
		ПодставляемыеЗначения = 
			ПодставляемыеЗначения + 
			"%СимволыПС%" + 
			ПодставляемыеЗначенияСтроки;
	КонецЦикла;
	ТекстПредупреждения = СтрЗаменить(
		ТекстПредупреждения, 
		"%ПодставляемыеЗначения%", 
		ПодставляемыеЗначения);
	ТекстПредупреждения = СтрЗаменить(
		ТекстПредупреждения, 
		"%СимволыПС%", 
		Символы.ПС);
	ПоказатьПредупреждение(, ТекстПредупреждения);
КонецПроцедуры 

Предупреждение ничего не решает. Хотя это наш 1-ый псевдомодальный вызов. Поздравляю!!!

Шаг 3. Создаём вызовы пока для тех, кто не в цикле

// Завершает ввод строки
// Параметры:
//	ВведеннаяСтрока - Строка, Неопределено
//	ДопПараметры - Структура
&НаКлиенте
Процедура ЗавершениеВводаСтроки(ВведеннаяСтрока, ДопПараметры) Экспорт
	ДопПараметры.СтруктураДанных.Вставить(ДопПараметры.КлючВставки, ВведеннаяСтрока);
	ЗапускВыбора(ДопПараметры.СтруктураДанных);
КонецПроцедуры

// Завершает ответ на вопрос
// Параметры:
//	Ответ - КодВозвратаДиалога, Неопределено
//	ДопПараметры - Структура
&НаКлиенте
Процедура ЗавершениеВопроса(Ответ, ДопПараметры) Экспорт
	ДопПараметры.СтруктураДанных.Вставить(ДопПараметры.КлючВставки, Ответ);
	ЗапускВыбора(ДопПараметры.СтруктураДанных);
КонецПроцедуры

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

#КонецОбласти //ПсевдоМодальныеПроцедуры

// Запускает выбор
// Параметры: нет
&НаКлиенте
Процедура ЗапускВыбора(СтруктураДанных = Неопределено)
	Если СтруктураДанных = Неопределено Тогда
		СтруктураДанных = Новый Структура;
	КонецЕсли;
	
	Если Не СтруктураДанных.Свойство("ВведеннаяСтрока") Тогда
		ВведеннаяСтрока = "";
		ПоказатьВводСтроки(
			Новый ОписаниеОповещения(
				"ЗавершениеВводаСтроки", 
				ЭтотОбъект, 
				Новый Структура(
					"СтруктураДанных, КлючВставки", 
					СтруктураДанных, "ВведеннаяСтрока")), 
			ВведеннаяСтрока, 
			НСтр("ru='Введите строку'")
		);
		Возврат;
	ИначеЕсли СтруктураДанных.ВведеннаяСтрока = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если Не СтруктураДанных.Свойство("ОтветНаВопросОПродолжении") Тогда
		ПоказатьВопрос(
			Новый ОписаниеОповещения(
				"ЗавершениеВопроса", 
				ЭтотОбъект,
				Новый Структура(
					"СтруктураДанных, КлючВставки", 
					СтруктураДанных, "ОтветНаВопросОПродолжении") 
			),
			НСтр("ru='Продолжить?'"), 
			РежимДиалогаВопрос.ДаНет, 
			10, 
			КодВозвратаДиалога.Да, 
			НСтр("ru='Вопрос о продолжении'"), 
			КодВозвратаДиалога.Нет
		);
		Возврат;
	ИначеЕсли СтруктураДанных.ОтветНаВопросОПродолжении = Неопределено Или 
		Не СтруктураДанных.ОтветНаВопросОПродолжении = КодВозвратаДиалога.Да Тогда
		Возврат;
	КонецЕсли;
	
	Если Не СтруктураДанных.Свойство("ВвестиЧисло") И 
		Не СтруктураДанных.Свойство("ВвестиДату") И 
		Не СтруктураДанных.Свойство("ВвестиБулево") Тогда
		СтруктураДанных.Вставить("ВвестиЧисло");
		СтруктураДанных.Вставить("ВвестиДату");
		СтруктураДанных.Вставить("ВвестиБулево");
		ОткрытьФорму(
			"ВнешняяОбработка.ПробаПсевдомодальныхВызовов.Форма.ЗапроснаяФорма",,,,,, 
			Новый ОписаниеОповещения("ЗавершениеОткрытияФормы", ЭтотОбъект, 
				Новый Структура(
					"СтруктураДанных, КлючВставки", 
					СтруктураДанных, "ВвестиЧисло, ВвестиДату, ВвестиБулево")), 
			РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
		Возврат;
	КонецЕсли;
	
	ЧислоСтрок = ПолучитьСлучайноеЧисло(2, 4);
	СтруктураДанных.Вставить("ЧислоСтрок", ЧислоСтрок);
	
	ТекстЗаголовка = НСтр("ru='Укажите %Что% для строки %Сч% (из %ЧислоСтрок%)'");
	ТекстЗаголовка = СтрЗаменить(ТекстЗаголовка, "%ЧислоСтрок%", Строка(ЧислоСтрок));
	
	МассивДанныхСтрок = Новый Массив;
	
	Для Сч = 1 По ЧислоСтрок Цикл
		СтруктураДанныхСтрок = Новый Структура;
		ТекстЗаголовкаСтроки = ТекстЗаголовка;
		ТекстЗаголовкаСтроки = СтрЗаменить(ТекстЗаголовкаСтроки, "%Сч%", Строка(Сч));
		Если СтруктураДанных.ВвестиЧисло Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "число");
			ВведенноеЧисло = 0;
			Если ВвестиЧисло(ВведенноеЧисло, ТекстЗаголовкаВвода, 6, 0) Тогда
				СтруктураДанныхСтрок.Вставить("ВведенноеЧисло", ВведенноеЧисло);
			КонецЕсли;
		КонецЕсли;
		Если СтруктураДанных.ВвестиДату Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "дату");
			ВведеннаяДата = Дата(1,1,1);
			Если ВвестиДату(ВведеннаяДата, ТекстЗаголовкаВвода) Тогда
				СтруктураДанныхСтрок.Вставить("ВведеннаяДата", ВведеннаяДата);
			КонецЕсли;
		КонецЕсли;
		Если СтруктураДанных.ВвестиБулево Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "булево");
			ВведенноеБулево = Ложь;
			Если ВвестиЗначение(
				ВведенноеБулево, 
				ТекстЗаголовкаВвода, 
				Новый ОписаниеТипов("Булево")) Тогда
				СтруктураДанныхСтрок.Вставить("ВведенноеБулево", ВведенноеБулево);
			КонецЕсли;
		КонецЕсли;
		МассивДанныхСтрок.Добавить(СтруктураДанныхСтрок);
	КонецЦикла;
	СтруктураДанных.Вставить("МассивДанныхСтрок", МассивДанныхСтрок);
	ВывестиПредупреждение(СтруктураДанных);
КонецПроцедуры 

Обратите внимание: здесь мы перевели ВвестиСтроку на ПоказатьВводСтроки, Вопрос на ПоказатьВопрос и ОткрытьФормуМодально на ОткрытьФорму и после каждого этого вызова завершаем нашу процедуру:

		Возврат;

а после каждого завершения - запускаем нашу процедуру.

а если строку 'возвращаем' в Неопределено или Ответ в 'Нет', то выходим совсем.

		Возврат;
	ИначеЕсли СтруктураДанных.ОтветНаВопросОПродолжении = Неопределено Или 
		Не СтруктураДанных.ОтветНаВопросОПродолжении = КодВозвратаДиалога.Да Тогда
		Возврат;
	КонецЕсли;

Шаг 4. Теперь для тех кто в цикле

// Завершает ввод числа
// Параметры:
//	ВведенноеЧисло - Число, Неопределено
//	ДопПараметры - Структура
&НаКлиенте
Процедура ЗавершениеВводаЧисла(ВведенноеЧисло, ДопПараметры) Экспорт
	Если Не ДопПараметры.Свойство("ПодСтруктураДанных") Тогда
		ДопПараметры.СтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведенноеЧисло);
	Иначе
		ДопПараметры.ПодСтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведенноеЧисло);
	КонецЕсли;
	ЗапускВыбора(ДопПараметры.СтруктураДанных);
КонецПроцедуры

// Завершает ввод даты
// Параметры:
//	ВведеннаяДата - Дата, Неопределено
//	ДопПараметры - Структура
&НаКлиенте
Процедура ЗавершениеВводаДаты(ВведеннаяДата, ДопПараметры) Экспорт
	Если Не ДопПараметры.Свойство("ПодСтруктураДанных") Тогда
		ДопПараметры.СтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведеннаяДата);
	Иначе
		ДопПараметры.ПодСтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведеннаяДата);
	КонецЕсли;
	ЗапускВыбора(ДопПараметры.СтруктураДанных);
КонецПроцедуры

// Завершает ввод значения
// Параметры:
//	ВведенноеЗначение - Произвольное, Неопределено
//	ДопПараметры - Структура
&НаКлиенте
Процедура ЗавершениеВводаЗначения(ВведенноеЗначение, ДопПараметры) Экспорт
	Если Не ДопПараметры.Свойство("ПодСтруктураДанных") Тогда
		ДопПараметры.СтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведенноеЗначение);
	Иначе
		ДопПараметры.ПодСтруктураДанных.Вставить(
			ДопПараметры.КлючВставки, ВведенноеЗначение);
	КонецЕсли;
	ЗапускВыбора(ДопПараметры.СтруктураДанных);
КонецПроцедуры
...
	ТекстЗаголовка = НСтр("ru='Укажите %Что% для строки %Сч% (из %ЧислоСтрок%)'");
	ТекстЗаголовка = СтрЗаменить(ТекстЗаголовка, "%ЧислоСтрок%", Строка(ЧислоСтрок));
	
	Если Не СтруктураДанных.Свойство("МассивДанныхСтрок") Тогда
		СтруктураДанных.Вставить("МассивДанныхСтрок", Новый Массив);
	КонецЕсли;
	
	Для Сч = 1 По ЧислоСтрок Цикл
		Если СтруктураДанных.МассивДанныхСтрок.Количество() < Сч Тогда
			СтруктураДанных.МассивДанныхСтрок.Добавить(Новый Структура);
		КонецЕсли;
		СтруктураДанныхСтрок = СтруктураДанных.МассивДанныхСтрок[Сч - 1];
		ТекстЗаголовкаСтроки = ТекстЗаголовка;
		ТекстЗаголовкаСтроки = СтрЗаменить(ТекстЗаголовкаСтроки, "%Сч%", Строка(Сч));
		Если СтруктураДанных.ВвестиЧисло И 
			Не СтруктураДанныхСтрок.Свойство("ВведенноеЧисло") Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "число");
			ВведенноеЧисло = 0;
			ПоказатьВводЧисла(
				Новый ОписаниеОповещения(
					"ЗавершениеВводаЧисла",
					ЭтотОбъект,
					Новый Структура(
						"СтруктураДанных, ПодСтруктураДанных, КлючВставки", 
						СтруктураДанных, СтруктураДанныхСтрок, "ВведенноеЧисло")
				), 
				ВведенноеЧисло, ТекстЗаголовкаВвода);
			Возврат;
		ИначеЕсли СтруктураДанных.ВвестиЧисло И 
			СтруктураДанныхСтрок.ВведенноеЧисло = Неопределено Тогда
			СтруктураДанныхСтрок.Вставить("ВведенноеЧисло", 0);
		КонецЕсли;
		Если СтруктураДанных.ВвестиДату И 
			Не СтруктураДанныхСтрок.Свойство("ВведеннаяДата") Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "дату");
			ВведеннаяДата = Дата(1,1,1);
			ПоказатьВводДаты(
				Новый ОписаниеОповещения(
					"ЗавершениеВводаДаты",
					ЭтотОбъект,
					Новый Структура(
						"СтруктураДанных, ПодСтруктураДанных, КлючВставки", 
						СтруктураДанных, СтруктураДанныхСтрок, "ВведеннаяДата")
				), 
				ВведеннаяДата, ТекстЗаголовкаВвода);
			Возврат;
		ИначеЕсли СтруктураДанных.ВвестиДату И 
			СтруктураДанныхСтрок.ВведеннаяДата = Неопределено Тогда
			СтруктураДанныхСтрок.Вставить("ВведеннаяДата", Дата(1,1,1));
		КонецЕсли;
		Если СтруктураДанных.ВвестиБулево И 
			Не СтруктураДанныхСтрок.Свойство("ВведенноеБулево") Тогда
			ТекстЗаголовкаВвода = ТекстЗаголовкаСтроки;
			ТекстЗаголовкаВвода = СтрЗаменить(ТекстЗаголовкаВвода, "%Что%", "булево");
			ВведенноеБулево = Ложь;
			ПоказатьВводЗначения(
				Новый ОписаниеОповещения(
					"ЗавершениеВводаЗначения",
					ЭтотОбъект,
					Новый Структура(
						"СтруктураДанных, ПодСтруктураДанных, КлючВставки", 
						СтруктураДанных, СтруктураДанныхСтрок, "ВведенноеБулево")
				), 
				ВведенноеБулево, ТекстЗаголовкаВвода);
			Возврат;
		ИначеЕсли СтруктураДанных.ВвестиБулево И 
			СтруктураДанныхСтрок.ВведеннаяДата = Неопределено Тогда
			СтруктураДанныхСтрок.Вставить("ВведенноеБулево", Ложь);
		КонецЕсли;
	КонецЦикла;
	ВывестиПредупреждение(СтруктураДанных);
КонецПроцедуры 

Точно также проверяем, что число / дату / булево требуется вводить и они не введены. Посылаем программу на ввод данных и завершаем процедуру. Она получает ввод и вновь запускает нашу процедуру. Вновь проверяет все введённые данные и приходит к невведённым.

Вот и всё! Работает! Можно смело идти в свойства конфигурации и ставить 'Режим использования модальности' - 'Не использовать'. Если это единственная обработка с модальными вызовами, конечно...

'Русская весна. А что дальше?!'

Процедур всё равно много. И сидят они в одной единственной обработке. А как сделать, чтобы модальные в псевдомодальные м.б.переделать во всей конфигурации?

Но мы не были бы мы, русскими программистами, если бы не сделали отдельный модуль для псевдомодальных вызовов.

Пересяем все эти вызовы в общий клиентский модуль, например, 'АсинхронныеВызовы'. А чтобы узнавать, куда потом 'стучаться', передавайте также в дополнительные параметры текущий модуль и имя процедуры:

в обработке:

	Если Не СтруктураДанных.Свойство("ВведеннаяСтрока") Тогда
		ВведеннаяСтрока = "";
		ПоказатьВводСтроки(
			Новый ОписаниеОповещения(
				"ЗавершениеВводаСтроки", 
				АсинхронныеВызовы, 
				Новый Структура("СтруктураДанных, КлючВставки, модуль, ИмяПроцедуры", 
					СтруктураДанных, "ВведеннаяСтрока", ЭтотОбъект, "ЗапускВыбора")), 
			ВведеннаяСтрока, 
			НСтр("ru='Введите строку'")
		);

в общем модуле для каждого вызова сделаем завершение. По переданному имени процедуры узнаём какую процедуру нужно вызвать. Другого [универсального] способа я не нашёл (оператор выполнить не поддерживается на веб-клиенте): 

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

По прилагаемой обработке:

её можно не закачивать. Весь код с избытком здесь.

Спасибо за внимание. Надеюсь, кому-нибудь моя идея поможет!

PS.А как же замена модальных вызовов в функциях. Хм, тут надо подумать...

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

Наименование Файл Версия Размер
Обработка с примером перевода модальных вызовов на немодальные 4
.epf 30,67Kb
05.10.14
4
.epf abc 30,67Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Сергей Галюк (dj_serega) 07.10.14 16:48
Занимательно. Есть над чем поразмыслить.
Было бы хорошо задачи получать с учетом модальности =)
3. Яков Коган (Yashazz) 09.10.14 23:11
Коллега, если у вас код с модальным окном в цикле, то безо всяких 8.3 скажу вам, что рефакторить немедленно, это ж полная лажа. Это надо идеологически реорганизовывать, выносить на интерфейс для пред-/пост-обработки.
А что до идеи, то "сгребалка" всея асинхронов на ИС уже предлагалась, и даже более универсально, чем у вас.
корум; 1cmax; zqzq; +3 Ответить 1
4. Франко Деллиани (Franco) 10.10.14 15:15
(3) Yashazz,
1.Не у меня, а в примере. Что можно получить, когда разбираешь конфигурацию, где на каждую ранее заполненную строчку идут вопросы.
2.можно пример что предлагалось?
5. Maximilian Alekseevich (1cmax) 28.07.15 22:31
(1) dj_serega, печать в том, что если у тебя КА 1.1, и нужен вебклиент, то отказаться от режима совместимости 8.2 не получится. а какие там асинхронные процедуры. немодальность движение правильное, но в реальных задачах не всегда приятное