// ***********************************************************************************************
// Возвращает индекс элемента формы, заданный при помощи спецзнака "_", без спецзнака вернет 0 
//
// Пример: ПолучитьИндексПоИмени("Телефон_1") вернет 1   
//         ПолучитьИндексПоИмени("Телефон_0") вернет 0
//         ПолучитьИндексПоИмени("Телефон")   вернет 0
// ***********************************************************************************************
Функция ПолучитьИндексПоИмени(Знач Имя) Экспорт
    ИмяДлина = СтрДлина(Имя);
    ПозицияСпецСимвола = СтрНайти(Имя, "_", НаправлениеПоиска.СКонца);
    Попытка    Возврат Цел(Прав(Имя, ИмяДлина - ПозицияСпецСимвола));
    Исключение Возврат 0;
    КонецПопытки;
КонецФункции // ПолучитьИндексПоИмени()
// ***********************************************************************************************
// Возвращает ссылку на элемент формы, заданный при помощи спецзнака "_" или без для 0 индекса
//
// Пример: ПолучитьЭлементПоИндексу(ЭтаФорма, 1, "Телефон") вернет ссылку на Элементы.Телефон_1  
//         ПолучитьЭлементПоИндексу(ЭтаФорма, ,  "Телефон") вернет ссылку на Элементы.Телефон 
//
//         ПолучитьЭлементПоИндексу(ЭтаФорма, 0, "Телефон") вернет ссылку на Элементы.Телефон_0, 
//         если Элементы.Телефон_0 не найден вернет ссылку на Элементы.Телефон 
// ***********************************************************************************************  
Функция ПолучитьЭлементПоИндексу(Форма, Индекс = Неопределено, ШаблонИмени) Экспорт
    Элемент = Форма.Элементы.Найти(ШаблонИмени + ?(Индекс = Неопределено, "", "_" + Индекс));
    Если Элемент = Неопределено И Индекс = 0 Тогда 
        Элемент = Форма.Элементы.Найти(ШаблонИмени);
    КонецЕсли;
    Возврат Элемент; 
КонецФункции // ПолучитьЭлементПоИндексу()    
// ***********************************************************************************************
// Ищет в группе команды соответствующие шаблону и устанавливает у них параметр видимость
//
// Пример: НайтиКомандуПоШаблонуИУстановитьВидимость(Форма.Элементы.ГруппаEmail, "Удалить", Ложь)
// ***********************************************************************************************  
Процедура НайтиКомандуПоШаблонуИУстановитьВидимость(ГруппаПоиска, ШаблонПоиска, Состояние) Экспорт 
    Для Каждого Элемент Из ГруппаПоиска.ПодчиненныеЭлементы Цикл   
        Если    ТипЗнч(Элемент) = Тип("КнопкаФормы") И СтрНайти(Элемент.Имя, ШаблонПоиска) <> 0 Тогда
            Элемент.Доступность = Состояние; 
        ИначеЕсли ТипЗнч(Элемент) = Тип("ГруппаФормы") Тогда
            НайтиКомандуПоШаблонуИУстановитьВидимость(Элемент, ШаблонПоиска, Состояние);
        ИначеЕсли ТипЗнч(Элемент) = Тип("ПолеФормы") Тогда 
            НайтиКомандуПоШаблонуИУстановитьВидимость(Элемент.КонтекстноеМеню, ШаблонПоиска, Состояние)
        КонецЕсли;    
    КонецЦикла;                                                                     
КонецПроцедуры // НайтиКомандуПоШаблонуИУстановитьВидимость()
// ***********************************************************************************************
// Добавляет строку в таблицу и настраивает видимость элементов, возвращает ссылку на строку 
//
// Пример: ДобавитьСтроку(ЭтаФорма, Объект.Телефоны, Элементы.ГруппаТелефон, 10)
// ***********************************************************************************************
Функция ДобавитьСтроку(Форма, ТаблицаИсточникДанных, ГруппаИсточник, МаксКоличествоСтрок = Неопределено, СкрытьЗаголовок = Истина) Экспорт  
    Строка = Неопределено;
    Если ТаблицаИсточникДанных.Количество() <> МаксКоличествоСтрок Тогда    
        // Определяем текущую строку и индекс группы
        Строка  = ТаблицаИсточникДанных.Добавить();
        Индекс  = ТаблицаИсточникДанных.Количество() - 1; 
        // Устанавливаем видимость группы
        ГруппаКопии = TableAsInputField.ПолучитьЭлементПоИндексу(Форма, Индекс, ГруппаИсточник.Имя);   
        Если ГруппаКопии <> Неопределено Тогда 
            ГруппаКопии.Видимость = Истина; 
        Иначе 
            ГруппаКопии = СкопироватьЭлемент(Форма, ГруппаИсточник, Индекс, СкрытьЗаголовок);
            #Если Не Сервер Тогда
            ВызватьИсключение("Создавать элементы формы можно только в серверной процедуре!" + Символы.ПС + ОписаниеОшибки());
            #КонецЕсли
        КонецЕсли; 
        // Устанавливаем доступность команды "удалить"  
        НайтиКомандуПоШаблонуИУстановитьВидимость(ГруппаКопии, "Удалить", Истина);  
        Форма.Модифицированность = Истина;
    КонецЕсли;
    Возврат Строка; 
КонецФункции // ДобавитьСтроку()  
// ***********************************************************************************************
// Удаляет строку из таблицы и настраивает видимость элементов   
//
// Пример: УдалитьСтроку(ЭтаФорма, Объект.Телефоны, Элементы.ГруппаТелефон, Истина, "Уверены?")
//         УдалитьСтроку(ЭтаФорма, Объект.Телефоны, Элементы.ГруппаТелефон)
// *********************************************************************************************** 
&НаКлиенте
Асинх Процедура УдалитьСтроку(Форма, ТаблицаИсточникДанных, ГруппаИсточник, ЗадатьВопрос = Ложь, Вопрос = Неопределено) Экспорт
    Строка  = ТаблицаИсточникДанных[TableAsInputField.ПолучитьИндексПоИмени(Форма.ТекущийЭлемент.Имя)];
    Индекс  = ТаблицаИсточникДанных.Количество() - 1; 
    Вопрос = ?(Вопрос = Неопределено, "Удалить текущую запись?", Вопрос);
    Подтверждено = ?(ЗадатьВопрос = Истина, 
                   Ждать ВопросАсинх(Вопрос, РежимДиалогаВопрос.ДаНет, 0, КодВозвратаДиалога.Нет),
                   КодВозвратаДиалога.Да);
    Если Подтверждено = КодВозвратаДиалога.Да Тогда
        // Удаляем текущую строку
        ТаблицаИсточникДанных.Удалить(Строка);   
        // Устанавливаем видимость группы
        ГруппаКопии = TableAsInputField.ПолучитьЭлементПоИндексу(Форма, Индекс, ГруппаИсточник.Имя);   
        Если ГруппаКопии <> Неопределено И ТаблицаИсточникДанных.Количество() <> 0 Тогда 
            ГруппаКопии.Видимость = Ложь;  
        КонецЕсли;    
        // На ВебКлиенте при скрытии элементов формы, поля не обновляются, 
        // поэтому получаем группу для их принудительного обновления
        #Если ВебКлиент Тогда 
        ГруппаРодитель = Форма.Элементы.Найти(ГруппаИсточник.Родитель.Имя); 
        #КонецЕсли
        // Устанавливаем доступность команды "удалить"  
        НайтиКомандуПоШаблонуИУстановитьВидимость(ГруппаКопии, "Удалить", Ложь); 
        Форма.Модифицированность = Истина; 
        // Если ВебКлиент, обновляем все элементы группы родителя принудительно        
        #Если ВебКлиент Тогда 
        Форма.ОбновитьОтображениеДанных(ГруппаРодитель); 
        #КонецЕсли
    КонецЕсли;
КонецПроцедуры // УдалитьСтроку() 
// ***********************************************************************************************
// Устанавливает видимость групп для вывода талицы как отдельных полей ввода строк 
// *Если поле не найдено, создает его программно
//
// Пример: ВывестиСтрокиТаблицыИсточника(ЭтаФорма, Объект.Телефоны, Элементы.ГруппаТелефон)
// ***********************************************************************************************  
Процедура ВывестиСтрокиТаблицыИсточника(Форма, ТаблицаИсточникДанных, ГруппаИсточник, СкрытьЗаголовок = Истина) Экспорт     
#Если Сервер Тогда
    // Обходим все элементы таблицы источника данных
    Для Индекс = 0 To ТаблицаИсточникДанных.Количество() - 1 Цикл    
        // Устанавливаем видимость группы
        ГруппаКопии = TableAsInputField.ПолучитьЭлементПоИндексу(Форма, Индекс, ГруппаИсточник.Имя);   
        Если ГруппаКопии <> Неопределено Тогда 
            ГруппаКопии.Видимость = ГруппаИсточник.Видимость; 
        Иначе                                
            ГруппаКопии = СкопироватьЭлемент(Форма, ГруппаИсточник, Индекс, СкрытьЗаголовок);
        КонецЕсли;
        // Устанавливаем доступность команды "удалить"  
        НайтиКомандуПоШаблонуИУстановитьВидимость(ГруппаКопии, "Удалить", Истина); 
    КонецЦикла;
#Иначе
    ВызватьИсключение("Функция ВывестиСтрокиТаблицыИсточника может быть вызвана только в серверной процедуре!
          |Например, внутри процедуры ПриСозданииНаСервере()" + Символы.ПС + ОписаниеОшибки());
#КонецЕсли  
КонецПроцедуры // ВывестиСтрокиТаблицыИсточника()  
// *********************************************************************************************** 
// Процедура создает копию элемента формы
//
// Форма           - Форма источник
// Источник        - элемент который копируется       
// Группа             - необязательный параметр, группа куда будет вставлен скопированный элемент  
// Индекс          - индекс строки в пути к данным поля ввода
// СкрытьЗаголовок - если значение Истина, заголовок будет скрыт   
// ***********************************************************************************************
Функция СкопироватьЭлемент(Форма, Источник, Индекс, СкрытьЗаголовок, Группа = Неопределено)   
    // Определяем группу родитель и текущий вызов на рекурсию
    Если Группа = Неопределено Тогда
        Группа = Форма.Элементы.Найти(Источник.Родитель.Имя);
        ЭтоРекурсия = Ложь;
    Иначе 
        ЭтоРекурсия = Истина;
    КонецЕсли; 
    // Добавляем элемент формы
    Копия = Форма.Элементы.Добавить(Источник.Имя + "_" + Индекс, ТипЗнч(Источник), Группа); 
    // Копируем реквизиты и параметры элемента из элемента источника
    Если ТипЗнч(Источник) = Тип("ГруппаФормы") Тогда
        СкопироватьГруппуФормыБезЭлементов(Форма, Источник, Копия);
        // Отключаем видимость группы пока не будут скопированы все элементы
        Если ЭтоРекурсия = Ложь Тогда                   
            Копия.Видимость = Ложь;
        КонецЕсли;
        СкопироватьПодчиненныеЭлементы(Форма, Копия, Источник, Индекс, СкрытьЗаголовок);
    ИначеЕсли ТипЗнч(Источник) = Тип("ПолеФормы") Тогда   
        Если Группа <>  Неопределено И СкрытьЗаголовок = Истина Тогда 
            Цвет = ?(Группа.ЦветФона.Вид = ВидЦвета.АвтоЦвет, New Цвет(255, 255, 255), Группа.ЦветФона); 
        Иначе
            Цвет = Неопределено;
        КонецЕсли;   
        СкопироватьПолеФормы(Форма, Источник, Копия, Индекс, Цвет);    
        СкопироватьПодчиненныеЭлементы(Форма, Копия.КонтекстноеМеню, Источник.КонтекстноеМеню, Индекс, СкрытьЗаголовок);
    Иначе
        ЗаполнитьЗначенияСвойств(Копия, Источник);
    КонецЕсли;  
    // Все элементы скопированы, возвращаем видимость группы  
    Если ЭтоРекурсия = Ложь Тогда                   
        Копия.Видимость = Источник.Видимость; 
        Возврат Копия;
    КонецЕсли;
КонецФункции // СкопироватьЭлемент()
// ***********************************************************************************************
// Сервисная процедура
// ***********************************************************************************************
Процедура СкопироватьПодчиненныеЭлементы(Форма, ГруппаКопии, Источник, Индекс, СкрытьЗаголовок)
    Для Каждого Элемент Из Источник.ПодчиненныеЭлементы Цикл
        СкопироватьЭлемент(Форма, Элемент, Индекс, СкрытьЗаголовок, ГруппаКопии);
    КонецЦикла; 
КонецПроцедуры // СкопироватьПодчиненныеЭлементы()              
  
// ***********************************************************************************************
// Сервисная процедура
// ***********************************************************************************************
Процедура СкопироватьПолеФормы(Форма, Источник, Копия, Индекс, ЦветЗаголовка) 
    Если ТипЗнч(Источник) = Тип("ПолеФормы") Тогда
        Копия.Вид = Источник.Вид;
        // Ищем опреатор []
        ЛевСкобка  = СтрНайти(Источник.ПутьКДанным, "[");
        ПрвСкобка = СтрНайти(Источник.ПутьКДанным, "[");
        Размер    = СтрДлина(Источник.ПутьКДанным); 
        Если ЛевСкобка = 0 ИЛИ ПрвСкобка = 0 Тогда 
            Копия.ПутьКДанным = Источник.ПутьКДанным;  
        Иначе
            Копия.ПутьКданным = Лев(Источник.ПутьКДанным, ЛевСкобка) + Индекс + Прав(Источник.ПутьКДанным, Размер - ПрвСкобка - 1);
        КонецЕсли;
        Если Источник.Вид = ВидПоляФормы.ПолеВвода Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,, "ВыделенныйТекст, СвязьПоТипу, ПутьКДанным");
            Если  Источник.СвязьПоТипу.ПутьКДанным <> "" Тогда
                ПутьКДаннымСвязиПриемника = СтрЗаменить(Источник.СвязьПоТипу.ПутьКДанным, Источник.Имя, Копия.Имя);
                Копия.СвязьПоТипу = New СвязьПоТипу(ПутьКДаннымСвязиПриемника, Источник.СвязьПоТипу.ЭлементСвязи);    
            КонецЕсли; 
            ЗаполнитьКоллекциюСвойств(Копия.СписокВыбора, Источник.СписокВыбора);
        ИначеЕсли Источник.Вид = ВидПоляФормы.ПолеПереключателя Тогда
            ЗаполнитьКоллекциюСвойств(Копия.СписокВыбора, Источник.СписокВыбора);
            ЗаполнитьЗначенияСвойств(Копия, Источник,,"ПутьКДанным");
        ИначеЕсли Источник.Вид = ВидПоляФормы.ПолеТекстовогоДокумента Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,,"ПутьКДанным, ВыделенныйТекст");
        ИначеЕсли Источник.Вид = ВидПоляФормы.ПолеФорматированногоДокумента Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,,"ПутьКДанным, ВыделенныйТекст");
        Иначе
            ЗаполнитьЗначенияСвойств(Копия, Источник,,"ПутьКДанным");
        КонецЕсли; 
        Если ЦветЗаголовка <> Неопределено Тогда 
            Копия.ЦветТекстаЗаголовка = ЦветЗаголовка;
        КонецЕсли;
        СкопироватьСобытия(Копия, Источник);
    КонецЕсли; 
КонецПроцедуры // СкопироватьПолеФормы()                 
// ***********************************************************************************************
// Сервисная процедура
// ***********************************************************************************************
Процедура СкопироватьГруппуФормыБезЭлементов(Форма, Источник, Копия)
    Если ТипЗнч(Источник) = Тип("ГруппаФормы") Тогда
        Копия.Вид = Источник.Вид;
        Если Источник.Вид = ВидГруппыФормы.ОбычнаяГруппа Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,, "ПутьКДаннымЗаголовка");  
        ИначеЕсли Источник.Вид = ВидГруппыФормы.Страницы Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,, "ТекущаяСтраница");
            СкопироватьСобытия(Копия, Источник);
        ИначеЕсли Источник.Вид = ВидГруппыФормы.Страница Тогда
            ЗаполнитьЗначенияСвойств(Копия, Источник,, "ПутьКДаннымЗаголовка");      
        ИначеЕсли Источник.Вид = ВидГруппыФормы.ГруппаКолонок Тогда          
            ЗаполнитьЗначенияСвойств(Копия, Источник,, "ПутьКДаннымШапки");            
        Иначе
            ЗаполнитьЗначенияСвойств(Копия, Источник);
        КонецЕсли; 
    КонецЕсли; 
КонецПроцедуры // СкопироватьГруппуФормыБезЭлементов()
// *********************************************************************************************** 
// Сервисная процедура
// ***********************************************************************************************
Процедура ЗаполнитьКоллекциюСвойств(КолекцияКопия, КолекцияИсточник) 
    Для Каждого Элемент Из КолекцияИсточник Цикл
        ЗаполнитьЗначенияСвойств(КолекцияКопия.Добавить(), Элемент);
    КонецЦикла;  
КонецПроцедуры // ЗаполнитьКоллекциюСвойств()
// ***********************************************************************************************  
// Сервисная процедура
// ***********************************************************************************************
Процедура СкопироватьСобытие(Копия, Источник, ИмяСобытия)
    Действие = Источник.ПолучитьДействие(ИмяСобытия);
    Если Действие <> "" Тогда
        Копия.УстановитьДействие(ИмяСобытия, Действие);
    КонецЕсли; 
КонецПроцедуры // СкопироватьСобытие()
// ***********************************************************************************************
// Сервисная процедура
// ***********************************************************************************************
Процедура СкопироватьСобытия(Копия, Источник)
    СкопироватьСобытие(Копия, Источник, "Приизменении");
    СкопироватьСобытие(Копия, Источник, "НачалоВыбора");
    СкопироватьСобытие(Копия, Источник, "НачалоВыбораИзСписка");
    СкопироватьСобытие(Копия, Источник, "Очистка");
    СкопироватьСобытие(Копия, Источник, "Выбор");
    СкопироватьСобытие(Копия, Источник, "Регулирование");
    СкопироватьСобытие(Копия, Источник, "Открытие");
    СкопироватьСобытие(Копия, Источник, "ОбработкаВыбора");
    СкопироватьСобытие(Копия, Источник, "АвтоПодбор");
    СкопироватьСобытие(Копия, Источник, "ОкончаниеВводаТекста");
    СкопироватьСобытие(Копия, Источник, "ПриОбновленииСоставаПользовательскихНастроекНаСервере");
    СкопироватьСобытие(Копия, Источник, "ПриНачалеРедактирования");
    СкопироватьСобытие(Копия, Источник, "ПередНачаломДобавления");
    СкопироватьСобытие(Копия, Источник, "ПередНачаломизменения");
    СкопироватьСобытие(Копия, Источник, "ПриАктивизацииСтроки");
КонецПроцедуры // СкопироватьСобытия()