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
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;
|
|
}());
|
|
}
|
|
|