/** * Форма поиска * * @version 4.1 * Правила встраивания поисковой формы на HTML-страницу: Для доступа к возможностям поисковой формы на странице надо прописать ссылку для загрузки данного скрипта, вот так: Ссылка для загрузки скрипта может располагаться в любом месте страницы, но ДО вызова конструктора объекта ExatSearchForm. После закрытия тега нужно создать объект ExatSearchForm и вызвать его метод initForm(). Все элементы управления на поисковой форме необязательны, но если в ней встретятся элементы управления с префиксом из имени формы, сконкатенированным с одним из зарезервированных id, то методы объекта ExatSearchForm будут соответствующим образом манипулировать их содержимым. Теоретически на странице может быть несколько поисковых форм, но они должны быть с разными id, и для каждой должен быть создан свой экземпляр объекта ExatSearchForm. Пример:
...
*/ /** Конструктор класса ExatSearchForm. * @access public * @param formId - значение атрибута id тега form, для которого конструируется * объект. Загрузка HTML-текста формы в момент конструирования объекта необязательна. * @param clientId - зашифрованный идентификатор клиентских настроек * @param defaults - необязательный объект, значения по умолчанию для параметров * поиска, которые будут использованы при отсутствии свойств параметра values * метода initForm,либо при сбросе после ошибки. Поддерживаемые свойства: * departureId - код точки отправления. По умолчанию 64(Москва). * tourTypeIds - коды туров через запятую. По умолчанию - все типы туров. * countryId - код страны. По умолчанию 0 (не выбрана). * countryFilter - id групп стран через запятую. * countryIncTrans - значение галочки "только с вкл. перелётом": 0=не зависит от страны, * 1=зависит от страны. По умолчанию 1. * resortIds - коды курортов через запятую. По умолчанию - все курорты. * minDate - дата тура "от" в формате "DD.MM.YYYY". * Пустая строка (не путать с null или undefined) = без ограничений. * minDateOffset - смещение в днях от текущей даты для даты тура "от". * По умолчанию - неделя вперёд от текущей даты. Игнорируется при наличии minDate. * maxDate - дата тура "до" в формате "DD.MM.YYYY". * Пустая строка (не путать с null или undefined) = без ограничений. * maxDateOffset - смещение в днях от текущей даты для даты тура "до". * По умолчанию - две недели вперёд от текущей даты. Игнорируется при наличии maxDate. * minDuration - длительность тура "от" в днях. По умолчанию - 8 дней (неделя). 0=[все] * maxDuration - длительность тура "до" в днях. По умолчанию - 8 дней (неделя). 0=[все] * minNightsDuration - длительность тура "от" в ночях. По умолчанию - 7 ночей (неделя). 0=[все] * maxNightsDuration - длительность тура "до" в ночях. По умолчанию - 7 ночей (неделя). 0=[все] * categoryIds - коды категорий отелей через запятую. По умолчанию - все категории. * hotelIds - коды отелей через запятую. По умолчанию - все отели (ограничены только категориями). * minAmount - цена "от" в валюте currencyId. * maxAmount - цена "до" в валюте currencyId. * currencyId - код валюты. По умолчанию - доллары, если для страны нет своей валюты по умолчанию. * foodTypeIds - коды типов питания через запятую. По умолчанию - все типы питания. * serviceIds - коды услуг через запятую. По умолчанию - все услуги. * accommodation - размещение в виде строки ВЗР_РЕБ * show123Acc - 0 или 1: отображать ли размещение 1/2/3 взрослых * в списке доступных размещений, если есть DBL. По умолчанию 1. * ages - возраста детей через запятую * transportRequired - 0 или 1: искать ли только туры с включённым перелётом. * По умолчанию 1, но зависит от countryIncTrans * resortFilter - 0 или 1, поиск маршрутов только по выбранным курортам/странам, и ни по каким другим. * resultType - 'tours' или 'hotels': в каком виде будут представлены результаты поиска -- в виде списка туров или списка отелей. * дополнительные поля, только для профессиональной версии: * tourOperatorIds - коды туроператоров через запятую. По умолчанию - все "предпочтительные" туроператоры. * includeStop - 0 или 1: показывать ли остановленные продажи. По умолчанию 0. * limit - количество строк в странице результатов. По умолчанию 20. * showTourCount - битовая маска, управляющая показом числа туров в опциях списков выбора (1 -- отправление, 2 -- страна, 4 -- курорт, 8 -- отель). По умолчанию 0. * resortDepth - глубина отображения дерева курортов (1 -- показывать только подкурорты страны первого уровня, напр. Болгария / Банско) * @param host - необязательный параметр, указывающий имя HTTP-хоста, с которого будут подгружаться данные. * По умолчанию равен "http://exat.ru" * @param params - необязательный параметр (ассоциативный массив). * params[newWindowParams] - свойства нового окна (2-ой аргумент метода window.open) * По умолчанию равен "resizable=yes, scrollbars=yes" * params[alertLocks] - блокировка уведомлений об ошибках */ var allCountryText; function ExatSearchForm(formId, clientId, defaults, host, params) { this.clientId = clientId; this.formId = formId; this.host = (typeof(host)=='undefined') ? "http://exat.ru" : host; this.params = (typeof(params)=='undefined') ? { newWindowParams : 'resizable=yes, scrollbars=yes' } : params; window.exatForms[formId] = this; // константы this.ONE_HOUR_MS = 1000 * 3600; //количество миллисекунд в часе this.ONE_DAY_MS = 1000 * 3600 * 24; //количество миллисекунд в сутках this.DEF_HOURS = 4; this.MAX_TOUR_DAYS = 22; // максимальное количество дней для генерации из суточных цен //специальные константы для случаев, когда ничего не выбрано this.ALL_TOUR_TYPES = 0xffffffff; this.ALL_CATEGORIES = 0xffffffff; this.ALL_FOOD_TYPES = 0xffffffff; this.ALL_ACCOMMODATIONS = 0xffffffff; this.MAX_AMOUNT = 999999999; this.ACC_TEXT = new Array( '1 / 2 / 3 взр', '1 взр', '2 взр', '3 взр', '4 взр', '5 взр', '6 взр', '7 взр', '8 взр', '9 взр', '10 взр', '11 взр', '12 взр','13 взр', '14 взр', '15 взр', '16 и более взр', '1 взр + 1 реб', '1 взр + 2 реб', '1 взр + 3 реб', '1 взр + 4 и более детей', '2 взр + 1 реб', '2 взр + 2 реб', '2 взр + 3 реб', '2 взр + 4 и более детей', '3 взр + 1 реб', '3 взр + 2 реб', '3 взр + 3 реб', '3 взр + 4 и более детей', '4 и более взр + 1 реб', '4 и более взр + 2 реб', '4 и более взр + 3 реб', '4 и более взр + 4 и более детей' ); this.ACC_VAL = new Array(0, '1_0', '2_0', '3_0', '4_0', '5_0', '6_0', '7_0', '8_0', '9_0','10_0','11_0','12_0','13_0','14_0','15_0','16_0', '1_1', '1_2', '1_3', '1_4', '2_1', '2_2', '2_3', '2_4', '3_1', '3_2', '3_3', '3_4', '4_1', '4_2', '4_3', '4_4'); this.CAT_TEXT = new Array('[все]', '5*', '4*', '3*', '2*', '1*', 'HV-1', 'HV-2', 'без кат.'); this.CAT_VAL = new Array(this.ALL_CATEGORIES, '5', '4', '3', '2', '1', '17', '16', '0'); this.CAT_NEW_VAL = new Array(this.ALL_CATEGORIES, '11,10', '9,8', '7,6', '5,4', '3,2', '17', '16', '0'); this.departureData = null; //ассоциативный массив: код точки отправления=>Array(название,маска доступных типов туров, Array(код страны, ...)) this.tourTypeData = null; //ассоциативный массив: код типа тура=>название типа тура this.countryData = null; //ассоциативный массив: код страны=>Array(название страны, маска типов туров) this.foodTypeData = null; //ассоциативный массив: код типа питания=>название типа питания this.currencyData = null; //ассоциативный массив: код валюты=>название валюты this.servicesData = null; //ассоциативный массив: код услуги=>Array() this.tourOperatorData = null; //ассоциативный массив: код туроператора=>название туроператора this.resortData = []; //ассоциативный массив: 'x'+код точки отправления+'-'+код страны => Array() /* Идентификаторы элементов управления внутри формы, * которыми умеет манипулировать ExatSearchForm * Предполагается, что на странице перед каждым идентификатором * будет префикс в виде идентификатора формы * * Элементы управления профессиональной версии (отображение стопов, технической информации, * переключатель старого/нового вида результатов поиска) здесь не отражены, * для них обработчики надо прописывать явно */ this.controls = [ {name:'DepartureCtrl', onchange:1}, {name:'TourTypeCtrl', onchange:1}, {name:'CountryCtrl', onchange:1}, {name:'CountryFilterCtrl', onchange:1}, {name:'ResortCtrl', onchange:1}, {name:'MinDateCtrl', onchange:1}, {name:'MaxDateCtrl', onchange:1}, {name:'MinDurationCtrl', onchange:1}, {name:'MaxDurationCtrl', onchange:1}, {name:'MinNightsDurationCtrl', onchange:1}, {name:'MaxNightsDurationCtrl', onchange:1}, {name:'MinAmountCtrl', onchange:1}, {name:'MaxAmountCtrl', onchange:1}, {name:'CurrencyCtrl', onchange:1}, {name:'CategoryCtrl', onchange:1}, {name:'HotelCtrl', onchange:1}, {name:'FoodTypeCtrl', onchange:1}, {name:'AccommodationCtrl', onchange:1}, {name:'AgeCtrl', onchange:1}, {name:'ServiceCtrl', onchange:1}, {name:'TourOperatorCtrl', onchange:1}, {name:'TransportRequiredCtrl', onclick:1}, {name:'ResortFilterCtrl', onchange:1}, {name:'LimitCtrl', onchange:1}, {name:'ResultTypeCtrl', onchange:1}, {name:'SubmitCtrl', onclick:1}, {name:'ResetCtrl', onclick:1} ]; this.initTimeout = 0; //сброс таймера начальной инициализации для initForm this.resortException = false; //специальный случай комбинации страна/тип тура/точка отправления, по которой нет туров this.nextNewWindowName = this.generateNewWindowName(); //заранее определяем имя нового окна для тестирования this.prefTourOperators = ''; //список предпочтительных туроператоров, действующий, когда выбран пункт "все" //предусмотрим вариант отсутствия аргумента values совсем this.defaults = (typeof(defaults)=='undefined' || defaults==null) ? {} : defaults; var htmlDefaults=window[this.formId + 'Defaults']; if(htmlDefaults) this.defaults=htmlDefaults; this.defaults.minDate = '23.02.2012'; this.defaults.maxDate = '01.03.2012'; if(this.defaults.countryId==null) this.defaults.countryId = 0; if(this.defaults.minNightsDuration==null) this.defaults.minNightsDuration = 7; if(this.defaults.maxNightsDuration==null) this.defaults.maxNightsDuration = 14; if(this.defaults.minDuration==null) this.defaults.minDuration = 0; if(this.defaults.maxDuration==null) this.defaults.maxDuration = 0; if(this.defaults.departureId==null) this.defaults.departureId = 64;/* Москва */ if(this.defaults.countryFilter==null) this.defaults.countryFilter = 0; if(this.defaults.countryIncTrans==null) this.defaults.countryIncTrans = 1; if(this.defaults.minDateOffset==null) this.defaults.minDateOffset = 7; if(this.defaults.maxDateOffset==null) this.defaults.maxDateOffset = 21; if(this.defaults.minAmount==null) this.defaults.minAmount = 0; if(this.defaults.maxAmount==null) this.defaults.maxAmount = this.MAX_AMOUNT; if(this.defaults.currencyId==null) this.defaults.currencyId = 'undefined'; if(this.defaults.show123Acc==null) this.defaults.show123Acc = 1; if(this.defaults.transportRequired==null) this.defaults.transportRequired = 1; if(this.defaults.resortFilter==null) this.defaults.resortFilter = 0; if(this.defaults.accommodation==null) this.defaults.accommodation = 0; if(this.defaults.includeStop==null) this.defaults.includeStop = 0; if(this.defaults.showTechInfo==null) this.defaults.showTechInfo = 0; if(this.defaults.showTourOperator==null) this.defaults.showTourOperator = 0; if(this.defaults.limit==null) this.defaults.limit = 20; if(this.defaults.showTourCount==null) this.defaults.showTourCount = 0; if(this.defaults.resortDepth==null) this.defaults.resortDepth = 1; if(this.defaults.resultType==null) this.defaults.resultType = 'tours'; //загрузка дополнительных скриптов в конце конструктора инициализации, иначе Opera выполняет сначала эти подгруженные скрипты, а потом уже остальную часть конструктора this.AutoRefreshTimeout = 720000; //Период автоматической перезагрузки данных формы во избежание устаревания this.loadPrefData(); this.loadInitData(); } ExatSearchForm.prototype.loadPrefData = function() { if(typeof(exatPrefData) == 'undefined') { exatPrefData = []; } //если динамические настройки предпочтения ещё не загружены для предыдущей формы, загружаем if(typeof(exatPrefData[this.clientId]=='undefined')) { document.write(''); } } ExatSearchForm.prototype.loadInitData = function() { // Последний выполненный запрос будет автоматически повторяться, чтобы данные не устаревали if (this.LoadResortTimeout != null) { clearTimeout(this.LoadResortTimeout); } if (this.LoadInitTimeout != null) { clearTimeout(this.LoadInitTimeout); } this.LoadInitTimeout = setTimeout('exatForms.' + this.formId + '.loadInitData()', this.AutoRefreshTimeout); //загрузим начальные общие справочники this.loadScript(this.host + '/touronline/?jsapp=getjs&ver=4&file=data&form_id=' + this.formId + '&showTourCount=' + this.defaults.showTourCount + (this.clientId ? '&client_id=' + this.clientId : '')); } ExatSearchForm.prototype.getInitVal = function(name) { if(this.values!=undefined && this.values[name]!=null) { return this.values[name]; } else { return this.defaults[name]; } } ExatSearchForm.prototype.getInitArr = function(name) { var strIds=''; if(this.values!=undefined && this.values[name]!=null) { if(this.values[name]=="") return []; else strIds=this.values[name]; } else if(this.defaults!=undefined && this.defaults[name]!=null) { if(this.defaults[name]=="") return []; else strIds=this.defaults[name]; } else { return []; } strIds=String(strIds); strIds=strIds.replace(/^,/,''); return strIds.split(","); } ExatSearchForm.prototype.array2hash = function(arraydata){ var hashdata=new Array(); for(var i=0; i= 150) { throw new Error('Не удалось инициализировать поисковую форму в течении 30 сек.' + ' Причина: ' + reason + '. Попробуйте перезагрузить страницу (удерживая клавишу Ctrl, нажмите F5).' + ' В случае повторного появления ошибки ' + 'обратитесь в службу технической поддержки'); return; } else { this.initTimeout++; setTimeout('window.exatForms[\''+this.formId+'\'].initForm()', 200); return; } } this.form = document.getElementById(this.formId); if(!this.form) { this.reportError('Форма с id="'+this.formId+'" не найдена'); return; } // запрет сабмита по нажатие Enter в текстовом поле формы, так как в этом случае не запускается обработчик this.form.onsubmit=function(){return false;}; this.departureId = this.getInitVal('departureId'); this.countryId = this.getInitVal('countryId'); this.resortIds = []; var ids = this.getInitArr('resortIds'); for(var i=0; i0) ? this.minAmount : ''; } ctrl = this.form.elements[this.formId + 'MaxAmountCtrl']; if(ctrl) { ctrl.value = (this.maxAmount < this.MAX_AMOUNT && this.maxAmount>0) ? this.maxAmount : ''; } //установка обработчиков событий for (var i = 0; i < this.controls.length; i++) { var c = this.form.elements[this.formId + this.controls[i].name]; if(c) { if(!c.onchange && this.controls[i].onchange) { c.onchange = new Function( "window.exatForms['" + this.formId + "'].on" + this.controls[i].name + "Change" + "()"); } if(!c.onclick && this.controls[i].onclick) { c.onclick = new Function( "window.exatForms['" + this.formId + "'].on" + this.controls[i].name + "Click" + "()"); } } } this.enableControls(); this.resortException = false; if(typeof(this.values)!='undefined') { delete this.values; } this.initTimeout = 0; if(this.form.elements[this.formId + 'IncludeStopCtrl']){ var checkIncludeStop=this.form.elements[this.formId + 'IncludeStopCtrl']; checkIncludeStop.checked=this.includeStop; } if(this.form.elements[this.formId + 'ShowTechInfoCtrl']){ var checkShowTechInfo=this.form.elements[this.formId + 'ShowTechInfoCtrl']; checkShowTechInfo.checked=this.showTechInfo; } if(this.form.elements[this.formId + 'ShowTourOperatorCtrl']){ var checkShowTourOperator=this.form.elements[this.formId + 'ShowTourOperatorCtrl']; checkShowTourOperator.checked=this.showTourOperator || this.showTechInfo; checkShowTourOperator.disabled=this.showTechInfo; } this.formInitAutoAppend(); } ExatSearchForm.prototype.formInitAutoAppend = function(){ } ExatSearchForm.prototype.test = function(){ //D EBUG BEGIN var res = []; obj=this.hotelIds; for (var prop in obj) { //return; if (obj.hasOwnProperty(prop)) { if (useValues=0 && (typeof(obj[prop]) != 'boolean') && (obj[prop] == Number(obj[prop]))){ res.push(obj[prop]); } else if (prop == Number(prop)) { res.push(prop); } } } var rrr=res.join(','); alert(rrr); //D EBUG END } /** * Зависимость пункта отправления "Без перелета" и чекбокса "Без перелета" **/ /** * селект -> чекбокс **/ ExatSearchForm.prototype.Departure2TransportReq=function(){ this.transportRequired = this.departureId!=1 var c = this.form.elements[this.formId+'TransportRequiredCtrl']; if(c) { exatSetCheckedValue(c, this.transportRequired); } } /** * чекбокс -> селект **/ ExatSearchForm.prototype.TransportReq2Departure=function(){ var transportReq=this.form.elements[this.formId +'TransportRequiredCtrl'].checked; //смена в селекте места отправления if(transportReq){// выбрать прежний город if(!this.departurePrevId)// если последний город не известен this.departurePrevId=this.defaults.departureId;// то установить дефолтный this.departureId=this.departurePrevId;// установить предыдущий город текущим }else{// выбрать "без перелета" this.departurePrevId=this.departureId;// запомнить последний город this.departureId=1;// установить городом отправления "без перелета" } var c = this.form.elements[this.formId +'DepartureCtrl']; for(var i=0;i 0) { q.push(['transportRequired', 1]); } if(this.resortFilter > 0) { q.push(['selectedPlacesOnly', 1]); } if(this.countryFilter) { if (this.countryFilter instanceof Array) { q.push(['countryFilter', exatJoinNumbers(this.countryFilter, true)]); } else { q.push(['countryFilter', +this.countryFilter]); } } if(this.includeStop > 0) { q.push(['includeStop', 1]); } if(!this.resortIds || !this.resortIds.length) { q.push(['placeGroupId[]', this.countryId ]); q.push(['placeItemId[]', this.countryId ]); } else { var resortStr = exatJoinNumbers(this.resortIds, /*isArray=*/ false); if(resortStr.length) { q.push(['placeGroupId[]', resortStr ]); q.push(['placeItemId[]', resortStr ]); } else { q.push(['placeGroupId[]', this.countryId ]); q.push(['placeItemId[]', this.countryId ]); } } if(this.tourTypeMask!=this.ALL_TOUR_TYPES) { var a = ''; for(var i=0; i<31; ++i) { if(this.tourTypeMask & (1< 0) { q.push(['minDate', exatFromTime(this.minTimestamp)]); } if(this.maxTimestamp > 0) { q.push(['maxDate', exatFromTime(this.maxTimestamp)]); } if(this.minDuration > 0) { q.push(['minDuration', this.minDuration]); } if(this.maxDuration > 0) { q.push(['maxDuration', this.maxDuration]); } if(this.minNightsDuration > 0) { q.push(['minNightsDuration', this.minNightsDuration]); } if(this.maxNightsDuration > 0) { q.push(['maxNightsDuration', this.maxNightsDuration]); } if(this.minAmount > 0) { q.push(['minAmount', this.minAmount]); } if(this.maxAmount!=this.MAX_AMOUNT) { q.push(['maxAmount', this.maxAmount]); } if(this.accommodationId > 0) { q.push(['accommodation', this.ACC_VAL[this.accommodationId]]); } if(this.ages && this.ages.length) { q.push(['ages[]', this.ages]); } var hotels = exatJoinNumbers(this.hotelIds, /*isArray=*/ false);//у отелей могут быть отрицательные id, поэтому свойство length массива проверять нельзя if(hotels.length) { q.push(['hotelId[]', hotels]); } if(!!this.serviceIds && this.serviceIds.length) { q.push(['serviceId[]', exatJoinNumbers(this.serviceIds, /*isArray=*/ false)]); } if(this.tourOperatorIds && this.tourOperatorIds.length) { var str = exatJoinNumbers(this.tourOperatorIds, /*isArray=*/ false); if(str.length) { q.push(['tourOperatorId[]', str]); } } else { if(this.prefTourOperators.length > 0) { q.push(['tourOperatorId[]', this.prefTourOperators]); } } if (this.resultType != 'tours') { q.push(['resultType', this.resultType]); } return q; } /** Сконвертировать объект с параметрами запроса в строку суффикса * @access public * @param sdata объект с параметрами для конвертации в строку запроса, * полученный, например, через getSubmitData * @return URL suffix to append to search query */ ExatSearchForm.prototype.getSubmitSuffix = function(sdata) { var result = ''; for(var i=0; i< sdata.length; ++i) { result += '&' + sdata[i][0] + '=' + sdata[i][1]; } return result; } /** Получить стандартный префикс для action * @access public * @return строка префикса */ ExatSearchForm.prototype.getSubmitPrefix = function() { return '/tour_search1.php'; } /** Отправить поисковый запрос * @access public * @param openNewWindow - если true, то будет открыто новое окно * @param customAction - если не пуст, то запрос будет отправлен на указнный action url */ ExatSearchForm.prototype.submitForm = function(openNewWindow, customAction) { if (!this.checkParameters()) { return false; } var holder=window.document.location.protocol+'//'+window.document.location.hostname+'/'; this.form.action = this.getSubmitPrefix() ; if(openNewWindow) { var wnd = window.open('', this.nextNewWindowName, this.params['newWindowParams']); wnd.document.write('Пожалуйста, подождите. Идет поиск туров...'); wnd.focus(); this.form.method='post'; this.form.target = this.nextNewWindowName; this.nextNewWindowName = this.generateNewWindowName(); } this.form.submit(); } ExatSearchForm.prototype.onSubmitCtrlClick = function() { this.submitForm(0); } ExatSearchForm.prototype.onResetCtrlClick = function() { this.initForm(); } ExatSearchForm.prototype.resetForm = function() { this.initForm(); } ExatSearchForm.prototype.generateNewWindowName = function() { return 'result_' + exatGenRandomStr(10); } /** * Динамическая загрузка скрипта */ ExatSearchForm.prototype.loadScript = function(url) { var s = document.createElement('script'); s.src = url; s.language = 'javascript'; try { s.charset = 'Windows-1251'; } catch (e) {} // Dirty fix for an occasional IE7 bug document.body.insertBefore(s, document.body.firstChild); } /** Динамическая асинхронная загрузка данных курортов и др. после выбора страны. * @access protected, но предназначена для вызова только из скриптов системы "Ехать!" */ ExatSearchForm.prototype.asyncLoadResort = function() { // Последний выполненный запрос будет автоматически повторяться, чтобы данные не устаревали if (this.LoadResortTimeout != null) { clearTimeout(this.LoadResortTimeout); } if (this.LoadInitTimeout != null) { clearTimeout(this.LoadInitTimeout); } this.LoadResortTimeout = setTimeout('exatForms.' + this.formId + '.asyncLoadResort()', this.AutoRefreshTimeout); this.loadScript(this.host + '/touronline/?jsapp=getjs&ver=4&file=data-' + this.departureId + '-' + this.countryId + '&form_id=' + this.formId + '&showTourCount=' + this.showTourCount + (this.clientId ? '&client_id=' + this.clientId : '')); } /** Заполнение списка курортов и зависимых от них данных. * @access public, но предназначена для вызова только из скриптов системы "Ехать!" */ ExatSearchForm.prototype.fillResort = function() { this.initResortCtrl(); this.initLCDCtrl(); this.initCategoryCtrl(); this.initFoodTypeCtrl(); this.initAccommodationCtrl(); this.initHotelCtrl(); this.initTourOperatorCtrl(); this.enableControls(); } /** Заполнение данных, привязанных к текущим выбранным точке отправления и стране * @access public, но для вызова только из скриптов "Ехать!" * @param departureId - код точки отправления * @param countryId - код страны * @param propName - имя свойства, куда вписать массив данных * @param propVal - данные */ ExatSearchForm.prototype.setResortParam = function(departureId, countryId, propName, propVal) { var id = 'x' + departureId + '-' + countryId; if (!this.resortData[id]) { this.resortData[id] = []; } this.resortData[id][propName] = propVal; } /** Получить данные свойства, учитывая выбранную точку отправления и страну * @access protected * @param propName имя свойства * @return null, если не выбрана страна или данные ещё не загружены, иначе - * значение свойства с именем propName */ ExatSearchForm.prototype.getResortData = function(propName) { if (!this.countryId) { return null; } var id = 'x' + this.departureId + '-' + this.countryId; if (!this.resortData[id]) { this.asyncLoadResort();//отдадим команду на загрузку данных return null;//но не будем дожидаться загрузки } return this.resortData[id][propName]; } /** Возвратить строку символов с объёдинёнными битами дат/длительностей по курортам * В каждом символе используется только шесть бит * @param indx 0=даты, 1=длительности * @return строка с символами с установленными битами */ ExatSearchForm.prototype.getString6 = function(indx) { var r = this.getResortData('lcd'); if(r==null) { reportWarning("Не выбрана страна или не загружены данные курортов"); return ''; } var res = ''; var allResorts = true; //выбраны [все] курорты for(var resortId in this.resortIds) { if(resortId != Number(resortId)) continue; allResorts = false; break; } for(resortId in r) { if(resortId != Number(resortId)) continue; if(allResorts || this.resortIds[resortId]) { var str = r[resortId][indx]; if (str.length < res.length) { // Если строка с упакованными датами короче текущего значения res, дополним ее пустышками var padLength = res.length - str.length; var padString = ""; for (var i = 0; i < padLength; i++) { padString += '?'; } str += padString; } var len = str.length; if(res=='') { for (var i = 0; i < len; i++) { res += '?'; } } var buffer = ''; for (var j = 0; j < len; j++) { buffer += String.fromCharCode(((str.charCodeAt(j) - 63) | (res.charCodeAt(j) - 63)) + 63); } res = buffer; } } return res; } /** Заполнить список значений single select "точка отправления" и выбрать одно * в соответствии с this.departureId * @access protected */ ExatSearchForm.prototype.initDepartureCtrl = function() { var c = this.form.elements[this.formId +'DepartureCtrl']; if (!c || c.nodeName != 'SELECT') { return 1; } exatClearCtrl(c); var arr = this.departureData; var f = false; for (var i in arr) { if(i!=Number(i)) continue; //пропустим нечисловые свойства var o = exatCreateOptionElement(i, arr[i][0]); if (i == this.departureId) { f = true; o.setAttribute('selected', 'selected'); } if (i == 1) { // выделение "без перелета" o.style.fontWeight = "bold"; } c.appendChild(o); } if (!f){ //не нашли, выбираем первую попавшуюся точку отправления if(c.firstChild) { c.firstChild.setAttribute('selected', 'selected'); this.departureId = c.firstChild.value; } else { this.departureId = 0; this.reportError("Нет доступных точек отправления"); } } this.Departure2TransportReq(); } /** Заполнить список значений single/multi select "типы туров" * и выбрать одно или несколько значений в соответствии с this.tourTypeMask * @access protected */ ExatSearchForm.prototype.initTourTypeCtrl = function() { var c = this.form.elements[this.formId + 'TourTypeCtrl']; if(!c) { return 1; } exatClearCtrl(c); //битовая маска доступных типов туров в текущей точке отправления var availableTourTypes = this.departureData[this.departureId][1]; var firstElement = exatCreateOptionElement(0, '[все]'); if(this.tourTypeMask == this.ALL_TOUR_TYPES) { firstElement.setAttribute('selected', true); } c.appendChild(firstElement); var allSelected = true; //в tourTypeId установлен всегда только один бит for(var tourTypeId in this.tourTypeData) { if (tourTypeId!=Number(tourTypeId) || !(tourTypeId & availableTourTypes)) { continue; } var o = exatCreateOptionElement(tourTypeId, this.tourTypeData[tourTypeId]); if (!(tourTypeId & this.tourTypeMask)) { this.tourTypeMask &= ~tourTypeId; allSelected = false; } c.appendChild(o); } var selectTourType=false; if(allSelected) { exatSelectChild(firstElement); selectTourType=true; } else { for (var opt = c.firstChild.nextSibling; opt; opt = opt.nextSibling) { if(this.tourTypeMask & opt.value) { exatSelectChild(opt); selectTourType=true; } } } if(!selectTourType){ exatSelectChild(firstElement); } } /** Заполнить список значений для select "группа стран" * @access protected */ ExatSearchForm.prototype.initCountryFilterCtrl = function() { var c = this.form.elements[this.formId + 'CountryFilterCtrl']; if(!c || !this.countryGroups) { return; } exatClearCtrl(c); c.appendChild(exatCreateOptionElement(0, '[все]')); var countryIds = this.departureData[this.departureId][2]; for (var i = 0; i < this.countryGroups.length; i++) { var groupIsPopulated = false; for (var j = 0; j < countryIds.length; j++) { var countryId = countryIds[j]; if (typeof(this.countryData[countryId]) != 'undefined' && this.countryData[countryId][1] & this.tourTypeMask ) { if (this.countryData[countryId][2]) { for (var gi = 0; gi < this.countryData[countryId][2].length; gi++) { if (this.countryData[countryId][2][gi] == this.countryGroups[i][0]) { groupIsPopulated = true; break; } } } } } if (!groupIsPopulated) { continue; } c.appendChild(exatCreateOptionElement(this.countryGroups[i]['0'], this.countryGroups[i]['1'])); } if (!!this.countryFilter) { var val = this.countryFilter; if (!(this.countryFilter instanceof Array)) { val = [+this.countryFilter]; } for (var i = 0; i < c.options.length; i++) { for (var j = 0; j < val.length; j++) { if (c.options[i].value == val[j]) { c.options[i].selected = true; } } } } } /** Заполнить список значений для single select "страна" и выбрать одно значение * в соответствии с this.countryId * @access protected */ ExatSearchForm.prototype.initCountryCtrl = function() { var c = this.form.elements[this.formId + 'CountryCtrl']; if(!c) { return; } exatClearCtrl(c); var f = false; var availableCountryIds = this.departureData[this.departureId][2]; c.appendChild(exatCreateOptionElement(0, allCountryText?allCountryText:'выберите страну')); for (var i = 0; i 0 && this.countryIncTrans > 0 && typeof(exatPrefData[this.clientId].prefIncludeCheckbox) != 'undefined' && typeof(exatPrefData[this.clientId].prefIncludeCheckbox[this.countryId]) != 'undefined') { this.transportRequired = exatPrefData[this.clientId].prefIncludeCheckbox[this.countryId] ? 1 : 0; } else { this.transportRequired = this.defaults.transportRequired; } var c = this.form.elements[this.formId+'TransportRequiredCtrl']; if(c) { exatSetCheckedValue(c, this.transportRequired); } } /** Заполнить список значений single/multi select "курорты" и выбрать одно * или несколько значений в соответствии с массивом this.resortIds * @access protected */ ExatSearchForm.prototype.initResortCtrl = function() { var c = this.form.elements[this.formId+'ResortCtrl']; var isSelected=false; if(!c) { return 1; } exatClearCtrl(c); if(!Number(this.countryId)) { return 0; } this.foodTypeRange = this.ALL_FOOD_TYPES; this.categoryRange = this.ALL_CATEGORIES; this.accommodationRange = this.ALL_ACCOMMODATIONS; var resortData = this.getResortData('resorts'); if (!resortData) { return 0; } var firstElement = exatCreateOptionElement(this.countryId, '[все]'); c.appendChild(firstElement); var filled = false; for (var resortId in resortData) { if (resortId!=Number(resortId) || !(resortData[resortId][1] & this.tourTypeMask)){ continue; } if (resortData[resortId][4] && resortData[resortId][4].length) { filled = true; if (resortData[resortId][4].length > ((this.resortDepth + 1) * 7)) { continue; // отображать курорт не нужно, задана меньшая глубина дерева } if (resortData[resortId][4].length <= 7) { continue; // отображать курорт не нужно, это корневой курорт (страна) } } filled = true; var opt = exatCreateOptionElement(resortId, resortData[resortId][0]); if(this.resortIds[resortId]) { opt.setAttribute('selected', 'selected'); isSelected=true; this.resortIds[resortId] = 2; } var optt = c.appendChild(opt); if (resortData[resortId][0].charAt(0) != String.fromCharCode(160)) { optt.style.fontWeight = "bold"; //optt.style.color = "blue"; } } //удалим из resortIds невыбранные курорты for(resortId in this.resortIds) { if(resortId == Number(resortId) && this.resortIds[resortId] != 2) { delete this.resortIds[resortId]; } } this.resortException = false; if (!filled) { this.resortException = true; return -1; } if(!isSelected) firstElement.setAttribute('selected', true); return 0; } /** Установить значение checkbox "туры только в выбранные курорты" * в соответствии с this.resortFilter * @access protected */ ExatSearchForm.prototype.initResortFilterCtrl = function() { var c = this.form.elements[this.formId+'ResortFilterCtrl']; if(!c) { return 1; } if (c && c.nodeName == 'INPUT' && c.getAttribute('type') == 'checkbox') { c.checked = this.resortFilter; } } /** Заполнить список значений single select'ов "дата от"/"до", * длительность от"/"до" и выбрать значения в соответствии * с this.minTimestamp, this.maxTimestamp, this.minDuration, this.maxDuration, * а также this.transportRequired * @access protected */ ExatSearchForm.prototype.initLCDCtrl = function() { var oCl, oCh; var cl, ch; var ddstr; var symb; var tmpDate; var val, name; var d0 = this.getResortData('date'); if(d0==null) { //данные не подгружены (возможно, туров нет в этой связке точка отправления/страна) return; } var dNow = new Date(); // Даты d0.setHours(this.DEF_HOURS); d0.setMinutes(0); d0.setSeconds(0); d0.setMilliseconds(0); dNow.setHours(this.DEF_HOURS); dNow.setMinutes(0); dNow.setSeconds(0); dNow.setMilliseconds(0); var zeroTime = d0.getTime(); var nowTime = dNow.getTime(); cnl = this.form.elements[this.formId + 'MinNightsDateCtrl']; cnh = this.form.elements[this.formId + 'MaxNightsDateCtrl']; cl = this.form.elements[this.formId + 'MinDateCtrl']; ch = this.form.elements[this.formId + 'MaxDateCtrl']; if(cnl) { exatClearCtrl(cnl); oCl = exatCreateOptionElement(0, '[все]'); cnl.appendChild(oCl); } if (cnh) { exatClearCtrl(cnh); oCh = exatCreateOptionElement(0, '[все]'); cnh.appendChild(oCh); } if(cl) { exatClearCtrl(cl); oCl = exatCreateOptionElement(0, '[все]'); cl.appendChild(oCl); } if (ch) { exatClearCtrl(ch); oCh = exatCreateOptionElement(0, '[все]'); ch.appendChild(oCh); } var loSel = null; var hiSel = null; var lonSel = null; var hinSel = null; ddstr = this.getString6(0); for (j = 0; j < ddstr.length; j++) { symb = ddstr.charCodeAt(j) - 63; if (symb) { for (var l = 1; l < 7; l++) { if (Math.pow(2, l - 1) & symb) { tmpTime = zeroTime + this.ONE_DAY_MS * (j * 6 + l); val = tmpTime; name = exatGetNiceDate(tmpTime); if(cnl) { oCnl = cnl.appendChild(exatCreateOptionElement(val, name)); if(this.minTimestamp > 0 && tmpTime <= this.minTimestamp ) { //пытаемся выбрать предыдущую дату "от", если нет - то ближайшую более раннюю lonSel = oCnl; } } if(cnh) { oCnh = cnh.appendChild(exatCreateOptionElement(val, name)); if(this.maxTimestamp > 0 && !hinSel && tmpTime >= this.maxTimestamp) { //пытаемся выбрать предыдущую дату "до", если нет - то ближайшую более позднюю hinSel = oCnh; } } if(cl) { oCl = cl.appendChild(exatCreateOptionElement(val, name)); if(this.minTimestamp > 0 && tmpTime <= this.minTimestamp ) { //пытаемся выбрать предыдущую дату "от", если нет - то ближайшую более раннюю loSel = oCl; } } if(ch) { oCh = ch.appendChild(exatCreateOptionElement(val, name)); if(this.maxTimestamp > 0 && !hiSel && tmpTime >= this.maxTimestamp) { //пытаемся выбрать предыдущую дату "до", если нет - то ближайшую более позднюю hiSel = oCh; } } } } } } if(cnl) { lonSel = lonSel ? lonSel : cnl.firstChild; this.minTimestamp = lonSel.value; exatSelectChild(lonSel); } if(cnh) { hinSel = hinSel ? hinSel : cnh.firstChild; this.maxTimestamp = hinSel.value; exatSelectChild(hinSel ? hinSel : cnh.firstChild); } if(cl) { loSel = loSel ? loSel : cl.firstChild; this.minTimestamp = loSel.value; exatSelectChild(loSel); } if(ch) { hiSel = hiSel ? hiSel : ch.firstChild; this.maxTimestamp = hiSel.value; exatSelectChild(hiSel ? hiSel : ch.firstChild); } // Продолжительности cnl = this.form.elements[this.formId + 'MinNightsDurationCtrl']; cnh = this.form.elements[this.formId + 'MaxNightsDurationCtrl']; cl = this.form.elements[this.formId + 'MinDurationCtrl']; ch = this.form.elements[this.formId + 'MaxDurationCtrl']; if(cnl) { exatClearCtrl(cnl); oCnl = exatCreateOptionElement(0, '[все]'); cnl.appendChild(oCnl); } if (cnh) { exatClearCtrl(cnh); oCnh = exatCreateOptionElement(0, '[все]'); cnh.appendChild(oCnh); } if(cl) { exatClearCtrl(cl); oCl = exatCreateOptionElement(0, '[все]'); cl.appendChild(oCl); } if (ch) { exatClearCtrl(ch); oCh = exatCreateOptionElement(0, '[все]'); ch.appendChild(oCh); } ddstr = this.getString6(1); lonSel = null; hinSel = null; loSel = null; hiSel = null; if (this.transportRequired || ((ddstr.charCodeAt(0) - 63) & 0x03) == 0) { //если "только с перелётом" или нет туров на 1/2 дня (т.е. суточных) for (var j = 0; j < ddstr.length; j++) { symb = ddstr.charCodeAt(j) - 63; if (symb) { //пропустим в for'e туры на 1 день, т.к. это признак "суток", //а "сутки" у нас сейчас автоматически складываются for (var m = 1 + (j?0:1); m < 7; m++) { if ( (1 << (m - 1)) & symb) { val = (j * 6 + m); name = val; nightsname=name-1; if(cnl) { oCnl = exatCreateOptionElement(val, nightsname); if(this.minNightsDuration > 0 && val <= this.minNightsDuration) { lonSel = oCnl; } cnl.appendChild(oCnl); } if(cnh) { oCnh = exatCreateOptionElement(val, nightsname); if(this.maxNightsDuration > 0 && !hinSel && val >= this.maxNightsDuration) { hinSel = oCnh; } cnh.appendChild(oCnh); } if(cl) { oCl = exatCreateOptionElement(val, name); if(this.minDuration > 0 && val <= this.minDuration) { loSel = oCl; } cl.appendChild(oCl); } if(ch) { oCh = exatCreateOptionElement(val, name); if(this.maxDuration > 0 && !hiSel && val >= this.maxDuration) { hiSel = oCh; } ch.appendChild(oCh); } } } } } } else { for(var j = 2; j <= this.MAX_TOUR_DAYS; j++) { val=j; name=j; nightsname=name-1; if(cnl) { oCnl = exatCreateOptionElement(val, nightsname); if (this.minNightsDuration > 0 && j <= this.minNightsDuration) { lonSel = oCnl; } cnl.appendChild(oCnl); } if(cnh) { oCnh = exatCreateOptionElement(val, nightsname); if (this.maxNightsDuration > 0 && !hinSel && j >= this.maxNightsDuration) { hinSel = oCnh; } cnh.appendChild(oCnh); } if(cl) { oCl = exatCreateOptionElement(val, name); if (this.minDuration > 0 && j <= this.minDuration) { loSel = oCl; } cl.appendChild(oCl); } if(ch) { oCh = exatCreateOptionElement(val, name); if (this.maxDuration > 0 && !hiSel && j >= this.maxDuration) { hiSel = oCh; } ch.appendChild(oCh); } } } if(cnl) { lonSel = lonSel ? lonSel : cnl.firstChild; this.minDuration = this.minNightsDuration = lonSel.value; exatSelectChild(lonSel); } if(cnh) { hinSel = hinSel ? hinSel : cnh.firstChild; this.maxDuration = this.maxNightsDuration = hinSel.value; exatSelectChild(hinSel ? hinSel : cnh.firstChild); } if(cl) { loSel = loSel ? loSel : cl.firstChild; this.minNightsDuration = this.minDuration = parseInt(loSel.value); exatSelectChild(loSel); } if(ch) { hiSel = hiSel ? hiSel : ch.firstChild; this.maxNightsDuration = this.maxDuration = parseInt(hiSel.value); exatSelectChild(hiSel ? hiSel : ch.firstChild); } return true; } /** Заполнить список значений single/multi select "категория отеля", * в соответствии с this.categoryIds * @access protected */ ExatSearchForm.prototype.initCategoryCtrl = function() { var c = this.form.elements[this.formId + 'CategoryCtrl']; if(!c) { return; } exatClearCtrl(c); firstElement = exatCreateOptionElement(this.CAT_VAL[0], this.CAT_TEXT[0]); if(this.categoryMask==this.ALL_CATEGORIES || this.categoryMask==0) { exatSelectChild(firstElement); } c.appendChild(firstElement); var mask = 0; for (var i = 1; i < this.CAT_TEXT.length; i++) { var element = exatCreateOptionElement(this.CAT_NEW_VAL[i], this.CAT_TEXT[i]); var vals = this.CAT_NEW_VAL[i].split(","); for(var j=0; j =0) { if(this.accommodationHandSelectedId==i+1) { o.setAttribute("selected","selected"); newId = i+1; } } else { if(this.accommodationId==i+1) { o.setAttribute("selected","selected"); newId = i+1; } } c.appendChild(o); } } if (newId!=null) { this.accommodationId = newId; } else { if(firstId != null) { this.accommodationId = firstId; } else { this.accommodationId = 0; } } } /** Заполнить список значений single/multi select "отель", * в соответствии с this.hotelIds и доступными отелями * @access protected */ ExatSearchForm.prototype.initHotelCtrl = function() { var c = this.form.elements[this.formId+'HotelCtrl']; if(!c) { return; } exatClearCtrl(c); var availableHotels = this.getResortData('hotels'); if (!availableHotels) { return; } var f = false; //признак уже встретившейся фортуны var hotelSelected = false; //был ли выбран хотя бы один отель var tm = this.tourTypeMask; var fm = this.foodTypeMask & this.foodTypeRange; var am = this.accommodationRange; var cm = (this.categoryMask == this.ALL_CATEGORIES) ? 0xffffffff : this.categoryMask; firstElement = exatCreateOptionElement('', '[все]'); c.appendChild(firstElement); var allResortsSelected = true; for(var resortId in this.resortIds) { if(resortId != Number(resortId)) continue; allResortsSelected = false; break; } var strHotelIds=","+this.hotelIds.join(",")+","; for (var i =0; i < availableHotels.length; ++i) { var item = availableHotels[i]; if (!((1 << item[2]) & cm)) { continue; } if (!(item[3] & tm) || !(item[4] & fm) || !(item[5] & am)) { continue; } // если выбран конкретный курорт или курорты, проверить, находится ли отель в нем или в одном из его подкурортов if (!allResortsSelected && !this.resortIds[item[6]]) { var availableResorts = this.getResortData('resorts'); var hotelPlace = item[6]; if (availableResorts[hotelPlace] && availableResorts[hotelPlace][4]) { var hotelPlacePath = new String(availableResorts[hotelPlace][4].toString()); } else { // курорт, где размещен отель, не найден или не имеет placePath (некорректные данные с сервера) continue; } // перебираем все выбранные курорты; если путь к отелю включает путь к выбранному курорту в позиции 0, то отель считается принадлежащим курорту и не пропускается var skipThisHotel = true; for(var resortId in this.resortIds) { if(resortId != Number(resortId)) continue; if (availableResorts[resortId] && availableResorts[resortId][4]) { var currResortPlacePath = availableResorts[resortId][4]; if (hotelPlacePath.indexOf(currResortPlacePath) == 0) { skipThisHotel = false; continue; } } } if (skipThisHotel == true) { continue; } } var val = item[0]; if (isNaN(val)) {//фортуна if (!f) { f = true; val = 0; o = exatCreateOptionElement(val, "[фортуна]"); } else { continue; } } else { o = exatCreateOptionElement(val, item[1]); } if(strHotelIds.indexOf(","+val+",") !== -1 || this.hotelIds[val]!=undefined && this.hotelIds[val]==2 ){ o.setAttribute("selected", "selected"); hotelSelected = true; this.hotelIds[val] = 2; //to show it's used } c.appendChild(o); } //удалим из hotelIds невыбранные курорты for(hotelId in this.hotelIds) { if(hotelId == Number(hotelId) && this.hotelIds[hotelId] != 2) { delete this.hotelIds[hotelId]; } } if(!hotelSelected) { //ни один отель не был выбран, тогда выбираем пункт "[все]" exatSelectChild(c.firstChild); this.hotelIds=new Array(); } } /** Заполнить список значений single select "валюта", * в соответствии с this.currencyId и предпочтениями * @access protected */ ExatSearchForm.prototype.initCurrencyCtrl = function() { var c = this.form.elements[this.formId + 'CurrencyCtrl']; if(!c) { return; } exatClearCtrl(c); var o; var prefCur; if(this.currencyId) { prefCur = this.currencyId; } if( this.countryId && typeof(exatPrefData[this.clientId].prefCurrency) != 'undefined' && typeof(exatPrefData[this.clientId].prefCurrency[this.countryId]) != 'undefined') { prefCur = exatPrefData[this.clientId].prefCurrency[this.countryId]; } if(typeof(this.defaults.currencyId) != 'undefined' && this.defaults.currencyId>0 ) prefCur = this.defaults.currencyId; for(var currencyId in this.currencyData) { if(currencyId != Number(currencyId)) { continue; } o = exatCreateOptionElement(currencyId, this.currencyData[currencyId]); if(prefCur && prefCur == currencyId) { exatSelectChild(o); } c.appendChild(o); } this.currencyId = Number(c.options[c.selectedIndex].value); } /** Заполнить список значений multi select "услуги", * и выбрать некоторые в соответствии с this.serviceIds * @access protected */ ExatSearchForm.prototype.initServicesCtrl = function() { var c = this.form.elements[this.formId+'ServiceCtrl']; if(!c) { return; } exatClearCtrl(c); var noServicesSelected = true; for(var serviceId in this.serviceIds) { if(serviceId == Number(serviceId)) { noServicesSelected = false; break; } } firstElement = exatCreateOptionElement('', '[все]'); if(noServicesSelected) { firstElement.setAttribute('selected', true); } c.appendChild(firstElement); for (var serviceGroupId in this.servicesData) { if(serviceGroupId != Number(serviceGroupId)) { continue; } var g = exatCreateGroupElement(this.servicesData[serviceGroupId][0]); var sarr = this.servicesData[serviceGroupId][1]; for (var i = 0; i < sarr.length; ++i) { if(typeof(sarr[i])!='object') { continue; } var opt = exatCreateOptionElement(sarr[i][1], sarr[i][0]); if(this.serviceIds[sarr[i][1]]) { opt.setAttribute('selected', true); } g.appendChild(opt); } c.appendChild(g); } } /** Заполнить список значений multi select "туроператоры", * и выбрать некоторых в соответствии с this.tourOperatorIds и с предыдущими значениями контрола "Туроператоры" * @access protected */ ExatSearchForm.prototype.initTourOperatorCtrl = function() { var c = this.form.elements[this.formId + 'TourOperatorCtrl']; if(!c) { return; } var prevTo = new Array(); var allTourOperatorsSelected = true; if(this.tourOperatorDefIds!=-1 && this.tourOperatorDefIds.length>0){ prevTo=this.tourOperatorDefIds; }else{ if (c.firstChild && !c.firstChild.selected && !this.resetTourOperatorEvent) { for(o = c.firstChild.nextSibling; o; o = o.nextSibling) { if(o.selected) { prevTo[o.value] = 2; } else { prevTo[o.value] = 1; } } } for(var toId in this.tourOperatorIds) { if(toId == Number(toId)) { allTourOperatorsSelected = false; prevTo[toId] = 2; } } } exatClearCtrl(c); var selTourOperatorIds=this.tourOperatorIds; this.tourOperatorIds = []; var availableTourOperators = this.getResortData('tourOperators'); if (!availableTourOperators) { return; } var tm = this.tourTypeMask; var fm = this.foodTypeMask & this.foodTypeRange; var am = this.accommodationRange; var usePrefTo = false; var resortToCnt = 0; this.prefTourOperators = ''; if( typeof(exatPrefData[this.clientId].arrPrefTo) != 'undefined' && exatPrefData[this.clientId].arrPrefTo.length > 0) { usePrefTo = true; } var f = 0; //количество выбранных туроператоров var allInPref = true; //все имеющиеся туроператоры - в предпочтениях, поэтому можно this.prefTourOperators сделать пустой var firstElement = exatCreateOptionElement('', '[все]'); if(allTourOperatorsSelected) { firstElement.setAttribute('selected', true); } c.appendChild(firstElement); for (var i = 0; i < availableTourOperators.length; ++i) { var item = availableTourOperators[i]; var toId = item[0]; if (!(item[1] & tm) || !(item[2] & fm) || !(item[3] & am)) { continue; } resortToCnt++; if (usePrefTo && !exatPrefData[this.clientId].arrPrefTo[toId]){ allInPref = false; continue; } this.prefTourOperators += (this.prefTourOperators.length > 0 ) ? (','+ toId) : toId; element = exatCreateOptionElement(toId, this.tourOperatorData[toId]); if(prevTo.length > 0 && (prevTo[toId] == 2 || !prevTo[toId] && this.tourOperatorDefIds==-1)) { //выбираем всех вновь появившихся туроператоров и тех, кто был выбран на пред. этапе exatSelectChild(element); this.tourOperatorIds[toId] = true; f++; } c.appendChild(element); } if(allInPref) { this.prefTourOperators = ''; } if (c.length == 1) { // есть только пункт [все], а самих ТО ни одного c.removeChild(c.firstChild); } else if (f > 0 && f < (c.length - 1)) { // есть выделенные ТО, поэтому снимается выделение с пункта [все] exatUnselectChild(c.firstChild); } else if (f > 0 && f == (c.length - 1)) { // все ТО выделены, поэтому с них снимается выделение и выделяется пункт [все] var o; for(o = c.firstChild.nextSibling; o; o = o.nextSibling) { exatUnselectChild(o); delete this.tourOperatorIds[o.value]; } exatSelectChild(c.firstChild); } this.tourOperatorDefIds=-1; } /** Заполнить список значений single select "размер страницы" * и выбрать пункт, соответствующий this.limit * @access protected */ ExatSearchForm.prototype.initLimitCtrl = function() { var c = this.form.elements[this.formId + 'LimitCtrl']; if(!c) { return; } exatClearCtrl(c); var limits = [20,100,500,1000]; for(var i=0; i maxCtrl.value)) { maxCtrl.value = minCtrl.value; this.maxTimestamp = this.minTimestamp; } } ExatSearchForm.prototype.onMaxDateCtrlChange = function() { if(!this.form) { return; } var minCtrl = this.form.elements[this.formId + 'MinDateCtrl']; var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl']; if(maxCtrl) { this.maxTimestamp = maxCtrl.value; } if (minCtrl && maxCtrl && maxCtrl.value != 0 && minCtrl.value > maxCtrl.value) { minCtrl.value = maxCtrl.value; this.minTimestamp = this.maxTimestamp; } } ExatSearchForm.prototype.onMinNightsDurationCtrlChange = function() { if(!this.form) { return; } var minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl']; if(! minCtrl) minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl']; var maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl']; if(!maxCtrl) maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl']; if(!minCtrl) { return; } this.minDuration = this.minNightsDuration = minCtrl.value; if(maxCtrl && (minCtrl.value == 0 || parseInt(minCtrl.value) > parseInt(maxCtrl.value))) { this.maxDuration = maxCtrl.value = this.maxNightsDuration = this.minNightsDuration; } } ExatSearchForm.prototype.onMinDurationCtrlChange = function() { if(!this.form) { return; } var minCtrl = this.form.elements[this.formId + 'MinDurationCtrl']; if(! minCtrl) minCtrl = this.form.elements[this.formId + 'MinDurationCtrl']; var maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl']; if(!maxCtrl) maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl']; if(!minCtrl) { return; } this.minNightsDuration = this.minDuration = minCtrl.value; if(maxCtrl && (minCtrl.value == 0 || parseInt(minCtrl.value) > parseInt(maxCtrl.value))) { this.maxNightsDuration = maxCtrl.value = this.maxDuration = this.minDuration; } } ExatSearchForm.prototype.onMaxNightsDurationCtrlChange = function() { if(!this.form) { return; } var minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl']; var maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl']; if(!maxCtrl) { return; } this.maxDuration = this.maxNightsDuration = maxCtrl.value; if (minCtrl && maxCtrl.value!=0 && parseInt(minCtrl.value) > parseInt(maxCtrl.value)) { this.minDuration = minCtrl.value = this.minNightsDuration = this.maxNightsDuration; } } ExatSearchForm.prototype.onMaxDurationCtrlChange = function() { if(!this.form) { return; } var minCtrl = this.form.elements[this.formId + 'MinDurationCtrl']; var maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl']; if(!maxCtrl) { return; } this.maxNightsDuration = this.maxDuration = maxCtrl.value; if (minCtrl && maxCtrl.value!=0 && parseInt(minCtrl.value) > parseInt(maxCtrl.value)) { this.minNightsDuration = minCtrl.value = this.minDuration = this.maxDuration; } } ExatSearchForm.prototype.onMinAmountCtrlChange = function() { if(!this.form) { return; } var ctrl = this.form.elements[this.formId + 'MinAmountCtrl']; this.minAmount = ctrl.value; } ExatSearchForm.prototype.onMaxAmountCtrlChange = function() { if(!this.form) { return; } var ctrl = this.form.elements[this.formId + 'MaxAmountCtrl']; this.maxAmount = ctrl.value; } ExatSearchForm.prototype.onCurrencyCtrlChange = function() { if(!this.form) { return; } var ctrl = this.form.elements[this.formId + 'CurrencyCtrl']; this.currencyId = ctrl.value; } ExatSearchForm.prototype.onServiceCtrlChange = function() { if(!this.form) { return; } var ctrl = this.form.elements[this.formId+'ServiceCtrl']; if(!ctrl) { throw new Error("Can't find element with id="+this.formId + "ServiceCtrl"); return; } if(!ctrl.options.length) { return; } var opt = ctrl.options[0]; this.serviceIds = []; if((opt.value=='' || opt.value==0)) { if(opt.selected) { //спец. значение "[все]" return; } } for (var i=1; i Number(this.maxTimestamp)) { alert('Начальная дата больше конечной'); return false; } if (Number(this.maxNightsDuration) && Number(this.minNightsDuration) > Number(this.maxNightsDuration)) { alert('Задан некорректный диапазон количества ночей'); return false; } if (Number(this.maxDuration) && Number(this.minDuration) > Number(this.maxDuration)) { alert('Задан некорректный диапазон количества дней'); return false; } c = this.form.elements[this.formId+'TourOperatorCtrl']; if (c && c.length == 0) { var s = 'Список туроператоров пуст. Это означает, что среди туроператоров, обслуживающих маршрут, нет' + ' ни одного из предпочитаемых Вами. Попробуйте настроить список предпочтительных туроператоров' + ' при помощи ссылки "настроить список" над списком туроператоров или изменить маршрут.'; alert(s); return false; } c = this.form.elements[this.formId+'AgeCtrl']; if (c && c.value.length > 0) { var ageS = c.value; var ageL = ageS.length; var ageN = 1; var age1 = ''; var age2 = ''; var sep = 0; for (var i = 0; i < ageL; i++) { var ch = ageS.charAt(i); if (ch >= '0' && ch <= '9') { if (sep && age1.length > 0) { ageN++; age1 += ','; age2 = ''; sep = 0; } age1 += ch; age2 += ch; if (age2 > 25) { alert('Возраст ребенка должен быть до 25 лет включительно.'); c.focus(); return false; } } else { sep = 1; } } this.ages = age1; var chnum = this.getChildren(); if(chnum > 0 && ageN > chnum) { alert('Введено больше возрастов, чем выбрано детей.\nУдалите лишние возрасты.'); c.focus(); return false; } } return true; } /** Поиск по коду тура * @access public */ ExatSearchForm.prototype.searchTpid = function(val, newWindow) { if (val.length) { var url = '/touronline/tpid_search.php?tpid=' + val; var st = this.form.elements[this.formId + "ShowTechInfoCtrl"]; var so = this.form.elements[this.formId + "ShowTourOperatorCtrl"]; if (st && st.checked) { url += '&show_tech_info=1'; } if (so && so.checked) { url += '&show_operator=1'; } exatShowWindow(url, 700, 500); } else { alert('Укажите код тура'); } } /** показать сообщение о предупреждении (нефатальной ошибке), если оно не пустое * @access protected */ ExatSearchForm.prototype.reportWarning = function(msg) { if(this.params.alertLocks) return; if (msg != '') { this.showMessage('Предупреждение : ' + msg); } else { this.showMessage('Неизвестная ошибка'); } } /** показать сообщение о фатальной ошибке, если оно не пустое * @access protected */ ExatSearchForm.prototype.reportError = function(msg) { if(this.params.alertLocks) return; if (msg != '') { this.showMessage('Фатальная ошибка : ' + msg); } else { this.showMessage('Неизвестная фатальная ошибка'); } } /** показать сообщение, если оно не пустое * @access protected */ ExatSearchForm.prototype.showMessage = function(msg) { if(msg) { alert(msg); return true; } else { return false; } } ExatSearchForm.prototype.getChildren = function() { var children = new Array(0,0); var accom = this.ACC_VAL[this.accommodationId]; if (accom != Number(accom)) children = accom.split('_'); return Number(children[1]); } /* глобальные утилитарные функции */ function exatGenRandomStr(strlen) { str = ''; for (i = 0; i < strlen; i++) { str += String.fromCharCode(Math.random()*25 + 97); } return str; } function exatShowWindow(url, width, height) { size = ''; if(width && height) { size = ',width=' + width + ',height=' + height; } var strInitParam='directories=no,status=yes,scrollbars=yes,resizable=yes,menubar=no,toolbar=no'; exat_wndname = exatGenRandomStr(10); var description = window.open('', exat_wndname, strInitParam+size); description.document.write('Пожалуйста, подождите. Идет загрузка...'); if (url) { description.document.location=url; } description.focus(); return description; } // возвращена функция с оригинальным названием для совместимости // by Eduard Pakaln function w(url, width, height) { return exatShowWindow(url, width, height); } function exatGetNiceDate(dateObj) { dateObj = new Date(dateObj); var daysOfWeek = new Array('вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'); var months = new Array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'); var day = dateObj.getDate(); return daysOfWeek[dateObj.getDay()] + ' ' + (day < 10 ? '0' : '') + day.toString() + ' ' + months[dateObj.getMonth()]; } /** Упаковка-распаковка строк */ function str2code(str_in) { var tmp=""; var i; var tmp_c=""; str_in=str_in.toString(); for(i = 0; i < str_in.length; i++) { tmp_c = str_in.charCodeAt(i) - 23; tmp += ''+(tmp_c<10 ? '0'+tmp_c : tmp_c); } var substr_len=14, out="", len_bit_tmp=0; while(tmp!=''){ len_bit_tmp=tmp.length 31) || (d[1] > 12) || (d[2].length !== 4)) { return null; } res = new Date(d[2], d[1] - 1, d[0]) return res.getTime(); } /** Преобразование значения 'DD.MM.YYYY' элемента управления ctrl * в кол-во миллисекунд с 1 января 1970 года */ function exatCheckDate(ctrl) { if (ctrl && ctrl.value.length) { var res = exatToTime(ctrl.value); if (res==null) { ctrl.focus(); return false; } else { return res; } } return 0; } /** * Получение значения элемента типа select. Если установлено свойство multiple и выбраны несколько элементов списка, возвращается массив значений * * @access global * @param element * @return mixed */ function exatGetSelectValue(el) { if (!el.nodeName || el.nodeName != 'SELECT') { return; } if (!el.multiple) { return el.value; } var result = []; for (var i = 0; i < el.options.length; i++) { if (!!el.options[i].selected) { result.push(el.options[i].value); } } if (!result.length) { return; } if (result.length == 1) { return result[0]; } return result; } /** * Получение значения установлено/сброшено объекта. Объект может быть input(checkbox, hidden, text) * Сделано на случай когда на сайте некоторые компоненты делают скрытыми * * @access global * @param obj * @return bool or null on error */ function exatGetCheckedValue(obj) { var checkedValue; if(obj.nodeName == 'INPUT'){ switch (obj.type) { case 'text': case 'hidden': checkedValue = obj.value; break; case 'checkbox': checkedValue = obj.checked; break; default: checkedValue = null; } } else { checkedValue = null; } return checkedValue; } /** * Установка значения установлено/сброшено объекта. Объект может быть input(checkbox, hidden, text) * Сделано на случай когда на сайте некоторые компоненты делают скрытыми * * @access global * @param obj * @param value * @return bool */ function exatSetCheckedValue(obj, value) { if (!obj) return; else if (obj.nodeName == 'INPUT') { switch (obj.type) { case 'text': case 'hidden': obj.value = value; ret = true; break; case 'checkbox': obj.checked = value ? true : false; ret = true; break; default: ret = false; } } else { ret = false; } return ret; } /** * Возвращает числовые имена свойств или значения свойств объекта в виде строки через запятую * * @param useValues если false, то возвращает имена свойств, иначе, если это массив, то значения */ function exatJoinNumbers(obj, useValues) { var res = []; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { if (useValues && (typeof(obj[prop]) != 'boolean') && (obj[prop] == Number(obj[prop]))){ res.push(obj[prop]); } else if (prop == Number(prop)) { res.push(prop); } } } return res.join(','); } function exatCreateGroupElement(l) { var g = document.createElement('optgroup'); g.setAttribute('label', l); return g; } function exatCreateOptionElement(v, n) { var o = document.createElement('option'); var t = document.createTextNode(n); o.setAttribute('value', v); o.appendChild(t); return o; } function exatClearCtrl(c) { // чтобы очистка поменьше тормозила и визуально не выбирала элементы, // сначала выберем первый элемент, а затем удалим всё с конца if(c && c.firstChild) { if(c.nodeName=='SELECT') { /* FIX for Opera * операция делает выбранные не существующее пустое поле * c.selectedIndex=-1; //чтобы в multiselect сбросить выделение совсем */ } else { c.firstChild.setAttribute('selected', true); } do { c.removeChild(c.lastChild); } while(c.lastChild); } } /** Кроссбраузерный выбор опции в селекте */ function exatSelectChild(chd) { chd.setAttribute('selected', true);//для IE, в FF не работает if(!chd.selected) { chd.selected = true;//работает только в FF, в IE вызывает ошибку } } function exatUnselectChild(chd) { chd.setAttribute('selected', false);//для IE, в FF не работает if(chd.selected) { chd.selected = false;//работает только в FF, в IE вызывает ошибку } } //глобальный реестр поисковых форм на странице. Заполняется конструктором. if(typeof(exatForms)=='undefined') { exatForms = []; } // функция для парсинга параметров GET function getSearchParams(){ var tmp = new Array(); // два вспомагательных var tmp2 = new Array(); // массива var param = new Array(); var get = location.search; // строка GET запроса if(get != '') { tmp = (get.substr(1)).split('&'); // разделяем переменные for(var i=0; i < tmp.length; i++) { tmp2 = tmp[i].split('='); // массив param будет содержать param[tmp2[0]] = tmp2[1]; // пары ключ(имя переменной)->значение } } return param; } // // find browser inner dimensions //var width = 0, height = 0; function getWindowDimensions(){ var width = 0, height = 0; if(window.innerWidth){ width = window.innerWidth; height = window.innerHeight; } else if(document.documentElement && document.documentElement.clientWidth){ width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; } else if(document.body && document.body.clientWidth){ width = document.body.clientWidth; height = document.body.clientHeight; } return {'width':width, 'height':height}; } // find browser inner dimensions End