You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2401 lines
103 KiB

var EXPO = EXPO || {}; //isolated namespace
// module requires JQuery library, dna.js template engine (http://dnajs.org/)
// protection against duplication of a module code
if (EXPO.searchBlock){
console.warn('WARNING: EXPO.searchBlock is already defined!');
}else{
EXPO.searchBlock = (function() {
// variables
var that = {};
/**
* default module setting
* @type {{place: {id: string, selectedItemTemplate: string, ajaxUrl: string}, subject: {id: string, ajaxUrl: string}}}
*/
that.settings = {
place:{
id:'pw-place',
selectedItemTemplate:'csb-selected',
ajaxUrl: window.location.protocol + '//hit.expomap.ru/search-form/'
},
subject:{
id:'pw-subj',
ajaxUrl: window.location.protocol + '//hit.expomap.ru/search-form/'
}
};
that.lang ={};
//dependence's
// module require dna.js tiny templating engine
var common = EXPO.common;
//private
var Json2URI = function (jsonObj) {
var str = Object.keys(jsonObj).map(function(key){
return encodeURIComponent(key) + '=' + encodeURIComponent(jsonObj[key]);
}).join('&');
return ('?'+str);
},
/**
* make ajax GET request and launch handler if exist or return data
* @param {Object|string} dataToSend
* @param {string} url
* @param {function} handler - function to execute when task is ready
*/
getRequest = function (dataToSend,url,handler) {
if(!dataToSend){
dataToSend = '';
}
$.ajax({
type: 'GET',
url: url,
data:dataToSend,
success: function(data) {
if(typeof handler == 'function'){
handler(data);
} else{
return data;
}
}
});
},
/**
* rename name of property of an object/ Check for the old property name to avoid a ReferenceError in strict mode.
* @param {Object} obj object to rename its properties
* @param {string} oldName
* @param {string} newName
* @returns {renameProperty}
*/
renameProperty = function (obj,oldName, newName) {
if (obj.hasOwnProperty(oldName)) {
obj[newName] = obj[oldName];
}
return this;
},
/**
* analogue of Array.length but for object
* @param {Object} obj - Object to count its method
* @returns {number}
*/
getObjectLength = function (obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
},
/**
* getSelectedToString returns string that contains selected values in both modal windows. values separated by ','
* @param {string} container
* @param {number} cutLength - length to cut off string
* @returns {string} string that is cutted off
*/
getSelectedToString = function(container, cutLength){
var $container = $('#'+container),
index = 0,
stringToReturn = '',
closingSymbol = '...',
closerText = EXPO.searchBlock.settings.closerText,
closerTextSingle = EXPO.searchBlock.settings.closerTextSingle,
dividerSymbol = '';
$element = $container.find('.csbs-text');
if($element.length > 2){
if($element.eq(0).text().length < cutLength){
dividerSymbol = ', ';
stringToReturn += $element.eq(0).text() + dividerSymbol + $element.eq(1).text() + closerText.replace('_',$element.length-2);
}else{
stringToReturn += $element.eq(0).text() + closerText.replace('_',$element.length-1);
}
} else if($element.length == 2){
if(($element.eq(0).text().length+$element.eq(1).text().length) < cutLength){
dividerSymbol = ', ';
// если даже 2 первых слова вместе меньше чем порог, то не указывать количество позиций
stringToReturn += $element.eq(0).text() + dividerSymbol + $element.eq(1).text()+' ';
} else if($element.eq(0).text().length < cutLength){
dividerSymbol = ', ';
stringToReturn += $element.eq(0).text() + dividerSymbol + $element.eq(1).text()+' ';
}else{
stringToReturn += $element.eq(0).text() + closerTextSingle.replace('_',$element.length-1);
}
}else if($element.length){
stringToReturn += $element.eq(0).text()+' ';
}else{
stringToReturn = false;
}
return stringToReturn;
},
/**
* ajax pending process indicator
* @type {*|jQuery|HTMLElement} индикатор загрузки диалоговых окон
*/
$waiter = $('.wait-ajax.absolute');
/**
* Constructor for modal window 'select subject'
* @param {Object} options
* @constructor
*/
var SubjectModal = function(options){
/**
* options init
* @type {Object}
*/
this.opt = options;
var self = this, index = 0,
$subjWrap = $('#'+self.opt.subjectTriggerWrapId),
$topicBox,
modalId = self.opt.id,
$modal = $('#'+modalId),
$checkBox = $('.csb-menu-input', $modal),
$selectedItemsWrap = $('.csb-selected-items',$modal),
setDefault = self.opt.defaultOn,
applyBtnClass = self.opt.applyBtnClass,
$modalTrigger = $('#'+self.opt.modalTrigger),
/**
* executed after render of modal Window
* @function
*/
afterRenderHandler = function () {
$waiter.hide();
},
/**
* fill text beneth search field
* @function triggerSetText
*/
triggerSetText = function () {
var selectedString,
cutLength = 16;
if($(window).width() < 1086){
cutLength = 12;
}
selectedString = getSelectedToString(self.opt.selectedItemsContainer,cutLength);
if(selectedString && selectedString != '~~text~~' && selectedString != '~~text~~...'){
$modalTrigger.text(selectedString);
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).addClass('active');
}else{
$modalTrigger.text($modalTrigger.data('default'));
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).removeClass('active');
}
};
/**
* this modal window DOM Instance
* @type {*|jQuery|HTMLElement}
*/
this.$modalInst = $('#'+modalId);
/**
* clones of tags for selected(checked) subject (powered by dna.js objects: see http://dnajs.org/)
* @type {Object}
*/
this.itemsSelected = {};
/**
* clones of sublist of selected(checked) subject (powered by dna.js objects: see http://dnajs.org/)
* @type {Object}
*/
this.sublist= {};
/**
* Jquery object of filtering input (autocomplete input)
* @type {*|jQuery|HTMLElement}
*/
this.$inputFilter = $('#'+self.opt.filterInputId);
this.$selectedItemsWrap = $selectedItemsWrap;
/**
* flag for management of turn of asynchronous requests
* @type {boolean}
*/
this.isReceived = true;
$(function () {
// topic checkbox selected event
$('.topicChecks', $subjWrap).on('change', function () {
if($(this).prop('checked')){
self._setVisible($(this).val());
}else{
self._setUnvisible($(this).val());
}
});
// selected topic by default self.opt.defaultOn[]
for(index = 0; index < setDefault.length; index++){
$topicBox = $('#'+setDefault[index])
$topicBox.prop('checked',true);
$topicBox.trigger('change');
}
//modal list and sublist behavior
$modal.on('click', 'a.trigger', function () {
var name = $(this).attr('data-name'),
id = $(this).attr('data-id'),
tmplId = $(this).attr('data-template-id'),
$sublist = $(this).siblings('.dna-container');
// no more than once execution
if($(this).attr('data-sub') == 'true'){
if($(this).parent().hasClass('level1')){
if(!$sublist.children().length){
$waiter.show();
self._renderSublist({name:name,id:id}, tmplId, afterRenderHandler);
$(this).parent().addClass('active');
}else{
//slideUp & Down stuff
self._slideToggle($sublist, $(this).parent());
}
}
}
return false;
});
/**
*
*/
// modal theme checkbox change behavior
$checkBox.on('change', function (event, param) {
var checkboxId = $(this).attr('id'),
$label = $(this).closest('.custom-radio-check'),
$parent = $(this).closest('.level'),
$parentCheckBox = $parent.parent().closest('.level').children('.custom-radio-check').find('.csb-menu-input'),
$sublist = $parent.children('.sublist');
if(!param){
if(this.checked){
$label.addClass('active');
var text = $(this).closest('.level').find('.trigger').first().text(),
tplObj = {'text':text,'id':checkboxId};
//tags field logic
if(!$selectedItemsWrap.hasClass('visible')){
$selectedItemsWrap.addClass('visible');
}
self._addTag(checkboxId, tplObj);
// proper selection and selection group logic
if($sublist.length){
$('.csb-menu-input',$sublist).each(function () {
var thisId = this.getAttribute('id'),
tagText = $(this).closest('.level').find('.trigger').first().text(),
DOMlabel = common.closest(this,'custom-radio-check');
this.checked = true;
self._destroyTag(thisId);
common.addClass(DOMlabel,'active');
});
}else{
$parent = $parent.parent().closest('.level')
// if checked items count equals all items count then parent item is checked and tags for children - deleted
if ( $('.csb-menu-input',$parent.find('.sublist')).length == $('.csb-menu-input:checked',$parent.find('.sublist')).length){
var parentId = $parentCheckBox[0].getAttribute('id'),
parentText = $parentCheckBox.closest('.level').find('.trigger').first().text(),
DOMlabel =common.closest(this,'custom-radio-check'),
DOMParentLabel = common.closest(DOMlabel.parentNode.parentNode,'level'),
parentObj = {'text':parentText,'id':parentId};
$('.csb-menu-input:checked',$parent.find('.sublist')).each(function () {
self._destroyTag(this.getAttribute('id'));
});
$parentCheckBox.prop('checked', true);
common.addClass($(DOMParentLabel).find('.custom-radio-check')[0],'active');
//$parentCheckBox.trigger('change',['true']);
self._addTag(parentId,parentObj);
}
}
//!uncheck event
}else {
$label.removeClass('active');
self._destroyTag(checkboxId);
if(!$selectedItemsWrap.children('.dna-clone').length){
$selectedItemsWrap.removeClass('visible');
}
//uncheck all sublist items while parent item is unchecked
if($sublist.length){
//destroy all tags for sublist items
$('.csb-menu-input',$sublist).each(function () {
var thisId = $(this).attr('id'),
DOMlabel = common.closest(this,'custom-radio-check');
this.checked = false;
common.removeClass(DOMlabel, 'active');
self._destroyTag(thisId);
});
}else{
// parent item is unchecked and tags for every children item are made
if($parentCheckBox.length && $parentCheckBox[0].checked){
var DOMlabel = common.closest($parentCheckBox[0],'custom-radio-check'),
DOMParentItem = common.closest(DOMlabel,'level'),
DOMSublist = DOMParentItem.querySelector('.sublist');
$parentCheckBox.prop('checked', false);
common.removeClass(DOMlabel, 'active');
self._destroyTag($parentCheckBox.attr('id'));
// checks children items
$('.csb-menu-input:checked',DOMSublist).each(function () {
var id = this.getAttribute('id'),
tagText = common.closest(this, 'level').querySelector('.trigger').textContent,
tagObj = {'text':tagText,'id':id};
self._addTag(id,tagObj);
});
}
}
}
triggerSetText();
}
});
//delete tag behavior
$('.csbs-del', $selectedItemsWrap).on('click', function () {
var checkboxId = $(this).attr('data-checkbox-id'),
$uncheckBoxes = $('#'+checkboxId);
$uncheckBoxes.prop('checked', false);
$uncheckBoxes.trigger('change');
dna.destroy(self.itemsSelected[checkboxId]);
if(!$selectedItemsWrap.children('.dna-clone').length){
$selectedItemsWrap.removeClass('visible');
}
return false;
});
$('.modal-clear', $modal).on('click', function () {
self.resetList();
return false;
});
self._autocompleteInit();
$('.'+applyBtnClass, $modal).on('click', function () {
self.applyHandler(this);
return false;
});
// кнопка "очистить параметры"
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).on('click', function () {
self.resetList();
EXPO.searchBlock.exhibitionField.clearValue();
});
});
};
/**
* methods
* @type {{_getAjax: Function, _setVisible: Function, _setUnvisible: Function, _checkCheckBox: Function, check: Function, _autocompleteInit: Function, _renderSublist: Function, _loadParentTree: Function, _destroyTag: Function, _addTag: Function, _slideToggle: Function, resetList: Function, applyHandler: Function}}
*/
SubjectModal.prototype = {
/**
* get ajax response when want sublists
* @param {Object|sting} dataToSend
* @param {function} handler - fires after request is complete
* @private
*/
_getAjax: function (dataToSend, handler) {
var self = this;
if(!dataToSend){
dataToSend = '';
}
$waiter.css({display:'block'});
$.ajax({
type: 'GET',
url: self.opt.ajaxUrl,
data:dataToSend,
success: function(data) {
if(typeof handler == 'function'){
$waiter.hide();
handler(data);
} else{
return data;
}
}
});
},
/**
* filter list accordingly to checked checkbox in 'select type' part of modal
* @param {string} type
* @private
*/
_setVisible:function(type){
var self = this;
$('.'+type, self.$modalInst).addClass('visible');
},
/**
* filter list accordingly to checked checkbox in 'select type' part of modal
* @param {string} type
* @private
*/
_setUnvisible: function (type) {
var self = this,
$li = $('.'+type, self.$modalInst);
$li.find('input[type="checkbox"]').each(function () {
var $this = $(this);
if($this.prop('checked')){
$this.prop('checked', false);
$this.trigger('change');
}
});
$li.find('.dna-container').each(function () {
if($(this).children().length){
$(this).addClass('hidden');
}
});
$li.removeClass('visible');
},
/**
* check particular checkbox input
* @param {string} id
* @param {string} name
* @param {boolean} strict - if true then select particular checkbox without 'popping' to parent category
* @private
*/
_checkCheckBox: function (id,name) {
var self = this,
$chckBox;
if(name == 'th'){
$chckBox = $('#tid_'+id, self.$modalInst);
}else if(name == 'tg'){
$chckBox = $('#tgid_'+id, self.$modalInst);
}
if($chckBox.length && !$chckBox.prop('checked')){
$chckBox.prop('checked',true);
$chckBox.trigger('change');
}
},
/**
* check particular checkbox input
* @param {string} id
* @param {string} name
* @public
*/
check: function (id,name) {
var self = this,
$chckBox;
if(name == 'th'){
$chckBox = $('#tid_'+id, self.$modalInst);
}else if(name == 'tg'){
$chckBox = $('#tgid_'+id, self.$modalInst);
}
if($chckBox.length){
$chckBox.prop('checked',true);
$chckBox.trigger('change');
$chckBox.parent().addClass('active');
}
},
/**
* initiliazing and setup autocomplete field for subject list
* @private
*/
_autocompleteInit : function () {
var self = this, dataObj, text , form = self.$inputFilter.attr('data-form'),index,
$completeWrap = $('#'+self.opt.autoCompleteId),
firstComplete = true,
selectTag = function (event, ui) {
//check of repeating execution
$waiter.show();
var firstTime = true;
for (var prop in self.sublist) {
for (var prop2 in self.sublist[prop]) {
if (prop2 == ui.item.value){
if($('#tid_'+ui.item.value+'[name="'+ui.item.name+'"]:checked').length){
firstTime = false;
}
}
}
}
if($('#tid_'+ui.item.value+'[name="'+ui.item.name+'"]:checked').length){
firstTime = false;
}
// ban of repeating execution
if (firstTime) { // konec
var $checkbox = $('#tid_' + ui.item.value+'[name="'+ui.item.name+'"]'),
requestObj, requestName,
treeLoadHandler = function (data) {
// make checkboxes selected after loading
if(getObjectLength(data)){
self._loadParentTree(data, function () {
self._checkCheckBox(ui.item.value,'tg');
$waiter.hide();
});
}else{
$waiter.hide();
console.warn()
}
};
// load tree related to selected item
if (!$checkbox.length) {
requestObj = {
id: ui.item.value,
name: ui.item.name
};
getRequest(requestObj, self.opt.getParentUrl, treeLoadHandler);
} else{
$waiter.hide();
$checkbox.prop('checked', true);
$checkbox.trigger('change');
}
}
},
requestHandler = function(data){
dataObj = data;
for(index = 0; index < dataObj.length; ++index) {
renameProperty(dataObj[index],'text','label');
}
for(index = 0; index < dataObj.length; ++index) {
renameProperty(dataObj[index],'id','value');
}
if(!self.$inputFilter.hasClass('ui-autocomplete-input')){
self.$inputFilter.placeComplete({
source:dataObj,
minLength: 0,
appendTo:$completeWrap,
select:function(event, ui){
self.$inputFilter.val('');
self.$inputFilter.trigger('keyup');
selectTag(event, ui);
event.preventDefault();
// return ui.label;
}
});
self.$inputFilter.placeComplete('search',"");
firstComplete = false;
}else{
self.$inputFilter.placeComplete('search',"");
}
};
/**
* the ID value of the timer that is set
*/
self.timeout;
self.$inputFilter.attr('autocomplete', 'on');
self.$inputFilter.on('keyup', function (event) {
text = $(this).val();
event.stopImmediatePropagation();
clearTimeout(self.timeout);
if (text.length > 2 && firstComplete){
self.timeout = setTimeout(function () {
getRequest({'term':text, 'form':form}, self.opt.autoCompleteUrl, requestHandler);
firstComplete = false;
}, 1000);
}else if(text.length == 0 && !firstComplete){
if(self.$inputFilter.hasClass('ui-autocomplete-input')){
self.$inputFilter.placeComplete( "destroy" );
firstComplete = true;
}
}
return false;
}).click(function () {
return false;
});
},
/**
* render first level sublist
* @param {Object} dataObj
* @param {number|string} tmplId
* @param {function} handler
* @private
*/
_renderSublist: function (dataObj, tmplId, handler) {
var self = this,
index = 0,
template = tmplId + '-sub',
ajaxHandler = function (data) {
if(data.length){
self.sublist[template] = {};
// for dna.clone definition see dnajs.org
for (index ; index < data.length; index++) {
self.sublist[template][data[index].id] = dna.clone(tmplId, data[index]);
}
handler(data.length);
}else{
$waiter.hide();
}
};
self._getAjax(dataObj, ajaxHandler);
},
/**
* if there is no children element in list, loads ITS Children sublist
* @param {Object} data - current (children) object data
* @param {number|string} handler
* @param {function} counter
* @private
*/
_loadParentTree: function (data, handler, counter) {
var self = this,
dataObj = data,
optObj, sublistTemplateId, nestedObj,nestedSublistTemplateId,
/**
* makes request in order to recieve children list information fires after request for parent list
* @param {number} length
* @function
*/
handlerParent = function (){
$waiter.hide();
counter||counter===0?handler(counter):handler();
};
$waiter.show();
optObj = {
name:dataObj.name,
id:dataObj.id
};
sublistTemplateId = $('#tid_'+dataObj.id).closest('.level').children('.trigger').attr('data-template-id');
self._renderSublist(optObj,sublistTemplateId,handlerParent);
},
/**
* destroy tag and clear tags block.for dna.clone definition see dnajs.org
* @param {string} checkboxId
* @private
*/
_destroyTag:function(checkboxId){
var self = this;
if(self.itemsSelected[checkboxId]){
dna.destroy(self.itemsSelected[checkboxId]);
}
},
/**
* for dna.clone definition see dnajs.org
* @param {number} checkboxId
* @param {Object} tplObj
* @private
*/
_addTag: function (checkboxId, tplObj) {
var self = this;
self.itemsSelected[checkboxId] = dna.clone(self.opt.selectedItemTemplate,tplObj);
},
/**
* hide or show sublists according active selected link
* @param {*|jQuery|HTMLElement} $sublist
* @param {*|jQuery|HTMLElement} $this
* @private
*/
_slideToggle:function ($sublist, $this){
if($sublist.hasClass('hidden')){
$sublist.removeClass('hidden');
$this.addClass('active');
}else{
$sublist.addClass('hidden').find('ul').addClass('hidden');
$this.removeClass('active');
}
},
/**
* reset all selected items, uncheck all selected checkboxes
* @public
*/
resetList: function () {
var self = this;
for (var key in self.itemsSelected) {
if (self.itemsSelected.hasOwnProperty(key)) {
$('#'+key, self.$selfContainer).prop('checked', false).trigger('change');
dna.destroy(self.itemsSelected[key]);
}
}
$('.level.active',self.$modalInst).removeClass('active');
self.$selectedItemsWrap.removeClass('visible');
$(this.$modalInst).find('input:checkbox:checked').prop('checked',false);
},
// кнопка применить
applyHandler: function (it) {
$waiter.show();
},
/**
* select particular item and render its tag and check checkbox
* @param {Object} item
* @public
*/
selectTag:function (item) {
//check of repeating execution
var firstTime = true,
self = this,
waitHandler = function () {
self.isReceived = false;
if(!item.children){
for (var prop in self.itemsSelected) {
if (prop == 'tid_'+item.id){
firstTime = false;
}
}
if($('#tid_'+item.id+':checked').length){
firstTime = false;
}
if(firstTime){
self.check(item.id, item.name);
self.isReceived = true;
}else{
$('#tid_' + item.id).prop('checked', true);
$('#tid_' + item.id).trigger('change');
self.isReceived = true;
}
}else{
if($('#tgid_'+item.children.id).length){
firstTime = false;
}
//Если выбран родитель
if($('#tid_'+item.id+':checked').length){
firstTime = false;
}
if(firstTime) {
self._loadParentTree({name: item.name, id: item.id}, function () {
self.check(item.children.id, item.children.name);
self.isReceived = true;
});
}else if(!$('#tgid_'+item.id+':checked').length){
$('#tgid_' + item.children.id).prop('checked', true);
$('#tgid_' + item.children.id).trigger('change');
self.isReceived = true;
}
}
};
this.wait(waitHandler);
},
/**
* waits so far the previous request will be executed and execute a method
* @param {function} method
* @param {Object|Array} args
* @public
*/
wait:function(method, args) {
var self = this,
waitImages,
waitHandler = function(self, method, args) {
if (self.isReceived) {
if (args) {
method(args);
}
else{
method();
}
clearInterval(waitImages);
}
};
waitImages = setInterval(function() {waitHandler(self, method, args)}, 100);
}
};
/**
* Constructor for modal window 'select place'
* @param {Object} options
* @constructor
*/
var PlacesModal = function(options){
/**
* object properties
* @type {Object}
*/
this.opt = options;
var self = this,
$modal = $('#'+self.opt.id),
$checkBox = $('input[type="checkbox"]', $modal),
$selectedItemsWrap = $('.csb-selected-items',$modal),
DOMTagsWrapper = $('.csb-selected-items',$modal)[0],
$modalTrigger = $('#'+self.opt.modalTrigger),
applyBtnClass = self.opt.applyBtnClass,
idPrefix = 'id_',
/**
* set trigger link text under the search field
* @function
*/
triggerSetText = function () {
var selectedString,
cutLength = 16;
if($(window).width() < 1086){
cutLength = 6;
}
selectedString = getSelectedToString(self.opt.selectedItemsContainer,cutLength);
if(selectedString && selectedString != '~~text~~' && selectedString != '~~text~~...'){
$modalTrigger.text(selectedString);
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).addClass('active');
}else{
$modalTrigger.text($modalTrigger.data('default'));
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).removeClass('active');
}
};
/**
* current template instances
* @type {Object}
*/
this.curDNA = {};
/**
* place modal list items that had selected
* @type {Object}
*/
this.itemsSelected = {};
this.selectedWrap = $selectedItemsWrap;
this.$selfContainer = $modal;
this.$modal = $modal;
this.idPrefix = idPrefix;
/**
* flag for management of turn of asynchronous requests
* @type {boolean}
*/
this.isReceived = true;
/**
* Jquery object of filtering input (autocomplete input)
* @type {*|jQuery|HTMLElement}
*/
this.$inputFilter = $('#'+self.opt.filterInputId);
$(function () {
self._autocompleteInit();
$modal.on('click', 'a.trigger', function () {
var name = $(this).attr('data-name'),
id = $(this).attr('data-id'),
that = this,
tmplId = $(this).attr('data-template-id'),
$sublist = $(this).siblings('.dna-container'),
afterRenderHandler = function (elem, data) {
var DOMParent = common.closest(that,'level'),
DOMParentCheckbox = DOMParent.querySelector('.csb-menu-input');
$('.csb-menu-input', $sublist).each(function () {
var DOMCheckboxWrap = common.closest(this,'custom-radio-check');
if(!this.checked){
if(DOMParentCheckbox.checked){
this.checked = true;
common.addClass(DOMCheckboxWrap,'active');
}
}else{
if(!DOMParentCheckbox.checked){
this.checked = false;
common.removeClass(DOMCheckboxWrap,'active');
}
}
});
$waiter.hide();
};
// no more than once execution
if($(this).attr('data-sub') == 'true'){
if($(this).parent().hasClass('level1')){
if(!$sublist.children().length){
$waiter.show();
self._renderSublist({name:name,id:id}, tmplId, afterRenderHandler);
}else{
//slideUp & Down stuff
self._slideToggle($sublist, $(this).parent());
}
}else if($(this).parent().hasClass('level2')){
if(!$sublist.children().length){
self._renderNested({name:name,id:id}, afterRenderHandler, tmplId, id);
$(this).parent().addClass('active');
}
else{
//slideUp & Down stuff
self._slideToggle($sublist, $(this).parent());
}
}
}
return false;
});
$checkBox.on('change', function (event, param) {
var id = this.getAttribute('id'),
fakeCheckboxClass = 'custom-radio-check',
fakeCheckbox = common.closest(this, fakeCheckboxClass),
itemClass = 'level',
activeClass = 'active',
sublistClass = 'sublist',
checkboxClass = 'csb-menu-input',
highestItemClass = 'level1',
tagClass = 'csb-selected',
tagButtonClass = 'csbs-del',
triggerClass = 'trigger',
tagIdAttribute = 'data-checkbox-id',
DOMParentRow = common.closest(this, itemClass),
DOMParentItem = common.hasClass(DOMParentRow, highestItemClass) == false?common.closest(DOMParentRow.parentNode, itemClass):DOMParentRow,
DOMParentCheckbox = DOMParentItem.querySelector('.'+checkboxClass),
DOMSublist = DOMParentItem.querySelector('.'+sublistClass),
DOMSublistInner = DOMParentRow.querySelector('.'+sublistClass),
DOMHighestItem = common.closest(this, highestItemClass),
DOMHighestCheckbox = DOMHighestItem.querySelector('.'+checkboxClass),
DOMHighestSublist = DOMHighestItem.querySelector('.'+sublistClass),
selectSublist = function (it) {
var DOMParentItem = common.closest(it, itemClass) || this,
DOMSublist = DOMParentItem.querySelector('.'+sublistClass);
$('.'+checkboxClass, DOMSublist).each(function () {
selectItem(this);
});
},
unSelectSublist = function (it) {
var DOMParentItem = common.closest(it, itemClass) || this,
DOMSublist = DOMParentItem.querySelector('.'+sublistClass);
$('.'+checkboxClass, DOMSublist).each(function () {
unSelectItem(this);
});
},
selectParent = function (it) {
var DOMParentRow = common.closest(it, itemClass),
DOMParentItem;
if(common.hasClass(DOMParentRow,'level1')){
DOMParentItem = DOMParentRow;
}else{
DOMParentItem = common.closest(DOMParentRow.parentNode, itemClass);
}
common.addClass(DOMParentItem.querySelector('.'+fakeCheckboxClass), activeClass);
DOMParentItem.querySelector('.'+checkboxClass).checked = true;
//it.selected = true;
},
unSelectParent = function (it) {
var DOMParentRow = common.closest(it, itemClass),
DOMParentItem = common.closest(DOMParentRow.parentNode, itemClass) || DOMParentRow;
common.removeClass(DOMParentItem.querySelector('.'+fakeCheckboxClass), activeClass);
DOMParentItem.querySelector('.'+checkboxClass).checked = false;
//it.checked = false;
},
selectItem = function (it) {
var itFakeCheckbox = common.closest(it, fakeCheckboxClass);
common.addClass(itFakeCheckbox, activeClass);
it.checked = true;
common.addClass(DOMParentItem,activeClass);
common.removeClass(DOMSublist,'hidden');
},
unSelectItem = function (it) {
var itFakeCheckbox = common.closest(it, fakeCheckboxClass),
DOMitem = common.closest(it, itemClass);
common.removeClass(itFakeCheckbox, activeClass);
it.checked = false;
// if there is children items
if(DOMitem.querySelector('.'+sublistClass) && !common.hasClass(DOMitem,highestItemClass)){
unSelectSublist(it);
}
},
allChildrenSelected = function () {
//var DOMselected = DOMSublist.querySelectorAll('.'+checkboxClass+':checked'),
var DOMSublistParent = common.closest(DOMSublist,sublistClass),
$selected = $(DOMSublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass+':checked'),
selectedCount = $selected.length,
//allCount = DOMSublist.querySelectorAll('.'+checkboxClass).length;
allCount = $(DOMSublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass).length;
if(allCount == selectedCount && selectedCount != 0){
return true;
} else{
return false;
}
},
allHighestSelected = function () {
//var DOMselected = DOMSublist.querySelectorAll('.'+checkboxClass+':checked'),
var $selected = $(DOMHighestSublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass+':checked'),
selectedCount = $selected.length,
allCount = $(DOMHighestSublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass).length;
if(allCount == selectedCount && selectedCount != 0){
return true;
} else{
return false;
}
},
parentSelected = function () {
var parentCheckbox = DOMParentItem.querySelector('.'+checkboxClass);
if(parentCheckbox.checked){
return true;
}else{
return false;
}
},
// Функционал добавления тегов: если есть в панели выбранный элемент либо его дочерние то удалить эти эдементы;
refreshTags = function (it) {
var DOMSublist = common.closest(it,sublistClass);
var DOMItem = common.closest(it,itemClass);
var DOMSublistInner = DOMItem.querySelector('.'+sublistClass);
var DOMAllTags = DOMTagsWrapper.querySelectorAll('.'+tagClass);
var ARRsublist;
var ARRsublistChildren = DOMSublist.querySelector('.'+sublistClass)?$('.'+checkboxClass+':checked',DOMSublist.querySelector('.'+sublistClass)):null;
var ARRsublistChildrenLength = ARRsublistChildren?ARRsublistChildren.length:null;
var ARRSublistIds = [];
var ARRAllTagsIds = [];
var allTagsLength = 0;
var sublistIdsLength = 0;
var itId = it.getAttribute('id');
var i = 0, j= 0, t= 0, tmp, k = 0;
var tagId;
var tagText = DOMParentRow.querySelector('.'+triggerClass).innerHTML;
// если есть дочерние элементы
if(DOMSublistInner){
ARRsublist = $(DOMSublistInner).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass+':checked')
//получаем массив id жлементовЮ для которых есть тег
for(k; k < ARRsublist.length; k++){
tmp = ARRsublist[k].getAttribute('id');
ARRSublistIds.push(tmp);
}
//очистк
for(t; t<DOMAllTags.length; t++){
tmp = DOMAllTags[t].querySelector('.'+tagButtonClass).getAttribute(tagIdAttribute);
if(tmp != '~~id~~'){
ARRAllTagsIds.push(tmp);
}
}
allTagsLength = ARRAllTagsIds.length;
sublistIdsLength = ARRSublistIds.length;
//если найден дочерний тег то он будет удален, либо текущий тег
for(i = 0; i < allTagsLength; i++){
tagId = ARRAllTagsIds[i];
for(j = 0; j< sublistIdsLength; j++){
if( tagId == ARRSublistIds[j] ){
deleteTag(ARRsublist[j]);
}
}
}
// удаление дубликатов текущего элемента
for(i = 0; i < allTagsLength; i++){
tagId = ARRAllTagsIds[i];
if( tagId == itId){
deleteTag(it);
}
}
// удаление дочерних тегов 2го уровня
if(DOMSublistInner.querySelectorAll('.final-tire')){
$('.'+fakeCheckboxClass+'.'+activeClass, DOMSublistInner.querySelectorAll('.final-tire')).each(function () {
deleteTag($('.'+checkboxClass,this)[0]);
});
}
}else{
// удаление дубликатов текущего элемента
for(i = 0; i < allTagsLength; i++){
tagId = ARRAllTagsIds[i];
if( tagId == itId){
deleteTag(itId);
}
}
}
},
deleteTag = function (it) {
var id = it.getAttribute('id');
self._destroyTag(id);
tagsPanelToggle();
},
createTag = function (it) {
var item = common.closest(it,itemClass),
tagTrigger = item.querySelector('.'+triggerClass),
tagText = '',
id = it.getAttribute('id'),
tagObj = {};
//setTimeout(function(){
tagText = tagTrigger.innerHTML,
tagObj = {'id':id,'text':tagText}
self._addTag(id, tagObj);
tagsPanelToggle();
//}, 200)
},
tagsPanelToggle = function () {
if($selectedItemsWrap.find('.'+tagButtonClass).length && $selectedItemsWrap.find('.'+tagButtonClass)[0].getAttribute(tagIdAttribute) != "~~id~~"){
$selectedItemsWrap.addClass('visible');
}else{
$selectedItemsWrap.removeClass('visible');
}
},
createTagList = function (sublist) {
var $selected = $(sublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass+':checked');
$selected.each(function () {
createTag(this);
});
},
deleteTagList = function () {
var $selected = $(DOMSublist).children('li').children('.'+fakeCheckboxClass).find('.'+checkboxClass+':checked');
$selected.each(function () {
deleteTag(this);
});
};
//make fake checkbox active\passive
/**
* if modala is not in strict mode ( enable popping from children categories to parent)
*/
if(!self.strictMode){
if(this.checked){
if($(DOMSublistInner).find('.'+checkboxClass)[0]){
if(DOMSublistInner && $(DOMSublistInner).find('.'+checkboxClass)[0].value != '~~id~~'){
refreshTags(this);
}
}
//если выбраны все дочерние
if(allChildrenSelected()){
selectParent(this);
selectItem(this);
refreshTags(DOMParentCheckbox);
createTag(DOMParentCheckbox);
deleteTagList(DOMSublist);
if(DOMParentCheckbox.getAttribute('id')== DOMHighestCheckbox.getAttribute('id') && !DOMHighestCheckbox.checked){
selectItem(DOMHighestCheckbox);
refreshTags(DOMHighestCheckbox);
createTag(DOMHighestCheckbox);
//если только что вклбченный чекбокс дополняет остальные включенные чекбоксы, то включается самый верхний чекбокс
}else if(allHighestSelected()){
selectItem(DOMHighestCheckbox);
refreshTags(DOMHighestCheckbox);
createTag(DOMHighestCheckbox);
}
}else{
selectItem(this);
refreshTags(this);
createTag(this);
}
//выбрать все дочерние
if(DOMSublistInner){
selectSublist(this);
}
}else{
//Если выбран родитель
if(parentSelected()){
unSelectParent(this);
unSelectItem(this);
refreshTags(DOMParentCheckbox);
deleteTag(DOMParentCheckbox);
createTagList(DOMSublist);
if(DOMHighestCheckbox.checked){
unSelectItem(DOMHighestCheckbox);
deleteTag(DOMHighestCheckbox);
createTagList(DOMHighestSublist);
}
}else{
unSelectItem(this);
refreshTags(this);
deleteTag(this);
}
//убрать все дочерние
if(DOMSublistInner){
unSelectSublist(this);
refreshTags(this);
}
}
}else{
if(this.checked){
selectItem(this);
refreshTags(this);
createTag(this);
}else{
unSelectItem(this);
refreshTags(this);
deleteTag(this);
}
}
triggerSetText();
});
/**
* delete tag button behavior
*/
$('.csbs-del', $selectedItemsWrap).on('click', function () {
var checkboxId = $(this).attr('data-checkbox-id'),
$uncheckBoxes = $('#'+checkboxId);
$uncheckBoxes.prop('checked', false);
$uncheckBoxes.trigger('change');
dna.destroy(self.itemsSelected[checkboxId]);
if(!$selectedItemsWrap.children('.dna-clone').length){
$selectedItemsWrap.removeClass('visible');
}
return false;
});
/**
* clear all button behavior
*/
$('.modal-clear',$modal).on('click', function () {
self.resetList();
return false;
});
/**
* sublist behaivor
*/
$('.q-sel a',$modal).on('click', function () {
var $this = $(this),
name = $this.attr('data-name'),
id = $this.attr('data-id'),
ajaxObj = {name:name, id:id},
ajaxHandler = function (data) {
self._loadParentTree(data, function () {
self._checkCheckBox(id);
});
};
//.prop('checked')
if($('#id_'+id).length){
$('#id_'+id).prop('checked',true).trigger('change');
}else{
getRequest(ajaxObj,self.opt.getParentUrl,ajaxHandler);
}
return false;
});
$('.'+applyBtnClass, $modal).on('click', function () {
self.applyHandler(this);
return false;
});
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).on('click', function () {
self.resetList();
EXPO.searchBlock.placesField.clearValue()
});
});
};
/**
* methods for modal window object
* @type {{_getAjax: Function, _renderSublist: Function, _renderNested: Function, _checkCheckBox: Function, selectTag: Function, wait: Function, check: Function, _slideToggle: Function, _destroyTag: Function, _addTag: Function, resetList: Function, _autocompleteInit: Function, _loadParentTree: Function, applyHandler: Function, isSelected: Function}}
*/
PlacesModal.prototype = {
/**
* some kind of wrapper in top of jquery.AJAx
* @param {Object|string} dataToSend
* @param {function} handler
* @private
*/
_getAjax: function (dataToSend, handler) {
var self = this;
if(!dataToSend){
dataToSend = '';
}
$.ajax({
type: 'GET',
url: self.opt.ajaxUrl,
data:dataToSend,
success: function(data) {
if(typeof handler == 'function'){
self.rawData = data;
handler(data);
} else{
self.rawData = data;
return data;
}
}
});
},
/**
* render first level sublist (require dna.js template engine)
* @param {Object} dataObj
* @param {string} tmplId
* @param {function} handler
* @private
*/
_renderSublist: function (dataObj, tmplId, handler) {
var self = this,
index = 0,
template = tmplId + '-sub',
ajaxHandler = function (data) {
if(data.length){
self.curDNA[template] = {};
// for dna.clone definition see dnajs.org
for (index ; index < data.length; index++) {
self.curDNA[template][data[index].id] = dna.clone(tmplId, data[index]);
}
$('.'+tmplId).parents('.level1').addClass('active');
handler(data.length);
}else{
$waiter.hide();
}
};
self._getAjax(dataObj, ajaxHandler);
},
/**
* render second level sublist
* @param {Object} dataObj
* @param {function} handler
* @param {string} template
* @param {number} item
* @private
*/
_renderNested: function (dataObj, handler, template, item) {
var self = this,
tmplId = template.substr(0, template.lastIndexOf("-")),
index = 0,
cities, $parent,
Uri = Json2URI(dataObj),
ajaxHandler = function (data) {
if(data.length){
dna.rest.get(template, (self.opt.ajaxUrl + Uri),{callback: function () {
handler(data.length);
}, container: self.curDNA[template][item]});
}
};
self._getAjax(dataObj, ajaxHandler);
},
/**
* check particular checkbox input
* @param {number} id
* @private
*/
_checkCheckBox: function (id ,strict) {
var self = this,
$chckBox = $('#id_'+id, self.$selfContainer);
if (strict){
this.strictMode = true;
}else{
this.strictMode = false;
}
if($chckBox.length && !$chckBox.prop('checked')){
$chckBox.prop('checked',true);
$chckBox.trigger('change');
}
},
/**
* select particular item and render its tag and check checkbox
* @param {Object} item ({id:3,name:'area'})
* @public
*/
selectTag:function (item) {
//check of repeating execution
var firstTime = true,
self = this,
waitHandler = function () {
for (var prop in self.curDNA) {
for (var prop2 in self.curDNA[prop]) {
if (prop2 == item.id){
firstTime = false;
}
}
}
if($('#id_'+item.id+'[name="' + item.name + '"]:checked').length){
firstTime = false;
$('#id_'+item.id+':checked').trigger('change');
}
// ban of repeating execution
if (firstTime) { // konec
self.isReceived = false;
var $checkbox = $('#id_' + item.id + '[name="' + item.name + '"]'),
requestObj, requestName,
treeLoadHandler = function (data) {
// make checkboxes selected after loading
self._loadParentTree(data, function () {
self._checkCheckBox(item.id);
self.isReceived = true;
});
$checkbox = $('#id_' + item.id);
};
// load tree related to selected item
if (!$checkbox.length) {
requestObj = {
id: item.id,
name: item.name
};
getRequest(requestObj, self.opt.getParentUrl, treeLoadHandler);
} else{
$checkbox.prop('checked', true);
$checkbox.trigger('change');
self.isReceived = true;
}
}else{
$('#id_'+item.id).prop('checked', true);
$('#id_'+item.id).trigger('change');
}
};
this.wait(waitHandler);
},
/**
* waits so far the previous request will be executed and execute a method
* @param {function} method
* @param {Object|Array} args
* @public
*/
wait:function(method, args) {
var self = this,
waitImages,
waitHandler = function(self, method, args) {
if (self.isReceived) {
if (args) {
method(args);
}
else{
method();
}
clearInterval(waitImages);
}
};
waitImages = setInterval(function() {waitHandler(self, method, args)}, 100);
},
/**
* check particular checkbox input
* @param {number} id
* @param {string} tagText
* @public
*/
check: function (id, tagText) {
var self = this,
$chckBox = $('#id_'+id, self.$selfContainer),
tagObj = {};
if($chckBox.length && !$chckBox.prop('checked')){
$chckBox.prop('checked',true);
$chckBox.trigger('change');
}
},
/**
* hide or show sublists according active selected link
* @param $sublist
* @param $this
* @private
*/
_slideToggle:function ($sublist, $this){
if($sublist.hasClass('hidden')){
$this.addClass('active');
$sublist.removeClass('hidden');
}else{
$this.removeClass('active');
//$sublist.addClass('hidden').find('ul').addClass('hidden');
$sublist.addClass('hidden').find('ul');
}
},
/**
* for dna.clone definition see dnajs.org
* @param {string} checkboxId
* @private
*/
_destroyTag:function(checkboxId){
var self = this;
if(self.itemsSelected[checkboxId]){
dna.destroy(self.itemsSelected[checkboxId]);
}
},
/**
* for dna.clone definition see dnajs.org
* @param {string} checkboxId
* @param tplObj
* @private
*/
_addTag: function (checkboxId, tplObj) {
var self = this;
self.itemsSelected[checkboxId] = dna.clone(self.opt.selectedItemTemplate,tplObj);
},
/**
* reset all checkboxes and clean tag wrapper
* @public
*/
resetList: function () {
var self = this;
for (var key in self.itemsSelected) {
if (self.itemsSelected.hasOwnProperty(key)) {
$('#'+key, self.$selfContainer).prop('checked', false).closest('.custom-radio-check').removeClass('active');
dna.destroy(self.itemsSelected[key]);
}
}
$('.level.active',this.$modal).removeClass('active');
this._refreshText();
self.selectedWrap.removeClass('visible');
$(this.$modal).find('input:checkbox:checked').prop('checked',false);
},
/**
* initiliazing and setup autocomplete field for places list
* @private
*/
_autocompleteInit : function () {
var self = this, dataObj, text , form = self.$inputFilter.attr('data-form'),index,
$completeWrap = $('#'+self.opt.autoCompleteId),
firstComplete = true,
/**
*
* @param event - Jquery event object
* @param ui - JqueryUI selected item object. ({item: {Objectid: -2090174,label: "Бангалор",name: "ci"text: "Бангалор",value: -2090174}})
*/
selectTag = function (event, ui) {
//check of repeating execution
self.selectTag({id:ui.item.id,name:ui.item.name});
self.$inputFilter.val(ui.item.label);
},
/**
* execute after client side recieve server response after enter 2 or above letter in autooomplete
* do Jquery UI autocomplete initialization and executing
* @param data - data object recieved from server. example {id: -2090174,name: "ci",text: "Бангалор"}
*/
requestHandler = function(data){
dataObj = data;
for(index = 0; index < dataObj.length; ++index) {
renameProperty(dataObj[index],'text','label');
}
for(index = 0; index < dataObj.length; ++index) {
renameProperty(dataObj[index],'id','value');
}
if(!self.$inputFilter.hasClass('ui-autocomplete-input')){
self.$inputFilter.autocomplete({
source:dataObj,
minLength: 0,
appendTo:$completeWrap,
select:function(event, ui){
selectTag(event, ui);
self.$inputFilter.val('');
self.$inputFilter.trigger('keyup');
event.preventDefault();
}
});
self.$inputFilter.autocomplete('search',"");
firstComplete = false;
}else{
self.$inputFilter.autocomplete('search',"");
}
};
/**
* the ID value of the timer that is set
*/
self.timeout;
self.$inputFilter.attr('autocomplete', 'on');
self.$inputFilter.on('keyup', function (event) {
text = $(this).val();
event.stopImmediatePropagation();
clearTimeout(self.timeout);
if (text.length > 2 && firstComplete){
self.timeout = setTimeout(function () {
getRequest({'term':text, 'form':form}, self.opt.autoCompleteUrl, requestHandler);
firstComplete = false;
}, 1000);
}else if(text.length == 0 && !firstComplete){
if(self.$inputFilter.hasClass('ui-autocomplete-input')){
self.$inputFilter.autocomplete( "destroy" );
firstComplete = true;
}
}
return false;
}).click(function () {
return false;
});
},
/**
* loads and shows list tree related to selected id
* @param {Object} data - is JSON object with information about parent elements.({text: "Германия", id: 47, parent: {text: "Европа", id: 4, name: "area"}, name: "co"})
* @param {function} handler - callback function
* @param {number} counter
* @private
*/
_loadParentTree: function (data, handler, counter) {
var self = this,
dataObj = data,
optObj, sublistTemplateId, nestedObj,nestedSublistTemplateId,
$midleLevelCheckbox = $('#id_'+dataObj.id),
/**
* makes request in order to recieve children list information fires after request for parent list
* @param {number} length - the number of received elements
* @function
*/
handlerNested = function (length) {
var $checkbox = $('#id_'+dataObj.id),
index = 0,
afterAll = function (number) {
$waiter.hide();
index++
if(index == number){
counter||counter===0?handler(counter):handler();
}
};
$waiter.hide();
if($checkbox.length && getObjectLength(self.curDNA[sublistTemplateId+'-sub']) == length){
nestedObj = {
name:dataObj.name,
id:dataObj.id
};
$waiter.show();
nestedSublistTemplateId = $('#id_'+dataObj.id).closest('.level').children('.trigger').attr('data-template-id');
self._renderNested(nestedObj, afterAll, nestedSublistTemplateId, dataObj.id);
}
},
/**
* @function
*/
handlerParent = function (){
$waiter.hide();
counter||counter===0?handler(counter):handler();
};
$waiter.show();
//if element has parent element
if(dataObj.hasOwnProperty('parent')){
//if checbox is existed
if($midleLevelCheckbox.length){
nestedObj = {
name:dataObj.name,
id:dataObj.id
};
nestedSublistTemplateId = $midleLevelCheckbox.closest('.level').children('.trigger').attr('data-template-id');
self._renderNested(nestedObj, function(){$waiter.hide();handler();}, nestedSublistTemplateId, dataObj.id);
}else{
optObj = {
name:dataObj.parent.name,
id:dataObj.parent.id
};
sublistTemplateId = $('#id_'+dataObj.parent.id).closest('.level').children('.trigger').attr('data-template-id');
self._renderSublist(optObj,sublistTemplateId,handlerNested);
}
}else{
optObj = {
name:dataObj.name,
id:dataObj.id
};
sublistTemplateId = $('#id_'+dataObj.id).closest('.level').children('.trigger').attr('data-template-id');
self._renderSublist(optObj,sublistTemplateId,handlerParent);
}
},
/**
* @param it
* @public
*/
applyHandler: function (it) {
console.log(this);
},
_refreshText: function () {
var selectedString,
$modalTrigger = $('#'+this.opt.modalTrigger),
cutLength = 16;
selectedString = getSelectedToString(this.opt.selectedItemsContainer,cutLength);
if(selectedString && selectedString != '~~text~~' && selectedString != '~~text~~...'){
$modalTrigger.text(selectedString);
$modalTrigger.siblings('.'+this.opt.clearAllButtonClass).addClass('active');
}else{
$modalTrigger.text($modalTrigger.data('default'));
$modalTrigger.siblings('.'+this.opt.clearAllButtonClass).removeClass('active');
}
}
};
/**
* period selector modal window
* @param {Object} options
* @constructor
*/
var PeriodModal = function (options) {
this.opt = options;
var self = this,
$dateFrom = $('#'+self.opt.dateFrom),
$dateTo = $('#'+self.opt.dateTo),
$modal = $('#'+self.opt.id),
$modalTrigger = $('#'+self.opt.modalTrigger),
applyBtnClass = self.opt.applyBtnClass,
$activeField,
/**
* make string from input:text values
* @returns {string}
* @function
*/
inputsTostring = function(){
var self = this,
stringToReturn = '',
toChar = $modalTrigger.data('lng-to'),
fromChar = $modalTrigger.data('lng-from'),
toVal = $.trim($dateTo.val()),
fromVal = $.trim($dateFrom.val());
if(toVal != ''&& fromVal != ''){
if($(window).width() < 1086){
stringToReturn = fromChar+': '+fromVal+'<br/>'+toChar+': '+toVal+'.';
}else{
stringToReturn = fromChar+': '+fromVal+' '+toChar+': '+toVal+'.';
}
} else if (toVal != ''&& fromVal == ''){
stringToReturn = toChar+': '+toVal+'.';
} else if (toVal == ''&& fromVal != ''){
stringToReturn = fromChar+': '+fromVal+'.';
}
return stringToReturn;
},
/**
* set trigger link text
* @param {string} selectedString
* @function
*/
triggerSetText = function (selectedString) {
var cutLength = 24;
if($(window).width() < 1086){
cutLength = 6;
}
if(selectedString != ''){
$modalTrigger.html(selectedString).siblings('.trigger-label').addClass('hidden');
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).addClass('active');
}else{
$modalTrigger.html($modalTrigger.data('default')).siblings('.trigger-label').removeClass('hidden');
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).removeClass('active');
}
},
/**
* checks and corrects value of fields of a modal and corrects values so that in the field from always there was a date "to" (less) date in the field "on"
* @param it
* @function
*/
checkInterval = function (it) {
var itId = it.getAttribute('id'),
itVal = it.value,
itValInt = Date.parse(itVal),
thatId,
thatVal,
thatValInt,
bfr;
/**
* check if it is a valid date
*/
if (self.validate()){
$(it).parent('.pwf-field').removeClass('err');
if(itId == self.opt.dateFrom){
thatId = $dateTo[0].getAttribute('id');
thatVal = $dateTo[0].value;
}else {
thatId = $dateFrom[0].getAttribute('id');
thatVal = $dateFrom[0].value;
}
thatValInt = Date.parse(thatVal);
/**
* swap values between date fields
*/
if(itValInt > thatValInt && itId == self.opt.dateFrom){
bfr = document.getElementById(itId).value;
document.getElementById(itId).value = document.getElementById(thatId).value;
document.getElementById(thatId).value = bfr;
}else if(itValInt < thatValInt && itId == self.opt.dateTo){
bfr = document.getElementById(thatId).value;
document.getElementById(thatId).value = document.getElementById(itId).value;
document.getElementById(itId).value = bfr;
}
}
};
this.$dateFrom = $dateFrom;
this.$dateTo = $dateTo;
this.$modalTrigger = $modalTrigger;
$(function () {
$.datepicker.setDefaults($.datepicker.regional["ru"]);
$dateFrom.datepicker({
dateFormat: 'dd.mm.yy',
showOn: 'button',
showOtherMonths: true,
constrainInput: true,
onClose: function( selectedDate ) {
$dateTo.datepicker( "option", "minDate", selectedDate );
}
}).inputmask("99.99.9999",{
showMaskOnHover:false,
insertMode:false,
'oncomplete': function () {
$activeField = this;
}
});
$dateTo.datepicker({
dateFormat: 'dd.mm.yy',
showOn: 'button',
showOtherMonths: true,
constrainInput: true,
onClose: function( selectedDate ) {
$dateFrom.datepicker( "option", "maxDate", selectedDate );
}
}).inputmask("99.99.9999",{
showMaskOnHover:false,
insertMode:false,
'oncomplete': function () {
$activeField = this;
}
});
$('input[type="text"]',$modal).on('change', function () {
var stringToset = inputsTostring();
if (self.validate()){
triggerSetText(stringToset);
}
});
$('.'+applyBtnClass, $modal).on('click', function () {
if($activeField){
checkInterval($activeField);
}
self.applyHandler(this);
return false;
});
$modalTrigger.siblings('.'+self.opt.clearAllButtonClass).on('click', function () {
$(this).removeClass('active');
self.resetList();
});
});
};
/**
* methods
* @type {{resetList: Function, applyHandler: Function}}
*/
PeriodModal.prototype = {
/**
* clear all input fields of modal window
* @public
*/
resetList: function () {
this.$dateFrom.val('');
this.$dateTo.val('');
this.$modalTrigger.text(this.$modalTrigger.attr('data-default'));
},
/**
* checks input fields to have valid date values, if not - adds err class to its container
* @returns {boolean}
*/
validate: function () {
var toVal = this.$dateTo.val(),
fromVal = this.$dateFrom.val(),
toValArr = toVal.split('.'),
fromValArr = fromVal.split('.'),
timestamps =[],
validationResult = true;
timestamps[0] = Date.parse(toValArr[1]+'.'+toValArr[0]+'.'+toValArr[2]);
timestamps[1] = Date.parse(fromValArr[1]+'.'+fromValArr[0]+'.'+fromValArr[2]);
if (!timestamps[0] && $.trim(toVal) != ''){
this.$dateTo.parent('.pwf-field').addClass('err');
validationResult = false;
}else{
this.$dateTo.parent('.pwf-field').removeClass('err');
}
if (!timestamps[1] && $.trim(fromVal) != ''){
this.$dateFrom.parent('.pwf-field').addClass('err');
validationResult = false;
}else{
this.$dateFrom.parent('.pwf-field').removeClass('err');
}
return validationResult;
},
applyHandler: function (it) {
}
};
/**
* constructor for main searchfield
* @param {Object} options
* @constructor
*/
var MainField = function (options) {
this.opt = options;
this.opt.anyChar = false;
var self = this,
firstComplete = true;
this.$field = $('#'+self.opt.id);
/**
* much faster than JQuery
* @type {HTMLElement}
*/
this.DOMcompleteWrap = document.getElementById(self.opt.autoCompleteWrapId);
this.afterClear;
/**
* data from ajax response
* @type {{items: Array, set: Function, get: Function, _rawDataChange: Function}}
*/
this.rawData = {
items:[],
/**
* setter
* @param data
* @public
*/
set:function (data) {
this.items = data;
this._rawDataChange();
},
/**
* get data
* @returns {*}
* @public
*/
get: function () {
return this.items;
},
/**
* executes when this.rawData changes
* @param {Object} e
* @private
*/
_rawDataChange: function (e) {
var self = this, index;
for(index = 0; index < self.items.length; index++) {
renameProperty(self.items[index],'text','label')
renameProperty(self.items[index],'id','value')
}
}
};
this.completeName = 'autocomplete';
this.firstComplete = true;
this.$field.attr('autocomplete','off');
/**
* the ID value of the timer that is set
*/
this.timeout;
//autocomplete behaviour
self.$field.on('keyup', function (event) {
var reqObj;
text = $(this).val();
event.stopImmediatePropagation();
clearTimeout(self.timeout);
if(self.dataForm){
reqObj = {
'term':text,
'form':self.dataForm
}
}else{
reqObj = {
'term':text
}
}
if(self.opt.anyChar){
if (text.length > 2){
self.timeout = setTimeout(function () {
getRequest(reqObj, self.opt.autoCompleteUrl, function (data) {
if(self.$field.hasClass('ui-autocomplete-input')){
self.$field[self.completeName]( "destroy" );
}
self.rawData.set(data);
self._initAutoComplete();
self.showList('');
});
}, 1000);
} else if(text.length === 0){
if(self.$field.hasClass('ui-autocomplete-input')){
self.$field[self.completeName]( "destroy" );
common.removeClass(self.DOMcompleteWrap,'full-visible');
self._resetmodals(self.afterClear);
}
}
}else{
if (text.length > 2 && firstComplete){
self.timeout = setTimeout(function () {
getRequest(reqObj, self.opt.autoCompleteUrl, function (data) {
self.rawData.set(data);
self._initAutoComplete();
self.showList('');
});
firstComplete = false;
}, 1000);
}else if(text.length == 0 && !firstComplete){
if(self.$field.hasClass('ui-autocomplete-input')){
self.$field[self.completeName]( "destroy" );
common.removeClass(self.DOMcompleteWrap,'full-visible');
self._resetmodals(self.afterClear);
firstComplete = true;
}
}else{
if(self.$field.hasClass('ui-autocomplete-input')){
self.showList(text);
}
}
}
//for autocomplete on each keypress
//for normal flow autocomplete
return false;
}).click(function () {
return false;
});
};
/**
* methods
* @type {{_initAutoComplete: Function, _afterSelect: Function, _resetmodals: Function, selectHandler: Function, newRender: Function, selectCheckBoxes: Function, showList: Function, pullData: Function}}
*/
MainField.prototype = {
/**
* Jquery autocomplete initialization and autocomplete functionality on this.$field
* @private
*/
_initAutoComplete: function () {
var self = this;
self.$field[self.completeName]({
source:self.rawData.get(),
minLength: 0,
appendTo:self.DOMcompleteWrap,
select:function(event, ui){
self._afterSelect(event, ui);
},
close: function () {
common.removeClass(self.DOMcompleteWrap,'full-visible');
},
open: function () {
common.addClass(self.DOMcompleteWrap,'full-visible');
}
});
},
/**
* fires after autocomplete is done and user selects item in it
* @param {Object} event
* @param {Object} ui
* @private
*/
_afterSelect: function (event, ui) {
var self = this;
event.preventDefault();
// much faster than jquery
if(ui.item.url){
window.location = ui.item.url;
} else if(ui.item.label.length){
self.$field[0].value = ui.item.label;
self.selectCheckBoxes(ui.item.id, ui.item.name);
}
},
/**
* method fires callback when field is cleared
* @param {function} callback
* @returns {number}
* @private
*/
_resetmodals: function (callback) {
if(callback){
callback();
}else{
return 0;
}
},
/**
* public property for redefine _afterSelect
* @public
*/
selectHandler: function () {
},
/**
* this property must be redefined for each individual instances of MainField Object
* select checkboxes if there is coincidence with search result and modal subject modal window
* @param {number} id
* @param {string} name
* @public
*/
selectCheckBoxes: function (id, name) {
},
/**
* simple shows out autocomplete list
* @param {string} text
*/
showList: function (text) {
self = this;
this.$field[self.completeName]('search',text);
},
/**
* brings data from server and transfer it to handler function
* @param {function} handler
*/
pullData: function (handler) {
},
clearValue: function () {
this.$field.val('');
}
};
/**
* whole module initialization
* @param {Object} options
* @public
*/
that.init = function(options) {
// settings extending
$.extend(this.lang, options.lang);
options.lang = null;
$.extend(this.settings, options);
// begin of initialization
var self = this,
submitHandler = function () {
$(self.DOMform).find('input[name="~~name~~"]').remove();
};
if(this.settings.searchData != 'None' && this.settings.searchData){
this.previousSearch = JSON.parse(this.settings.searchData)
}
this.DOMform = document.getElementById(this.settings.formId);
$(this.DOMform).on('submit', function () {
submitHandler();
});
// custom autocomplete realization for exibition input
$.widget( "custom.exibitionComplete", $.ui.autocomplete,{
_renderMenu: function( ul, items ) {
var that = this,
currentCategory = "";
$.each( items, function( index, item ) {
if ( item.cat != currentCategory && item.cat) {
ul.append( "<li class='ui-autocomplete-category'>" + item.cat + "</li>" );
currentCategory = item.cat;
}
that._renderItemData( ul, item );
});
}
});
$.widget( "custom.exibitionComplete", $.ui.autocomplete,{
_renderMenu: function( ul, items ) {
var that = this,
currentCategory = "";
$.each( items, function( index, item ) {
if ( item.cat != currentCategory && item.cat) {
ul.append( "<li class='ui-autocomplete-category'>" + item.cat + "</li>" );
currentCategory = item.cat;
}
that._renderItemData( ul, item );
});
}
});
$.widget( "custom.placeComplete", $.ui.autocomplete,{
_renderItem: function( ul, item ) {
return $( "<li>" )
.append( $( "<a>" ).text( item.label) )
.append('<span class="subj-category"> ('+item.cat+')</span>')
.appendTo( ul );
}
});
this.exhibitionField = new MainField(self.settings.firstField);
this.exhibitionField.completeName = 'exibitionComplete';
this.exhibitionField.opt.anyChar = true;
//modal windows
this.placesModal = new PlacesModal(self.settings.place);
this.subjModal = new SubjectModal(self.settings.subject);
this.periodModal = new PeriodModal(self.settings.period);
this.exhibitionField.selectCheckBoxes = function (id, name) {
var self = this,
DOMCheckboxes,
nestedObj,
iName = name;
if(name == 'th'){
DOMCheckboxes = document.getElementById(self.opt.prefix+id);
}else if(name == 'tg'){
DOMCheckboxes = document.getElementById(self.opt.prefixInner+id);
iName = 'th';
}
$waiter.show();
// load tree related to selected item
if (!DOMCheckboxes) {
nestedObj = {
name:name,
id:id
};
EXPO.searchBlock.subjModal.resetList();
getRequest(nestedObj, EXPO.searchBlock.subjModal.opt.getParentUrl, function (data) {
EXPO.searchBlock.subjModal._loadParentTree(data, function(){
EXPO.searchBlock.subjModal._checkCheckBox(id, name);
});
});
} else{
$waiter.hide();
EXPO.searchBlock.subjModal.resetList();
$(DOMCheckboxes).prop('checked', true);
$(DOMCheckboxes).trigger('change');
}
};
this.placesField = new MainField(self.settings.placeField);
this.placesField.dataForm = EXPO.searchBlock.placesModal.$inputFilter.attr('data-form');
this.placesField.selectCheckBoxes = function(id,name){
var self = this,
DOMCheckboxes,
nestedObj;
DOMCheckboxes = document.getElementById(self.opt.prefix+id);
if (!DOMCheckboxes) {
nestedObj = {
name:name,
id:id
};
EXPO.searchBlock.placesModal.resetList();
getRequest(nestedObj, EXPO.searchBlock.placesModal.opt.getParentUrl, function (data) {
EXPO.searchBlock.placesModal._loadParentTree(data, function(){
EXPO.searchBlock.placesModal._checkCheckBox(id, true);
});
});
} else{
$waiter.hide();
EXPO.searchBlock.placesModal.resetList();
$(DOMCheckboxes).prop('checked', true);
$(DOMCheckboxes).trigger('change');
}
};
// uncheck all checboxes in modal and clear label beneath searchfield
this.exhibitionField.afterClear = function () {
self.subjModal.resetList();
};
this.placesField.afterClear = function () {
self.placesModal.resetList();
};
//модальное окно
this.modalWindow = new common.Modal(self.settings.modal);
this.periodModal.applyHandler = function () {
if(this.validate()){
$waiter.show();
$(self.DOMform).submit();
}
};
this.placesModal.applyHandler = function () {
$waiter.show();
$(self.DOMform).submit();
};
this.subjModal.applyHandler = function () {
$waiter.show();
$(self.DOMform).submit();
};
//
// modal window calling
$('.'+self.settings.modalTriggerClass).on('click', function (event) {
event.preventDefault();
self.modalWindow.pullData(this.getAttribute('href'));
self.modalWindow.open();
return false;
});
// заполнение полей предыдущими значениями
$(function () {
if(self.previousSearch){
for (var i = 0; i < self.previousSearch.inputs.length; i++) {
// окно выбора тематики
if (self.previousSearch.inputs[i].name == 'th'){
self.subjModal.selectTag(self.previousSearch.inputs[i]);
// окно выбора мест
} else if (self.previousSearch.inputs[i].name == 'area'){
if(self.previousSearch.inputs[i].children && self.previousSearch.inputs[i].children.children){
self.placesModal.selectTag(self.previousSearch.inputs[i].children.children);
}else if (self.previousSearch.inputs[i].children){
self.placesModal.selectTag(self.previousSearch.inputs[i].children);
} else if(self.previousSearch.inputs[i]){
self.placesModal.selectTag(self.previousSearch.inputs[i]);
}
}
}
}
});
};
return that;
}());
}