PageSourceSearch

https://jacarandahealth.org/syssuree/unlimited-elements-for-elemen…/filters/ue_filters.js?ver=2.0.20

js jacarandahealth.org collected 2026-10-01 11:33:59 UTC 104,651 bytes, 5,161 lines download raw bytes

1//UE Filters Version 1.27
2
3function UEDynamicFilters(){
4
5	var g_objFilters, g_filtersData, g_urlBase;
6	var g_urlAjax, g_lastGridAjaxCall, g_cache = {}, g_objBody;
7	var g_remote = null, g_lastSyncGrids, g_initFiltersCounter = 0;
8	
9	var t = this;
10	
11	var g_showDebug = false;
12	var g_debugInitMode = false;
13	
14	var g_debugBeforeRefreshMode = false;	//debug filters state before refresh
15	
16	var g_isGutenberg = false;
17	
18	var g_types = {
19		PAGINATION:"pagination",
20		LOADMORE:"loadmore",
21		TERMS_LIST:"terms_list",
22		SEARCH: "search",
23		SELECT: "select",
24		SUMMARY: "summary",
25		GENERAL: "general",
26		GENERAL_MOBILE_DRAWER: "mobilefilters"
27	};
28
29	var g_vars = {
30		CLASS_DIV_DEBUG:"uc-div-ajax-debug",
31		CLASS_GRID:"uc-filterable-grid",
32		CLASS_GRID_NOREFRESH:"uc-grid-norefresh",	//grid that will not refresh
33		DEBUG_AJAX_OPTIONS: false,
34		CLASS_CLICKED:"uc-clicked",
35		CLASS_HIDDEN: "uc-filter-hidden",	//don't refresh with this class
36		CLASS_INITING: "uc-filter-initing",
37		CLASS_INITING_HIDDEN: "uc-initing-filter-hidden",
38		CLASS_SKIP_REFRESH: "uc-filters-norefresh",		//on some grid parent
39		CLASS_REFRESH_SOON: "uc-ajax-refresh-soon",
40		EVENT_SET_HTML_ITEMS: "uc_ajax_sethtml",
41		CLASS_FILTER_INITED:"ucfilters--filter-inited",
42		ATTRIBUTE_URLADD:"ajaxurladd",
43		GRID_DATA_SKIP_HTML: "skip_set_html",
44		
45		//grid events
46
47		EVENT_BEFORE_REFRESH: "uc_before_ajax_refresh",	   //on grid
48		EVENT_AJAX_REFRESHED: "uc_ajax_refreshed",	   //on grid
49		EVENT_AJAX_REFRESHED_BODY: "uc_ajax_refreshed_body",	   //on body
50		EVENT_UPDATE_ACTIVE_FILTER_ITEMS: "update_active_filter_items",	   //on grid
51		EVENT_UNSELECT_FILTER: "uc_unselect_filter",   //on grid
52		EVENT_SILENT_FILTER_CHANGE: "uc_silent_filter_change",   //on grid
53
54		EVENT_DOM_UPDATED: "uc_dom_updated",   //on body
55
56		//events on filters
57
58		EVENT_INIT_FILTER:"init_filter",
59		EVENT_INIT_FILTER_TYPE:"init_filter_type",
60		EVENT_GET_FILTER_DATA:"get_filter_data",
61		EVENT_FILTER_RELOADED: "uc_ajax_reloaded",
62
63		//grid actions
64
65		ACTION_CLEAR_FILTERS: "clear_filters",	   //on grid
66		ACTION_REFRESH_GRID: "uc_refresh",	//listen on grid
67		ACTION_GET_FILTERS_URL: "uc_get_filters_url",	//listen on grid
68		ACTION_FILTER_CHANGE: "uc_filter_change",		//listen on grid
69		ACTION_FILTER_UNSELECT_BY_KEY: "unselect_by_key",	//listen on grid
70		
71		REFRESH_MODE_PAGINATION: "pagination",
72		REFRESH_MODE_LOADMORE: "loadmore",
73		trashold_handle:null,
74		class_widget_wrapper:"elementor-widget",
75		current_postid:null,
76		ucpage_url:null
77	};
78
79	var g_options = {
80		is_cache_enabled:true,
81		urlkey_taxsap:"~"
82	};
83	
84	/**
85	 * console log some string
86	 */
87	function trace(str){
88		console.log(str);
89	}
90
91	function ________GENERAL_______________(){}
92
93
94
95	/**
96	 * add url param
97	 */
98	function addUrlParam(url, param, value){
99
100		if(url){
101			if(url.indexOf("?") == -1)
102				url += "?";
103			else
104				url += "&";
105		}
106
107		if(typeof value == "undefined")
108			url += param;
109		else
110			url += param + "=" + value;
111
112		return(url);
113	}
114
115
116	/**
117	 * get object property
118	 */
119	function getVal(obj, name, defaultValue){
120
121		if(!defaultValue)
122			var defaultValue = "";
123
124		var val = "";
125
126		if(!obj || typeof obj != "object")
127			val = defaultValue;
128		else if(obj.hasOwnProperty(name) == false){
129			val = defaultValue;
130		}else{
131			val = obj[name];
132		}
133
134		return(val);
135	}
136
137	/**
138	 * turn string value ("true", "false") to string
139	 */
140	function strToBool(str){
141
142		switch(typeof str){
143			case "boolean":
144				return(str);
145			break;
146			case "undefined":
147				return(false);
148			break;
149			case "number":
150				if(str == 0)
151					return(false);
152				else
153					return(true);
154			break;
155			case "string":
156				str = str.toLowerCase();
157
158				if(str == "true" || str == "1")
159					return(true);
160				else
161					return(false);
162
163			break;
164		}
165
166		return(false);
167	};
168
169	/**
170	 * get offsets distance
171	 */
172	function getOffsetsDistance(offset1, offset2){
173
174	  var dx = offset2.left-offset1.left;
175	  var dy = offset2.top-offset1.top;
176
177	  return Math.sqrt(dx*dx+dy*dy);
178	}
179
180	/**
181	 * round number to one decimal
182	 */
183	function roundToOneDecimal(num) {
184	    if (num % 1 !== 0) {
185	        return num.toFixed(1); // Round to 1 decimal place
186	    } else {
187	        return num.toFixed(0); // Keep the whole number
188	    }
189	}
190
191
192	/**
193	 * get closest object by offset
194	 */
195	function getClosestByOffset(objParents, objElement, isVertical){
196
197		if(objParents.length == 0){
198			throw new Error("get closest by offset error - grids not found");
199		}
200
201		if(g_showDebug == true){
202
203			trace("get closest grids for");
204			trace(objElement)
205			trace("parents");
206			trace(objParents);
207		}
208
209		var objClosest = null;
210		var minDiff = 1000000;
211
212		var elementOffset = objElement.offset();
213
214		jQuery.each(objParents, function(index, parent){
215
216			var objParent = jQuery(parent);
217
218			var objGrid = jQuery(parent);	//return this one
219
220			var distance = 0;
221
222			var isVisible = objParent.is(":visible");
223			
224			var constantHeight = null;
225
226			if(isVisible == false){
227				objParent = objParent.parent();
228			}
229
230			var parentOffset = objParent.offset();
231
232			if(isVertical == true){
233
234				var offsetY = elementOffset.top;
235				var parentY = parentOffset.top;
236
237				//get bottom of the parent
238
239				if(parentY < offsetY)
240					parentY += objParent.height();
241
242				var distance = Math.abs(offsetY - parentY);
243
244			}else{
245
246				var parentOffset = objParent.offset();
247
248				var distance = getOffsetsDistance(parentOffset, elementOffset);
249			}
250
251			if(g_showDebug == true){
252
253				trace(objParent);
254				trace("distance: " + distance);
255
256				trace("is vertical: " + isVertical);
257			}
258
259			if(distance < minDiff){
260				minDiff = distance;
261				objClosest = objGrid;
262			}
263
264		});
265
266		if(g_showDebug == true){
267
268			trace("filter: ");
269			trace(objElement);
270
271			trace("Closest grid found:");
272			trace(objClosest);
273		}
274
275
276		return(objClosest);
277	}
278
279	/**
280	 * get all grids
281	 */
282	function getAllGrids(type){
283
284		if(type == "loaded_only")
285			var objGrids = jQuery("."+ g_vars.CLASS_GRID).not(".ucfilters--grid-inited");
286		else
287			var objGrids = jQuery("."+ g_vars.CLASS_GRID);
288
289		return(objGrids);
290	}
291
292
293  /**
294   * get grid from parents containers
295   */
296  function getGridFromParentContainers(objSource){
297
298    var objParents = objSource.parents();
299    var objGrid = null;
300
301    if(g_showDebug == true){
302
303		trace("get from parent containers");
304		trace(objParents);
305	}
306
307    objParents.each(function(){
308
309      var objParent = jQuery(this);
310
311      objGrid = objParent.find("."+ g_vars.CLASS_GRID);
312
313      //if grid found return it and exit loop
314      if(objGrid.length >= 1)
315        return(false);
316
317    });
318
319
320    return(objGrid);
321  }
322
323
324	/**
325	 * get closest grid to some object
326	 */
327	function getClosestGrid(objSource){
328
329		//in case there are nothing:
330		var objGrids = getAllGrids();
331
332		if(objGrids.length == 0)
333			return(null);
334
335		if(g_showDebug == true){
336
337			trace("get closest grids");
338			trace(objSource);
339			trace(objGrids);
340		}
341
342		//get grid from parents
343
344		if(objGrids.length == 1)
345			return(objGrids);
346
347		//narrow by group
348		var group = objSource.data("connectgroup");
349
350		if(group){
351			var objGridsGroup = objGrids.filter("[data-filtergroup="+group+"]");
352			
353			if(objGridsGroup.length > 0){
354
355				if(objGridsGroup.length == 1)
356					return(objGridsGroup);
357
358				objGrids = objGridsGroup;
359			}
360
361		}else{
362
363			//get from same container - if group not set
364
365		    var objGrid = getGridFromParentContainers(objSource);
366
367		    if(objGrid && objGrid.length == 1)
368		        return(objGrid);
369		}
370
371
372		//get closest by offset
373
374	    if(objGrid && objGrid.length > 1)
375	    	objGrids = objGrid;
376
377		var objSingleGrid = getClosestByOffset(objGrids, objSource, true);
378
379		if(objSingleGrid && objSingleGrid.length == 1)
380			return(objSingleGrid);
381
382		//return first grid in the list
383
384		var objFirstGrid = jQuery(objGrids[0]);
385
386		return(objFirstGrid);
387	}
388
389	
390	
391	/**
392	 * add filter object to grid
393	 */
394	function bindFilterToGrid(objGrid, objFilter){
395		
396		if(g_showDebug){
397			trace("bind filter to grid");
398			
399			trace(objFilter);
400		}
401		
402		var arrFilters = objGrid.data("filters");
403		var objTypes = objGrid.data("filter_types");
404
405		if(!arrFilters)
406			arrFilters = [];
407
408		if(!objTypes)
409			objTypes = {};
410
411		var type = getFilterType(objFilter);
412
413		//validate double types
414
415		if(objTypes.hasOwnProperty(type)){
416
417			switch(type){
418				case g_types.LOADMORE:
419
420					trace("Double filter not allowed");
421					trace("existing Filters:");
422					trace(arrFilters);
423
424					trace("Second Filter");
425					trace(objFilter);
426
427					trace("Grid:");
428					trace(objGrid);
429
430					showElementError(objFilter, "Double load more button for one grid not allowed")
431					return(false);
432				break;
433			}
434
435		}
436
437		objTypes[type] = true;
438
439		var filterID = objFilter.attr("id");
440
441		//handle sticky
442		
443		var objElementorStickySpacer = objFilter.closest(".elementor-sticky__spacer");
444		if(objElementorStickySpacer.length)
445			return(true);
446		
447		
448		//----- validate existing -----
449		
450		var objExistingFilter = arrFilters.filter(function(objFilterInArray){
451			return objFilterInArray.attr("id") == filterID;
452		});
453		
454		if(objExistingFilter && objExistingFilter.length)
455				throw new Error("Can't bind filter to grid, it's already exists: " + filterID);			
456		
457		arrFilters.push(objFilter);
458
459		//add init after filters
460		var isInitAfter = objFilter.data("initafter");
461				
462		if(!isInitAfter)
463			isInitAfter = isSpecialFilterInitAfter(objFilter, objGrid);
464		
465		if(g_showDebug){
466			trace("init after: "+isInitAfter);
467		}
468				
469		if(isInitAfter === true){
470			addFilterToInitAfter(objFilter, objGrid);
471		}
472		
473		objGrid.data("filters", arrFilters);
474		
475		objGrid.data("filter_types", objTypes);
476
477	}
478
479	/**
480	 *
481	 * get element widget id from parent wrapper
482	 */
483	function getElementWidgetID(objElement){
484		
485		if (!objElement || objElement.length === 0)
486			throw new Error("Element not found");
487				
488		var objWidget = objElement.closest("."+g_vars.class_widget_wrapper);
489
490		if (objWidget.length === 0)
491			throw new Error("Element parent not found with class: "+g_vars.class_widget_wrapper);
492		
493		var widgetID = objWidget.data("id");
494
495		if (!widgetID)
496			throw new Error("widget id not found");
497
498		return widgetID;
499	}
500	
501
502	/**
503	 * get the grid widget object from elementor element id
504	 */
505	function getGridFromElementorElementID(elementID, group, showDebug){
506		
507		var selector = "."+g_vars.class_widget_wrapper+"[data-id='"+elementID+"']";
508		
509		var objElement = g_objBody.find(selector);
510		
511		if(showDebug == true){
512			trace("selector: "+selector);
513			trace("element: ");
514			trace(objElement);
515		}
516		
517		if(objElement.length == 0)
518			return(null);
519		
520		var selectorGrid = "."+g_vars.CLASS_GRID;
521		
522		var objGrid = objElement.find(selectorGrid);
523
524		if(showDebug == true){
525			trace("selector grid: "+selectorGrid);
526			trace("grid: ");
527			trace(objGrid);
528		}
529		
530		if(objGrid.length == 1)
531			return(objGrid);
532		
533		if(objGrid.length == 0)
534			return(null);
535
536		//more then one, filter by group
537		if(group){
538			objGrid = objGrid.filter("[data-filtergroup="+group+"]");
539		}
540
541		if(showDebug == true){
542			trace("after group filter: "+group);
543			trace(objGrid);
544		}
545		
546		if(objGrid.length != 1)
547			return(null);
548		
549		
550		return(objGrid);
551	}
552	
553	
554
555	/**
556	 * get another group widgets
557	 */
558	function getGroupWidgets(arrSyncedGrids, objElement){
559
560		var group = objElement.data("filtergroup");
561
562		if(!group)
563			return(arrSyncedGrids);
564
565		var objGrids = jQuery("."+ g_vars.CLASS_GRID);
566
567		if(objGrids.length < 2)
568			return(arrSyncedGrids);
569
570		var elementID = objElement.attr("id");
571
572		var objDataGrids = objGrids.filter("[data-filtergroup='"+group+"']:not(#" + elementID + ")");
573
574		if(objDataGrids.length == 0)
575			return(arrSyncedGrids);
576
577		jQuery.each(objDataGrids, function(index, grid){
578
579			var objGrid = jQuery(grid);
580
581			arrSyncedGrids.push(objGrid);
582		});
583
584
585
586		return(arrSyncedGrids);
587	}
588
589	/**
590	 * get synced widget IDs
591	 */
592	function getSyncedWidgetData(objElement){
593
594		var arrSyncedGrids = [];
595
596		if(g_remote)
597			arrSyncedGrids = g_remote.getSyncedElements(objElement);
598
599		if(!arrSyncedGrids)
600			arrSyncedGrids = [];
601
602		arrSyncedGrids = getGroupWidgets(arrSyncedGrids, objElement);
603
604		if(!arrSyncedGrids || arrSyncedGrids.length == 0)
605			return(false);
606
607		var arrWidgetIDs = [];
608
609		var objGrids = null;
610
611		for(var index in arrSyncedGrids){
612
613			var objGrid = arrSyncedGrids[index];
614
615			if(objGrid.hasClass(g_vars.CLASS_GRID) == false){
616
617				var message = "Please enable ajax on all synced widgets";
618				var message2 = "Please enable ajax on this synced widget, it's missing class: "+g_vars.CLASS_GRID;
619
620				showElementError(objGrid, message2);
621
622				showAjaxError(message);
623				throw new Error(message);
624				return(false);
625			}
626
627			var objWidgetID = getElementWidgetID(objGrid);
628
629			//add to jquery collection
630
631			if(!objGrids)
632				objGrids = objGrid;
633			else
634				objGrids = objGrids.add(objGrid);
635
636			arrWidgetIDs.push(objWidgetID);
637		}
638
639		var strWidgetIDs = arrWidgetIDs.toString();
640
641		var objOutput = {};
642		objOutput["ids"] = strWidgetIDs;
643		objOutput["grids"] = objGrids;
644
645		return(objOutput);
646	}
647
648
649	/**
650	 * get element layout data
651	 */
652	function getElementLayoutData(objElement, addSyncedGrids){
653		
654		//get widget id
655		var widgetID = getElementWidgetID(objElement);
656		var objWidget = objElement.parents("."+g_vars.class_widget_wrapper);
657
658		//get synced grids
659		var objSyncedData = null;
660
661		//add sync if allowed and available
662
663		if(addSyncedGrids){
664
665			var objSyncedData = getSyncedWidgetData(objElement);
666
667			if(g_showDebug && objSyncedData){
668
669				trace("sync data");
670				trace(objSyncedData);
671			}
672		}else{
673
674			if(g_showDebug)
675				trace("skip sync grid");
676
677		}
678		
679		//get layout id
680		
681		if(g_isGutenberg == false){
682		
683			var objLayout = objWidget.parents(".elementor");
684	
685			if(objLayout.length == 0)
686				throw new Error("layout not found");
687			
688			var layoutID = objLayout.data("elementor-id");
689	
690			if(!layoutID)
691				layoutID = objLayout.data("id");
692			
693		}else{	//gutenberg
694			
695			var layoutID = g_vars.current_postid;			
696		}
697		
698		
699		var output = {};
700
701		output["widgetid"] = widgetID;
702		output["layoutid"] = layoutID;
703
704		if(objSyncedData){
705			output["synced_widgetids"] = objSyncedData["ids"];
706			output["synced_grids"] = objSyncedData["grids"];
707		}
708
709		return(output);
710	}
711
712	/**
713	 * show element error above it
714	 */
715	function showElementError(objElement, error){
716
717		var objParent = objElement.parent();
718		
719		if(g_showDebug == true){
720			trace("Show Error Message for: ");
721			trace(objElement);
722			trace(error);
723		}
724		
725		var objError = objParent.find(".uc-filers-error-message");
726		if(objError.length == 0){
727			objParent.append("<div class='uc-filers-error-message' style='color:red;position:absolute;top:-24px;left:0px;background-color:rgba(230, 230, 230, 0.8);padding:3px;font-size:12px;border:5px solid white;'></div>");
728			var objError = objParent.find(".uc-filers-error-message");
729			objParent.css("border","1px solid red !important");
730		}
731		
732		objError.append(error);
733
734		objError.css("top",-objError.height()-5);
735		
736	}
737
738	/**
739	 * get grid empty message
740	 */
741	function getGridEmptyMessage(objGrid){
742
743		var gridID = objGrid.attr("id");
744
745		if(!gridID)
746			return(null);
747
748		var objEmptyMessage = jQuery("#"+gridID+"_empty_message");
749
750		if(objEmptyMessage.length == 0)
751			return(null);
752
753		return(objEmptyMessage);
754	}
755
756	/**
757	 * get active filter items, if no items - return 0
758	 */
759	function getGridActiveFilterItems(objGrid){
760		
761		var arrActiveItems = objGrid.data("active_filters_items");
762
763		if(!arrActiveItems)
764			return(null);
765
766		if(arrActiveItems.length == 0)
767			return(null);
768
769		return(arrActiveItems);
770	}
771
772
773	/**
774	 * get filters that are selected
775	 */
776	function getSelectedFilters(objFilters, roleArg){
777
778		if(!objFilters)
779			var objFilters = objGrid.data("filters");
780
781		if(!objFilters)
782			return(false);
783
784		var arrSelectedFilters = [];
785
786		jQuery.each(objFilters, function(index, filter){
787
788			var objFilter = jQuery(filter);
789			var isSelected = objFilter.hasClass("uc-has-selected");
790
791			if(!roleArg && isSelected == true){
792				arrSelectedFilters.push(objFilter);
793				return(true);
794			}
795
796			var role = objFilter.data("role");
797
798			if(role == roleArg){
799				var isSelected = objFilter.hasClass("uc-has-selected");
800				if(isSelected)
801					arrSelectedFilters.push(objFilter);
802			}
803
804		});
805
806		return(arrSelectedFilters);
807	}
808
809
810	function ________FILTERS_______________(){}
811
812
813	/**
814	 * get the parent
815	 */
816	function getFiltersParent(objFilters){
817
818		//init the events
819		var objParent = objFilters.parents(".elementor");
820
821		if(objFilters.length > 1 && objParent.length > 1)
822			objParent = objFilters.parents("body");
823
824		if(objParent.length > 1){
825			objParent = jQuery(objParent[0]);
826		}
827
828		if(objParent.length == 0)
829			objParent = objFilters.parents("body");
830
831		return(objParent);
832	}
833	
834	/**
835	 * get filter wrapper
836	 */
837	function getFilterWrapper(objFilter){
838		
839		var objParent = objFilter.parent();		
840		
841		if(objParent.hasClass("uc-checkbox-filter-accordion-container"))
842			objParent = objParent.parent();
843		
844		return(objParent);
845	}
846
847	
848	/**
849	 * get filter type
850	 */
851	function getFilterType(objFilter, getGeneralType){
852		
853		if(objFilter.hasClass("uc-filter-pagination"))
854			return(g_types.PAGINATION);
855
856		if(objFilter.hasClass("uc-filter-load-more"))
857			return(g_types.LOADMORE);
858
859		var filterType = objFilter.data("filtertype")
860
861		if(filterType == g_types.GENERAL && getGeneralType === true){
862			
863			var generalType = objFilter.data("generaltype");
864			return(generalType);
865		}
866		
867		if(filterType)
868			return(filterType);
869		
870		//if not found - throw error
871		
872		trace("Filter type not found: ");
873		trace(objFilter);
874		
875		throw new Error("wrong filter type");
876		
877	}
878
879
880	/**
881	 * clear all filters
882	 */
883	function clearAllFilters(objGrid){
884		
885		clearChildFilters(objGrid, null, true, null, true);
886	}
887
888	/**
889	 * get grid filters or null
890	 */
891	function getGridFilters(objGrid){
892
893		var objFilters = objGrid.data("filters");
894
895		if(!objFilters)
896			return(null);
897
898		if(objFilters.length == 0)
899			return(null);
900
901		return(objFilters);
902	}
903
904
905	/**
906	 * clear non main grid filters
907	 * hide children and just clear the main filters
908	 */
909	function clearChildFilters(objGrid, objCurrentFilter, isHideChildren, termID, isClearAll){
910		
911		var objFilters = getGridFilters(objGrid);
912		
913		if(!objFilters)
914			return(false);
915
916		var currentFilterID = null;
917
918		if(objCurrentFilter)
919			var currentFilterID = objCurrentFilter.attr("id");
920						
921		jQuery.each(objFilters, function(index, filter){
922						
923			var objFilter = jQuery(filter);
924			var filterID = objFilter.attr("id");
925
926			if(filterID == currentFilterID)
927				return(true);
928
929			var role = objFilter.data("role");
930			
931			//clear all others if that option selected
932			
933			if(role != "child" && role != "main" && role != "term_child"){
934				
935				if(isClearAll == true){
936					clearFilter(objFilter);
937				}
938				
939				return(true);
940			}
941
942			var isHide = false;
943			var isShow = false;
944
945			switch(role){
946				case "term_child":
947					if(isHideChildren == true)
948						isHide = true;
949
950					var linkedTermID = objFilter.data("childterm");
951
952					if(linkedTermID == termID){		//show the filter
953
954						objFilter.removeClass(g_vars.CLASS_HIDDEN);
955						objFilter.removeClass(g_vars.CLASS_INITING);
956						objFilter.removeClass(g_vars.CLASS_INITING_HIDDEN);
957					}else{
958						isHide = true;
959					}
960
961				break;
962				case "child":
963
964					if(isHideChildren == true)
965						isHide = true;
966					else{
967						//hide the filters and refresh
968
969						objFilter.removeClass(g_vars.CLASS_HIDDEN);
970
971						objFilter.addClass(g_vars.CLASS_INITING);
972						objFilter.addClass(g_vars.CLASS_INITING_HIDDEN);
973
974					}
975
976				break;
977				default:
978					
979					if(isClearAll == true){
980						clearFilter(objFilter);
981					}
982					
983					return(true);
984				break;
985			}
986
987			//hide the child filters and not refresh
988
989			if(isHide == true)
990				objFilter.addClass(g_vars.CLASS_HIDDEN);
991			
992			clearFilter(objFilter);
993
994		});
995
996	}
997
998	/**
999	 * clear some filter
1000	 */
1001	function clearFilter(objFilter){
1002		
1003		var type = getFilterType(objFilter);
1004
1005		switch(type){
1006			case g_types.TERMS_LIST:
1007				var objSelectedItems = objFilter.find(".ue_taxonomy_item.uc-selected");
1008				objSelectedItems.removeClass("uc-selected");
1009
1010				var objAll = objFilter.find(".ue_taxonomy_item.uc-item-all");
1011				objAll.addClass("uc-selected");
1012
1013			break;
1014			case g_types.SELECT:
1015				
1016				var objSelect = objFilter.find("select");
1017				objSelect.val("");
1018				
1019				//must leave one selected
1020				var objSelected = objFilter.find("option:selected");
1021				
1022				if(objSelected.length == 0)
1023					objFilter.find("option:first-child").prop("selected","selected");
1024				
1025			break;
1026			default:
1027			case g_types.SEARCH:
1028			case g_types.GENERAL:
1029				objFilter.trigger("clear_filter");
1030			break;
1031		}
1032
1033	}
1034
1035	/**
1036	 * unselect filter item
1037	 */
1038	function unselectFilterItem(objGrid, key){
1039
1040		var objFilters = getGridFilters(objGrid);
1041
1042		if(!objFilters)
1043			return(false);
1044		
1045		jQuery.each(objFilters, function(index, filter){
1046
1047			var objFilter = jQuery(filter);
1048			
1049			objFilter.trigger(g_vars.ACTION_FILTER_UNSELECT_BY_KEY, [key]);
1050			
1051		});
1052
1053	}
1054
1055	/**
1056	 * return true if the filter skip's it's action - like under mobile drawer
1057	 */
1058	function isFilterSkipAction(objFilter){
1059
1060		var objParentSkipRefresh = objFilter.parents("." + g_vars.CLASS_SKIP_REFRESH);
1061		
1062		if(objParentSkipRefresh.length)
1063			return(true);
1064
1065		return(false);
1066	}
1067	
1068	/**
1069	 * return if the grid has some child filters
1070	 */
1071	function hasChildFilters(objGrid){
1072		
1073		var objFilters = getGridFilters(objGrid);
1074		
1075		if(!objFilters)
1076			return(false);
1077		
1078		for(var index in objFilters){
1079			
1080			var objFilter = objFilters[index];
1081			var role = objFilter.data("role");
1082			if(role == "child")
1083				return(true);
1084		}
1085		
1086		return(false);
1087	}
1088	
1089	/**
1090	 * check and trigger skip action to the grid if needed 
1091	 * run before the refresh on some filter click
1092	 * for the mobile drawer (off canvas)
1093	 */
1094	function checkTriggerSkipAction(objFilter, objGrid){
1095		
1096		var isSkipAction = isFilterSkipAction(objFilter);
1097		if(isSkipAction == false)
1098			return(false);
1099		
1100		if(g_showDebug == true)
1101			trace("skip refresh - silent change triggered");
1102		
1103		var filterRole = objFilter.data("role");
1104		
1105		objGrid.trigger(g_vars.EVENT_SILENT_FILTER_CHANGE);
1106		
1107		initGrid_setActiveFiltersData(objGrid);
1108		
1109		//refresh children only main / children available
1110		if(filterRole == "main" && hasChildFilters(objGrid)){
1111			
1112			if(g_showDebug == true)
1113				trace("refresh children only");
1114			
1115			objGrid.data(g_vars.GRID_DATA_SKIP_HTML, true);
1116			refreshAjaxGrid(objGrid);
1117		}
1118		
1119		
1120		return(true);
1121	}
1122	
1123	function ________PAGINATION_FILTER______(){}
1124
1125
1126	/**
1127	 * get pagination selected url or null if is current
1128	 */
1129	function getPaginationSelectedData(objPagination){
1130				
1131		var objCurrentLink = objPagination.find("a.current,span.current");
1132			
1133		if(objCurrentLink.length == 0)
1134			return(null);
1135
1136		var url = objCurrentLink.attr("href");
1137				
1138		var numPage = objCurrentLink.text();
1139		
1140		if(jQuery.isNumeric(numPage) == false)
1141			numPage = null;
1142
1143		numPage = Number(numPage);
1144
1145		if(numPage === 1)
1146			numPage = null;
1147
1148		var output = {};
1149		output["url"] = url;
1150		output["page"] = numPage;
1151
1152		return(output);
1153	}
1154
1155
1156	/**
1157	 * on ajax pagination click
1158	 */
1159	function onAjaxPaginationLinkClick(event){
1160		
1161		var objLink = jQuery(this);
1162		
1163		//if no grid attached - act like a regular link
1164		
1165		var objPagination = objLink.parents(".uc-filter-pagination");
1166		
1167		var objGrid = objPagination.data("grid");
1168		
1169		if(!objGrid || objGrid.length == 0 || objPagination.hasClass("uc-no-ajax")){
1170						
1171			return(true);
1172		}
1173		
1174		//run the ajax, prevent default
1175		event.preventDefault();
1176		
1177		var objLinkCurrent = objPagination.find(".current");
1178
1179		
1180		//on next button click
1181
1182		if(objLink.hasClass("next")){
1183
1184			var nextLink = objLinkCurrent.next();
1185
1186			var objNextLink = jQuery(nextLink);
1187
1188			objNextLink.trigger("click");
1189
1190			return(false);
1191		}
1192
1193
1194		//on prev button click
1195
1196		if(objLink.hasClass("prev")){
1197
1198			var prevLink = objLinkCurrent.prev();
1199
1200			var objPrevLink = jQuery(prevLink);
1201
1202			objPrevLink.trigger("click");
1203
1204			return(false);
1205		}
1206
1207		objLinkCurrent.removeClass("current");
1208
1209		objLink.addClass("current");
1210
1211		var objGrid = objPagination.data("grid");
1212		
1213		objPagination.addClass(g_vars.CLASS_CLICKED);
1214
1215		if(g_showDebug == true){
1216
1217			trace("click on pagination!!!, no grid refresh");
1218			trace(objLink);
1219
1220		}else{
1221
1222			refreshAjaxGrid(objGrid, g_vars.REFRESH_MODE_PAGINATION);
1223
1224		}
1225
1226		return(false);
1227	}
1228
1229
1230	function ________LOAD_MORE_______________(){}
1231
1232
1233	/**
1234	 * get current load more page
1235	 */
1236	function getLoadMoreUrlData(objFilter){
1237
1238		var objData = objFilter.find(".uc-filter-load-more__data");
1239
1240		var nextOffset = objData.data("nextoffset");
1241		if(!nextOffset)
1242			nextOffset = null;
1243
1244		var numItems = objFilter.data("numitems");
1245
1246		if(!numItems)
1247			numItems = null;
1248
1249		//affect only single grids
1250
1251		var isSingleGridOnly = objFilter.data("affect_single_grid");
1252
1253
1254		var data = {};
1255		data.offset = nextOffset;
1256		data.numItems = numItems;
1257		data.singlegrid = isSingleGridOnly;
1258
1259		return(data);
1260	}
1261
1262
1263	/**
1264	 * do the load more operation
1265	 */
1266	function onLoadMoreClick(){
1267
1268		var objLink = jQuery(this);
1269
1270		var objLoadMore = objLink.parents(".uc-filter-load-more");
1271
1272		var objData = objLoadMore.find(".uc-filter-load-more__data");
1273
1274		var isMore = objData.data("more");
1275
1276		if(isMore == false)
1277			return(false);
1278
1279		var objGrid = objLoadMore.data("grid");
1280
1281		if(!objGrid || objGrid.length == 0)
1282			throw new Error("Grid not found!");
1283
1284		//run the ajax, prevent default
1285
1286		objLoadMore.addClass(g_vars.CLASS_CLICKED);
1287
1288		refreshAjaxGrid(objGrid, g_vars.REFRESH_MODE_LOADMORE);
1289
1290	}
1291
1292	function ________SELECT_______________(){}
1293
1294	/**
1295	 * init select filter, select the selected item (avoid cache)
1296	 */
1297	function initSelectFilter(objFilter){
1298		
1299		var objSelected = objFilter.find(".uc-selected");
1300
1301		if(objSelected.length == 0)
1302			return(false);
1303
1304		var value = objSelected.attr("value");
1305
1306		var objSelect = objFilter.find("select");
1307
1308		objSelect.val(value);
1309
1310	}
1311
1312
1313	function ________TERMS_LIST_______________(){}
1314
1315	/**
1316	 * unselect by key terms list and select
1317	 */
1318	function termsFilterUnselectByKey(event,key){
1319				
1320		var objFilter = jQuery(this);
1321		
1322		var selectedTerm = getTermsListSelectedTerm(objFilter);
1323		
1324		if(!selectedTerm)
1325			return(false);
1326		
1327		var selectedKey = getVal(selectedTerm,"key");
1328		
1329		if(selectedKey != key)
1330			return(false);
1331		
1332		//if key match - clear filter and set no refresh.
1333
1334		clearFilter(objFilter);	
1335		
1336		setNoRefreshFilter(objFilter);
1337	}
1338
1339
1340	/**
1341	 * on terms list click
1342	 */
1343	function onTermsLinkClick(event){
1344		
1345		var className = "uc-selected";
1346
1347		event.preventDefault();
1348
1349		var objLink = jQuery(this);
1350 
1351		if(objLink.hasClass("uc-grid-filter")){
1352
1353			var objTermsFilter = objLink;
1354
1355		}else{
1356
1357			var objTermsFilter = objLink.parents(".uc-grid-filter");
1358		}
1359
1360		var filterType = getFilterType(objTermsFilter);
1361
1362		if(filterType == g_types.SELECT){
1363
1364			var objLink = objTermsFilter.find("option:selected");
1365		}
1366
1367		if(filterType == g_types.TERMS_LIST){
1368
1369			var objActiveLinks = objLink.siblings("."+className).not(objLink);
1370
1371			objActiveLinks.removeClass(className);
1372			objLink.addClass(className);
1373
1374		}
1375
1376		var objGrid = objTermsFilter.data("grid");
1377
1378		if(!objGrid || objGrid.length == 0)
1379			throw new Error("Grid not found");
1380
1381		//if main filter - clear other filters
1382
1383		var filterRole = objTermsFilter.data("role");
1384
1385		var termID = objLink.data("id");
1386
1387		//set refresh - if all and there are hidden items - refresh
1388		var isRefresh = false;
1389
1390		if(!termID){
1391			var objHiddenItems = objTermsFilter.find(".uc-item-hidden");
1392			if(objHiddenItems.length)
1393				isRefresh = true;
1394		}
1395
1396		var isHideChildren = false;
1397		if(!termID)
1398			isHideChildren = true;
1399		
1400		//set not refresh next iteration, because of the clicked
1401		if(isRefresh == false)
1402			setNoRefreshFilter(objTermsFilter);
1403
1404		if(filterRole == "main")
1405			clearChildFilters(objGrid, objTermsFilter, isHideChildren, termID);
1406
1407		//skip action
1408		
1409		var isSkipAction = checkTriggerSkipAction(objTermsFilter, objGrid);
1410		
1411		if(isSkipAction == true)
1412			return(false);
1413		
1414		
1415		if(g_showDebug == true){
1416			trace("refresh grid - on term click");
1417		}
1418		
1419		//refresh grid
1420		refreshAjaxGrid(objGrid);
1421
1422	}
1423
1424
1425	/**
1426	 * get terms list term id
1427	 */
1428	function getTermsListSelectedTerm(objFilter){
1429
1430		if(!objFilter)
1431			return(null);
1432
1433		var filterType = getFilterType(objFilter);
1434
1435		var objSelected = objFilter.find(".uc-selected");
1436
1437		if(filterType == g_types.SELECT){
1438
1439			var objSelected = objFilter.find("option:selected");
1440
1441		}else{
1442
1443			var objSelected = objFilter.find(".uc-selected");
1444		}
1445
1446		if(objSelected.length == 0){
1447
1448			if(g_showDebug == true){
1449				trace("no selected found, skipping...");
1450			}
1451
1452			return(null);
1453		}
1454
1455		//check for hidden
1456
1457		if(filterType == g_types.TERMS_LIST && objSelected.hasClass("uc-item-hidden") == true){
1458
1459			if(g_showDebug == true){
1460
1461				trace("the selected object");
1462				trace(objSelected);
1463				trace("the term is hidden, skipping...");
1464
1465			}
1466
1467			return(null);
1468		}
1469
1470		if(objSelected.length > 1)
1471			objSelected = jQuery(objSelected[0]);
1472
1473		var objTerm = getFilterElementData(objSelected);
1474
1475		return(objTerm);
1476	}
1477
1478	/**
1479	 * select items in terms list by terms
1480	 */
1481	function termListSelectItems(objFilter, arrTerms){
1482
1483		//deselect
1484		var objSelected = objFilter.find(".uc-selected");
1485
1486		objSelected.removeClass("uc-selected");
1487
1488		//select by term
1489
1490		jQuery.each(arrTerms, function(index, term){
1491
1492			var termID = getVal(term,"id");
1493			var objItem = objFilter.find("a.ue_taxonomy_item[data-id='"+termID+"']");
1494
1495			if(objItem.length == 0)
1496				return(true);
1497
1498			objItem.addClass("uc-selected");
1499		});
1500
1501
1502	}
1503
1504	function ________GENERAL_FILTER_______________(){}
1505
1506	/**
1507	 * init general filter
1508	 */
1509	function initGeneralFilter(objFilter){
1510		
1511		objFilter.on(g_vars.ACTION_FILTER_CHANGE, onGeneralFilterChange);
1512
1513	}
1514
1515
1516
1517	/**
1518	 * on general filter change
1519	 */
1520	function onGeneralFilterChange(event, params){
1521			
1522		event.stopPropagation();
1523
1524		var isRefresh = getVal(params, "refresh");
1525
1526		var objFilter = jQuery(this);
1527		
1528		var filterType = objFilter.data("filtertype");
1529
1530		if(filterType != "general"){
1531			
1532			trace(objFilter);
1533
1534			throw new Error("Not a general filter on action: " + g_vars.ACTION_FILTER_CHANGE);
1535			return(false);
1536		}
1537				
1538		if(isRefresh !== true)
1539			setNoRefreshFilter(objFilter);
1540
1541		var objGrid = objFilter.data("grid");
1542
1543		if(!objGrid || objGrid.length == 0){
1544
1545			trace(objGrid);
1546
1547			throw new Error("Wrong filter change");
1548			return(false);
1549		}
1550		
1551		var filterRole = objFilter.data("role");
1552		
1553		if(filterRole == "main"){
1554			
1555			var isHideChildren = false;
1556			
1557			//if no items selected - hide all children			
1558			var objData = getGeneralFilterData(objFilter);
1559			if(!objData)
1560				isHideChildren = true;
1561			
1562			clearChildFilters(objGrid, objFilter, isHideChildren);
1563		}
1564		
1565		//check for skip action
1566
1567		var isSkipAction = checkTriggerSkipAction(objFilter, objGrid);
1568		
1569		if(isSkipAction == true)
1570			return(false);
1571
1572
1573		if(g_showDebug == true){
1574
1575			trace("refresh grid - on general filter change");
1576			trace(objFilter);
1577
1578		}
1579		
1580		refreshAjaxGrid(objGrid);
1581
1582		return(false);
1583	}
1584
1585
1586	/**
1587	 * select filter items by terms, without refresh, just set selected
1588	 */
1589	function selectFilterItemsByTerms(objFilters, arrTerms){
1590
1591		if(!objFilters || objFilters.length == 0)
1592			return(false);
1593
1594		if(!arrTerms || arrTerms.length == 0)
1595			return(false);
1596		
1597		jQuery.each(objFilters,function(index, filter){
1598
1599			var objFilter = jQuery(filter);
1600
1601			selectFilterItems(objFilter, arrTerms);
1602
1603		});
1604
1605	}
1606
1607	/**
1608	 * select filter items
1609	 */
1610	function selectFilterItems(objFilter, arrTerms){
1611
1612		var type = getFilterType(objFilter);
1613
1614		switch(type){
1615			//case g_types.SELECT:
1616			case g_types.TERMS_LIST:
1617
1618				termListSelectItems(objFilter, arrTerms);
1619
1620			break;
1621			case g_types.GENERAL:
1622
1623				objFilter.trigger("uc_select_items", arrTerms);
1624
1625			break;
1626		}
1627
1628	}
1629
1630	/**
1631	 * get filter data
1632	 */
1633	function getGeneralFilterData(objFilter){
1634		
1635		var filterDataObj = {};
1636		objFilter.trigger(g_vars.EVENT_GET_FILTER_DATA, filterDataObj);
1637		
1638		var filterData = getVal(filterDataObj, "output");
1639		
1640		return(filterData);
1641	}
1642
1643
1644	function ________INIT_FILTERS_______________(){}
1645
1646	/**
1647	 * init terms related filer (terms list and select)
1648	 */
1649	function initTermsRelatedFilter(objFilter){
1650		
1651		objFilter.on(g_vars.ACTION_FILTER_UNSELECT_BY_KEY, termsFilterUnselectByKey);
1652
1653	}
1654
1655
1656	/**
1657	 * get filter taxonomy id's
1658	 */
1659	function getFilterTaxIDs(objFilter, objIDs){
1660
1661		var type = getFilterType(objFilter);
1662
1663		//skip the if
1664		if(type == g_types.SELECT)
1665			var objItems = objFilter.find(".uc-select-filter__option");
1666		else
1667			var objItems = objFilter.find(".ue_taxonomy_item");
1668
1669		if(objItems.length == 0)
1670			return(objIDs);
1671
1672		jQuery.each(objItems, function(index, item){
1673
1674			var objItem = jQuery(item);
1675			var taxID = objItem.data("id");
1676
1677			if(!taxID)
1678				return(true);
1679
1680			objIDs[taxID] = true;
1681		});
1682
1683
1684		return(objIDs);
1685	}
1686
1687	/**
1688	 * get tax id's list string from assoc object
1689	 */
1690	function getTermDsList(objIDs){
1691
1692		var strIDs = "";
1693		for(var id in objIDs){
1694
1695			if(jQuery.isNumeric(id) == false)
1696				continue;
1697
1698			if(strIDs)
1699				strIDs += ",";
1700
1701			strIDs += id;
1702		}
1703
1704		return(strIDs);
1705	}
1706
1707
1708	function ________DATA_______________(){}
1709
1710
1711	/**
1712	 * map meta compare operator to URL word, empty for equals
1713	 */
1714	function getMetaCompareUrlWord(compare){
1715
1716		if(!compare || compare === "=" || compare === "equals")
1717			return("");
1718
1719		var map = {
1720			"!=": "notequals",
1721			">": "greater",
1722			"<": "less",
1723			">=": "greaterequal",
1724			"<=": "lessequal",
1725			"LIKE": "like",
1726			"NOT LIKE": "notlike",
1727			"IN": "in",
1728			"NOT IN": "notin",
1729			"BETWEEN": "between",
1730			"NOT BETWEEN": "notbetween",
1731			"EXISTS": "exists",
1732			"NOT EXISTS": "notexists"
1733		};
1734
1735		if(map[compare])
1736			return(map[compare]);
1737
1738		var lower = ("" + compare).toLowerCase();
1739
1740		for(var op in map){
1741			if(map[op] === lower)
1742				return(map[op]);
1743		}
1744
1745		return("");
1746	}
1747
1748
1749	/**
1750	 * selected meta pair for init mode: key:value[:compare]
1751	 */
1752	function getMetaSelectedPair(objMeta){
1753
1754		var metaKey = getVal(objMeta, "meta_key");
1755
1756		if(!metaKey)
1757			metaKey = getVal(objMeta, "slug");
1758
1759		if(!metaKey)
1760			return("");
1761
1762		var metaValue = getVal(objMeta, "meta_value");
1763
1764		if(!metaValue)
1765			metaValue = "";
1766
1767		var metaPair = metaKey + g_options.urlkey_taxsap + metaValue;
1768		var compareWord = getMetaCompareUrlWord(getVal(objMeta, "compare"));
1769
1770		if(compareWord)
1771			metaPair += g_options.urlkey_taxsap + compareWord;
1772
1773		return(metaPair);
1774	}
1775
1776
1777	/**
1778	 * grouping key for meta items: key, or key + compare word
1779	 */
1780	function getMetaGroupedQueryKey(objItem, keyName, extraName){
1781
1782		var key = objItem[keyName];
1783
1784		if(!key || !extraName)
1785			return(key);
1786
1787		var word = getMetaCompareUrlWord(objItem[extraName]);
1788
1789		if(!word)
1790			return(key);
1791
1792		return(key + "\x1e" + word);
1793	}
1794
1795
1796	/**
1797	 * handle item, add to key->values map
1798	 * keyName/valueName: "taxonomy"/"slug" for terms, "meta_key"/"meta_value" for meta
1799	 * extraName: optional, groups meta by compare as well
1800	 */
1801	function buildGroupedValuesQuery_handleItem(objItem, arrGrouped, keyName, valueName, extraName){
1802
1803		var key = getMetaGroupedQueryKey(objItem, keyName, extraName);
1804		var value = objItem[valueName];
1805
1806		if(!key)
1807			return(arrGrouped);
1808
1809		if(value === null || typeof value === "undefined")
1810			value = "";
1811
1812		var objValues = getVal(arrGrouped, key);
1813		if(!objValues)
1814			objValues = {};
1815
1816		objValues[value] = true;
1817		arrGrouped[key] = objValues;
1818
1819		return(arrGrouped);
1820	}
1821
1822	/**
1823	 * get values string (dot separated)
1824	 * adds .* for AND relation when multiple values
1825	 */
1826	function buildGroupedValuesQuery_getStrValues(objValues, isGroup){
1827		
1828		var isDebug = false;
1829		
1830		if(isDebug == true){
1831			trace("get str values");
1832			trace(objValues);
1833			trace("is group:" + isGroup);
1834		}
1835		
1836		var strValues = "";
1837
1838		var moreThenOne = false;
1839		var isEndSlugFound = false;
1840		var isOrSlugFound = false;
1841		
1842		for (var value in objValues){
1843				
1844			if(value === "__ucand__"){
1845				isEndSlugFound = true;
1846				continue
1847			}
1848			
1849			if(value === "__ucor__"){
1850				isOrSlugFound = true;
1851				continue
1852			}
1853
1854			if(strValues){
1855				moreThenOne = true;
1856				strValues += ".";
1857			}
1858
1859			strValues += value;
1860		}
1861
1862		if(isDebug == true){
1863			trace("more then one: "+moreThenOne);
1864			trace("is end found: "+isEndSlugFound);
1865		}
1866		
1867		var addAnd = (moreThenOne == true && isGroup !== true || isEndSlugFound);
1868		
1869		if(isOrSlugFound === true)
1870			addAnd = false;
1871		
1872		if(addAnd)
1873			strValues += ".*";
1874
1875		if(isDebug)
1876			trace("str values: "+strValues);
1877		
1878		return(strValues);
1879	}
1880
1881
1882	/**
1883	 * build grouped values query string
1884	 * format: key:value1.value2.*;key2:value3
1885	 * used for ucterms (taxonomy:slugs) and ucmeta (meta_key:values[:compare])
1886	 */
1887	function buildGroupedValuesQuery(arrItems, keyName, valueName, extraName){
1888		
1889		var isDebug = false;
1890
1891		if(!keyName)
1892			keyName = "taxonomy";
1893
1894		if(!valueName)
1895			valueName = "slug";
1896
1897		var query = "";
1898
1899		var arrGrouped = {};
1900		var arrGroupItems = [];
1901
1902		if(isDebug == true){
1903			trace("arr items");
1904			trace(arrItems);
1905		}
1906		
1907		jQuery.each(arrItems, function(index, objItem){
1908
1909			//group
1910			if(jQuery.isArray(objItem) && objItem.length != 0){
1911				
1912				if(objItem.length == 1){
1913					arrGrouped = buildGroupedValuesQuery_handleItem(objItem[0], arrGrouped, keyName, valueName, extraName);
1914					return;
1915				}
1916
1917				var arrGroupMap = {};
1918				
1919				jQuery.each(objItem, function(index, groupItem){
1920					
1921					arrGroupMap = buildGroupedValuesQuery_handleItem(groupItem, arrGroupMap, keyName, valueName, extraName);
1922				});
1923
1924				arrGroupItems.push(arrGroupMap);
1925
1926			}else{	//single
1927
1928				arrGrouped = buildGroupedValuesQuery_handleItem(objItem, arrGrouped, keyName, valueName, extraName);
1929			}
1930
1931		});
1932		
1933		if(isDebug == true){
1934			trace("first arr grouped");
1935			trace(arrGrouped);
1936		}
1937
1938		if(jQuery.isEmptyObject(arrGrouped) && jQuery.isEmptyObject(arrGroupItems))
1939			return(null);
1940
1941		if(isDebug == true){
1942			trace("group items");
1943			trace(arrGroupItems);
1944		}
1945		
1946		var isMultipleGroups = (arrGroupItems.length > 1);
1947		
1948		jQuery.each(arrGroupItems, function(index, objGroupKeys){
1949			
1950			jQuery.each(objGroupKeys, function(key, objValues){
1951				
1952			var strValues = buildGroupedValuesQuery_getStrValues(objValues, true);
1953			
1954			var strAdd = strValues;
1955			if(isMultipleGroups === true && strValues.indexOf(".") !== -1){
1956				strAdd = "|"+strValues+"|";	//OR inside the group - only when multiple groups
1957			}
1958				
1959				var objKeyValues = getVal(arrGrouped, key);
1960				if(!objKeyValues)
1961					objKeyValues = {};
1962		
1963				objKeyValues[strAdd] = true;
1964		
1965				arrGrouped[key] = objKeyValues;
1966			});
1967
1968		});
1969
1970		
1971		if(isDebug == true){
1972			trace("The result after grouping");
1973			trace(arrGrouped);
1974		}
1975
1976		jQuery.each(arrGrouped, function(groupKey, objValues){
1977			
1978			var strValues = buildGroupedValuesQuery_getStrValues(objValues);
1979
1980			var key = groupKey;
1981			var compareWord = "";
1982			var sepIndex = groupKey.indexOf("\x1e");
1983
1984			if(sepIndex !== -1){
1985				key = groupKey.substring(0, sepIndex);
1986				compareWord = groupKey.substring(sepIndex + 1);
1987			}
1988				
1989			var strPart = key + g_options.urlkey_taxsap + strValues;
1990
1991			if(compareWord)
1992				strPart += g_options.urlkey_taxsap + compareWord;
1993			
1994			if(query)
1995				query += ";";
1996
1997			query += strPart;
1998
1999		});
2000
2001		if(isDebug == true){
2002			trace("query");
2003			trace(query);
2004		}
2005
2006		return(query);
2007	}
2008
2009	/**
2010	 * build terms query
2011	 * ucterms=category:blog.cocktails.design.*
2012	 */
2013	function buildTermsQuery(arrTerms){
2014
2015		return buildGroupedValuesQuery(arrTerms, "taxonomy", "slug");
2016	}
2017
2018	/**
2019	 * build meta query - same format as terms, optional compare word
2020	 * ucmeta=meta_key:value1.value2;meta_key:value:notequals
2021	 */
2022	function buildMetaQuery(arrMeta){
2023
2024		//normalize: ensure meta_key exists (fallback from slug)
2025		var arrNormalized = [];
2026
2027		jQuery.each(arrMeta, function(index, item){
2028
2029			if(jQuery.isArray(item)){
2030
2031				var arrGroup = [];
2032
2033				jQuery.each(item, function(groupIndex, groupItem){
2034
2035					if(!groupItem)
2036						return(true);
2037
2038					if(!groupItem.meta_key && groupItem.slug)
2039						groupItem.meta_key = groupItem.slug;
2040
2041					if(typeof groupItem.meta_value === "undefined" || groupItem.meta_value === null)
2042						groupItem.meta_value = "";
2043
2044					if(!groupItem.compare)
2045						groupItem.compare = "=";
2046
2047					arrGroup.push(groupItem);
2048				});
2049
2050				arrNormalized.push(arrGroup);
2051
2052			}else{
2053
2054				if(!item)
2055					return(true);
2056
2057				if(!item.meta_key && item.slug)
2058					item.meta_key = item.slug;
2059
2060				if(typeof item.meta_value === "undefined" || item.meta_value === null)
2061					item.meta_value = "";
2062
2063				if(!item.compare)
2064					item.compare = "=";
2065
2066				arrNormalized.push(item);
2067			}
2068
2069		});
2070
2071		return buildGroupedValuesQuery(arrNormalized, "meta_key", "meta_value", "compare");
2072	}
2073
2074	/**
2075	 * get selected filter element data
2076	 */
2077	function getFilterElementData(objElement){
2078				
2079		var id = objElement.data("id");
2080		var title = objElement.data("title");
2081		var key = objElement.data("key");
2082		var type = objElement.data("type");
2083		
2084		if(!id && !key)
2085			return(null);
2086		
2087		
2088		switch(type){
2089		case "taxonomy":
2090		default:
2091			var slug = objElement.data("slug");
2092			var taxonomy = objElement.data("taxonomy");
2093			
2094			var objTerm = {
2095				"type": type,
2096				"id": id,
2097				"slug": slug,
2098				"taxonomy": taxonomy,
2099				"title": title,
2100				"key": key
2101			};
2102			return(objTerm);
2103			
2104		break;
2105		case "author":
2106			
2107			var username = objElement.data("username");
2108			
2109			var objAuthor = {
2110					"type": type,
2111					"id": id,
2112					"username": username,
2113					"title": title,
2114					"key": key
2115				};
2116				return(objAuthor);
2117			
2118		break;
2119		case "meta":
2120
2121			var slug = objElement.data("slug");
2122			var metaKey = objElement.data("metakey");
2123			var metaValue = objElement.data("metavalue");
2124			var compare = objElement.data("compare");
2125
2126			if(!metaKey)
2127				metaKey = slug;
2128
2129			if(!metaValue)
2130				metaValue = "";
2131
2132			if(!compare)
2133				compare = "=";
2134
2135			var objMeta = {
2136				"type": type,
2137				"id": id,
2138				"slug": slug,
2139				"meta_key": metaKey,
2140				"meta_value": metaValue,
2141				"compare": compare,
2142				"title": title,
2143				"key": key
2144			};
2145			return(objMeta);
2146
2147		break;
2148		}
2149		
2150	}
2151
2152
2153	function ________AJAX_CACHE_________(){}
2154
2155	/**
2156	 * get ajax url
2157	 */
2158	function getAjaxCacheKeyFromUrl(ajaxUrl){
2159
2160		var key = ajaxUrl;
2161
2162		key = key.replace(g_urlAjax, "");
2163		key = key.replace(g_urlBase, "");
2164
2165		//replace special signs
2166		key = replaceAll(key, "/","");
2167		key = replaceAll(key, "?","_");
2168		key = replaceAll(key, "&","_");
2169		key = replaceAll(key, "=","_");
2170
2171		return(key);
2172	}
2173
2174	/**
2175	 * get ajax cache key
2176	 */
2177	function getAjaxCacheKey(ajaxUrl, action, objData){
2178
2179	    if(g_options.is_cache_enabled == false)
2180	    	return(false);
2181
2182	    //cache only by url meanwhile
2183
2184	    if(jQuery.isEmptyObject(objData) == false)
2185	    	return(false);
2186
2187	    if(action)
2188	    	return(false);
2189
2190	    var cacheKey = getAjaxCacheKeyFromUrl(ajaxUrl);
2191
2192	    if(!cacheKey)
2193	    	return(false);
2194
2195	    return(cacheKey);
2196	}
2197
2198
2199	/**
2200	 * cache ajax response
2201	 */
2202	function cacheAjaxResponse(ajaxUrl, action, objData, response){
2203
2204	    var cacheKey = getAjaxCacheKey(ajaxUrl, action, objData);
2205
2206	    if(!cacheKey)
2207	    	return(false);
2208
2209	    //some precoutions for overload
2210	    if(g_cache.length > 100)
2211	    	return(false);
2212
2213	    g_cache[cacheKey] = response;
2214
2215	}
2216
2217
2218	function ________AJAX_RESPONSE_______________(){}
2219
2220	/**
2221	 * replace the grid debug
2222	 */
2223	function operateAjax_setHtmlDebug(response, objGrid){
2224
2225		//replace the debug
2226		var htmlDebug = getVal(response, "html_debug");
2227
2228		if(!htmlDebug)
2229			return(false);
2230		
2231		var gridParent = objGrid.parents("." + g_vars.class_widget_wrapper);
2232		
2233		var objDebug = gridParent.find(".uc-debug-query-wrapper");
2234
2235		if(objDebug.length == 0)
2236			return(false);
2237
2238		objDebug.replaceWith(htmlDebug);
2239	}
2240
2241
2242	/**
2243	 * set html grid from ajax response
2244	 */
2245	function operateAjax_setHtmlGrid(response, objGrid, isLoadMore){
2246		
2247		if(g_showDebug == true){
2248			trace("set html grid, response: ");
2249			trace(response);
2250
2251			trace("obj grid:");
2252			trace(objGrid);
2253		}
2254
2255		if(objGrid.length == 0)
2256			return(false);
2257		
2258		//skip set html if exists
2259		if(objGrid.data(g_vars.GRID_DATA_SKIP_HTML) === true){
2260			
2261			if(g_showDebug == true)
2262				trace("skip set html");
2263			
2264			objGrid.data(g_vars.GRID_DATA_SKIP_HTML,false);
2265			return(false);
2266		}
2267		
2268		var objItemsWrapper = getGridItemsWrapper(objGrid);
2269		var objItemsWrapper2 = getGridItemsWrapper(objGrid, true);
2270
2271		if(g_showDebug == true){
2272			trace("items wrapper 1: ");
2273			trace(objItemsWrapper);
2274
2275			trace("items wrapper 2:");
2276			trace(objItemsWrapper2);
2277		}
2278
2279
2280		if(!objItemsWrapper || objItemsWrapper.length == 0)
2281			throw new Error("Missing items wrapper: .uc-items-wrapper");
2282
2283		operateAjax_setHtmlDebug(response, objGrid);
2284
2285		//set grid items
2286
2287		//if init filters mode, and no items response - don't set
2288		if(response.hasOwnProperty("html_items") == false)
2289			return(false);
2290		
2291		var htmlItems = getVal(response, "html_items");
2292				
2293		var htmlItems2 = null;
2294
2295		if(objItemsWrapper2)
2296			htmlItems2 = getVal(response, "html_items2");
2297
2298		//replace widget id
2299		var gridID = objGrid.attr("id");
2300
2301		htmlItems = replaceAll(htmlItems, "%uc_widget_id%", gridID);
2302		
2303		if(htmlItems2)
2304			htmlItems2 = replaceAll(htmlItems2, "%uc_widget_id%", gridID);
2305
2306		var isCustomRefresh = objGrid.data("custom-sethtml");
2307
2308		//show / hide empty message if available and empty response
2309		var objEmptyMessage = getGridEmptyMessage(objGrid);
2310
2311		if(objEmptyMessage){
2312			if(htmlItems == "")
2313				objEmptyMessage.show();
2314			else
2315				objEmptyMessage.hide();
2316		}
2317
2318		//set the query data
2319		var queryDataOriginal = getVal(response, "query_data");
2320		var queryIDs = getVal(response,"query_ids");
2321
2322		var queryData = jQuery.extend({}, queryDataOriginal);
2323
2324		//add to old data
2325
2326		if(isLoadMore == true){
2327
2328			var currentQueryData = objGrid.attr("querydata");
2329
2330			var objCurrentData = jQuery.parseJSON(currentQueryData);
2331			var currentNumPosts = getVal(objCurrentData, "count_posts");
2332
2333			queryData.count_posts += currentNumPosts;
2334
2335			var currentQueryIDs = objGrid.data("postids");
2336
2337			if(queryIDs && currentQueryIDs)
2338				queryIDs = currentQueryIDs + "," + queryIDs;
2339		}
2340
2341		//query data replace
2342
2343		if(queryData){
2344
2345			objGrid.removeAttr("querydata");
2346
2347			var jsonData = JSON.stringify(queryData);
2348			objGrid.attr("querydata", jsonData);
2349
2350			objGrid.data("querydata", queryData);
2351		}
2352
2353		//post id's replace
2354
2355		objGrid.removeAttr("data-postids");
2356		objGrid.attr("data-postids", queryIDs);
2357		objGrid.data("postids", queryIDs);
2358
2359
2360		//if custom refresh - just save the new html in data
2361		if(isCustomRefresh == true){
2362
2363			objGrid.trigger(g_vars.EVENT_SET_HTML_ITEMS,[htmlItems, isLoadMore, htmlItems2]);
2364			return(false);
2365		}
2366
2367
2368		if(!htmlItems2)
2369			htmlItems2 = "";
2370
2371		if(isLoadMore === true){
2372
2373			if(g_showDebug == true){
2374				trace("append load more");
2375			}
2376
2377			objItemsWrapper.append(htmlItems);
2378
2379			if(objItemsWrapper)
2380				objItemsWrapper.append(htmlItems2);
2381
2382		}else{
2383						
2384			objItemsWrapper.html(htmlItems);
2385
2386			if(objItemsWrapper2 && objItemsWrapper2.length)
2387				objItemsWrapper2.html(htmlItems2);
2388
2389		}
2390		
2391		
2392		return(true);
2393	}
2394
2395
2396	/**
2397	 * refresh synced grids
2398	 */
2399	function operateAjax_setHtmlSyngGrids(response, objGrid, isLoadMore){
2400		
2401		var objSyncWidgetsResponse = getVal(response, "html_sync_widgets");
2402
2403		if(g_showDebug == true){
2404			trace("set html sync grids");
2405			trace(objSyncWidgetsResponse);
2406		}
2407
2408		var queryData = getVal(response,"query_data");
2409
2410		if(!objSyncWidgetsResponse){
2411			
2412			if(g_showDebug == true){
2413				trace("no sync widgets response");
2414			}
2415			
2416			return(false);
2417		}
2418		
2419		var group = objGrid.data("filtergroup");
2420		
2421		jQuery.each(objSyncWidgetsResponse, function(elementID, childResponse){
2422			
2423			var objGridWidget = getGridFromElementorElementID(elementID, group);
2424			
2425			if(!objGridWidget){
2426				
2427				if(g_showDebug == true){
2428					trace("no grid widget found: "+elementID);
2429					
2430					getGridFromElementorElementID(elementID,group,true);	//for debug
2431				}
2432				
2433				return(true);
2434			}
2435
2436			if(g_showDebug == true){
2437				trace("set sync grid!");
2438				trace(objGridWidget);
2439				trace(childResponse);
2440			}
2441			
2442			
2443			objGridWidget.removeClass(g_vars.CLASS_REFRESH_SOON);
2444			
2445			childResponse.query_data = queryData;
2446			
2447			operateAjax_setHtmlGrid(childResponse, objGridWidget, isLoadMore);
2448			
2449			objGridWidget.trigger(g_vars.EVENT_AJAX_REFRESHED);
2450			g_objBody.trigger(g_vars.EVENT_AJAX_REFRESHED_BODY, [objGridWidget]);
2451
2452		});
2453
2454	}
2455
2456
2457	/**
2458	 * replace filters html
2459	 */
2460	function operateAjax_setHtmlWidgets(response, objFilters){
2461
2462		if(!objFilters)
2463			return(false);
2464
2465		if(objFilters.length == 0)
2466			return(false);
2467
2468		var objHtmlWidgets = getVal(response, "html_widgets");
2469
2470		if(!objHtmlWidgets)
2471			return(false);
2472
2473		if(objHtmlWidgets.length == 0)
2474			return(false);
2475
2476		var objHtmlDebug = getVal(response, "html_widgets_debug");
2477
2478		jQuery.each(objFilters, function(index, objFilter){
2479
2480			var widgetID = getElementWidgetID(objFilter);
2481
2482			if(!widgetID)
2483				return(true);
2484
2485			var html = getVal(objHtmlWidgets, widgetID);
2486
2487			if(!html)
2488				return(true);
2489
2490			var objHtml = jQuery(html);
2491
2492			var htmlInner = objHtml.html();
2493
2494			//set the class
2495
2496			var filterClassName = objHtml.attr("class");
2497
2498			filterClassName += " "+g_vars.CLASS_FILTER_INITED;
2499
2500			objFilter.attr("class", filterClassName);
2501
2502			objFilter.removeClass(g_vars.CLASS_INITING);
2503			objFilter.removeClass(g_vars.CLASS_REFRESH_SOON);
2504
2505			objFilter.html(htmlInner);
2506
2507
2508
2509			//---- put the debug if exists
2510
2511			var htmlDebug = null;
2512
2513			if(objHtmlDebug)
2514				var htmlDebug = getVal(objHtmlDebug, widgetID);
2515
2516			if(htmlDebug){
2517				var objParent = objFilter.parents("." + g_vars.class_widget_wrapper);
2518				var objDebug = objParent.find(".uc-div-ajax-debug");
2519
2520				if(objDebug.length)
2521					objDebug.replaceWith(htmlDebug);
2522			}
2523			
2524			objFilter.trigger(g_vars.EVENT_FILTER_RELOADED);
2525
2526		});
2527
2528	}
2529
2530	/**
2531	 * scroll to grid top
2532	 */
2533	function scrollToGridTop(objGrid){
2534
2535		var gapTop = 150;
2536
2537		var gridOffset = objGrid.offset().top;
2538
2539		var gridTop = gridOffset - gapTop;
2540
2541		if(gridTop < 0)
2542			gridTop = 0;
2543
2544		//check if the grid top is visible
2545
2546		var currentPos = jQuery(window).scrollTop();
2547
2548		if(currentPos <= gridOffset)
2549			return(false);
2550
2551		window.scrollTo({ top: gridTop, behavior: 'smooth' });
2552
2553	}
2554
2555
2556	/**
2557	 * operate the response
2558	 */
2559	function operateAjaxRefreshResponse(response, objGrid, objFilters, isLoadMore, isNoScroll){
2560		
2561		var isGridRefreshed = operateAjax_setHtmlGrid(response, objGrid, isLoadMore);
2562		
2563		operateAjax_setHtmlWidgets(response, objFilters);
2564		
2565		operateAjax_setHtmlSyngGrids(response, objGrid, isLoadMore);
2566		
2567		objGrid.trigger(g_vars.EVENT_AJAX_REFRESHED,[{isLoadMore:isLoadMore}]);
2568		g_objBody.trigger(g_vars.EVENT_AJAX_REFRESHED_BODY, [objGrid]);
2569		
2570		//trigger body as well
2571
2572		//scroll to grid top
2573		if(isLoadMore == false && isGridRefreshed == true && isNoScroll !== true){
2574						
2575			setTimeout(function(){
2576				
2577				scrollToGridTop(objGrid);
2578					
2579			},200);
2580
2581		}
2582
2583	}
2584
2585
2586	/**
2587	 * replace all occurances
2588	 */
2589	function replaceAll(text, from, to){
2590
2591		return text.split(from).join(to);
2592	};
2593
2594
2595
2596
2597	/**
2598	 * get response from ajax cache
2599	 */
2600	function getResponseFromAjaxCache(ajaxUrl, action, objData){
2601
2602	    var cacheKey = getAjaxCacheKey(ajaxUrl, action, objData);
2603
2604	    if(!cacheKey)
2605	    	return(false);
2606
2607	    var response = getVal(g_cache, cacheKey);
2608
2609	    return(response);
2610	}
2611
2612
2613	function ________AJAX_______________(){}
2614
2615	/**
2616	 * set this filter not to refresh next time
2617	 */
2618	function setNoRefreshFilter(objFilter){
2619
2620		objFilter.data("uc_norefresh",true);
2621
2622	}
2623
2624	/**
2625	 * show ajax error, should be something visible
2626	 */
2627	function showAjaxError(message){
2628
2629		alert(message);
2630
2631	}
2632
2633	/**
2634	 * get the debug object
2635	 */
2636	function getDebugObject(){
2637
2638		var objGrid = g_lastGridAjaxCall;
2639
2640		if(!objGrid)
2641			return(null);
2642
2643		var objDebug = objGrid.find("."+g_vars.CLASS_DIV_DEBUG);
2644
2645		if(objDebug.length)
2646			return(objDebug);
2647
2648		//insert if not exists
2649
2650		objGrid.after("<div class='"+g_vars.CLASS_DIV_DEBUG+"' style='padding:10px;display:none;background-color:#D8FCC6'></div>");
2651
2652		var objDebug = jQuery("body").find("."+g_vars.CLASS_DIV_DEBUG);
2653
2654		return(objDebug);
2655	}
2656
2657
2658	/**
2659	 * show ajax debug
2660	 */
2661	function showAjaxDebug(str){
2662
2663		trace("Ajax Error! - Check the debug");
2664
2665		str = jQuery.trim(str);
2666
2667		if(!str || str.length == 0)
2668			return(false);
2669
2670		var objStr = jQuery(str);
2671
2672		if(objStr.find("header").length || objStr.find("body").length){
2673			str = "Wrong ajax response!";
2674		}
2675
2676		var objDebug = getDebugObject();
2677
2678		if(!objDebug || objDebug.length == 0){
2679
2680			alert(str);
2681
2682			throw new Error("debug not found");
2683		}
2684
2685		objDebug.show();
2686		objDebug.html(str);
2687
2688	}
2689
2690
2691	/**
2692	 * small ajax request
2693	 */
2694	function ajaxRequest(ajaxUrl, action, objData, onSuccess){
2695				
2696		if(g_debugInitMode === true){
2697
2698			trace("debug init mode - skip request");
2699			return(false);
2700		}
2701
2702		if(g_showDebug == true){
2703			trace("ajax request");
2704			trace(ajaxUrl);
2705		}
2706
2707		if(!objData)
2708			var objData = {};
2709
2710		if(typeof objData != "object")
2711			throw new Error("wrong ajax param");
2712
2713		//check response from cache
2714		var responseFromCache = getResponseFromAjaxCache(ajaxUrl, action, objData);
2715
2716		if(responseFromCache){
2717
2718			//simulate ajax request
2719			setTimeout(function(){
2720				onSuccess(responseFromCache);
2721			}, 300);
2722
2723			return(false);
2724		}
2725
2726		var ajaxData = {};
2727		ajaxData["action"] = "unlimitedelements_ajax_action";
2728		ajaxData["client_action"] = action;
2729
2730		var ajaxtype = "get";
2731
2732		if(jQuery.isEmptyObject(objData) == false){
2733			ajaxData["data"] = objData;
2734			ajaxtype = "post";
2735		}
2736
2737
2738		var ajaxOptions = {
2739				type:ajaxtype,
2740				url:ajaxUrl,
2741				success:function(response){
2742
2743					if(!response){
2744						showAjaxError("Empty ajax response!");
2745						return(false);
2746					}
2747
2748					if(typeof response != "object"){
2749
2750						try{
2751
2752							response = jQuery.parseJSON(response);
2753
2754						}catch(e){
2755
2756							showAjaxDebug(response);
2757
2758							showAjaxError("Ajax Error!!! not ajax response");
2759							return(false);
2760						}
2761					}
2762
2763					if(response == -1){
2764						showAjaxError("ajax error!!!");
2765						return(false);
2766					}
2767
2768					if(response == 0){
2769						showAjaxError("ajax error, action: <b>"+action+"</b> not found");
2770						return(false);
2771					}
2772
2773					if(response.success == undefined){
2774						showAjaxError("The 'success' param is a must!");
2775						return(false);
2776					}
2777
2778
2779					if(response.success == false){
2780						showAjaxError(response.message);
2781						return(false);
2782					}
2783
2784					cacheAjaxResponse(ajaxUrl, action, objData, response);
2785
2786					if(typeof onSuccess == "function"){
2787
2788						onSuccess(response);
2789					}
2790
2791				},
2792				error:function(jqXHR, textStatus, errorThrown){
2793
2794					switch(textStatus){
2795						case "parsererror":
2796						case "error":
2797
2798							//showAjaxError("parse error");
2799
2800							showAjaxDebug(jqXHR.responseText);
2801
2802						break;
2803					}
2804				}
2805		}
2806
2807		if(ajaxtype == "post"){
2808			ajaxOptions.dataType = 'json';
2809			ajaxOptions.data = ajaxData
2810		}
2811
2812		var handle = jQuery.ajax(ajaxOptions);
2813
2814		return(handle);
2815	}
2816
2817
2818
2819	/**
2820	 * get grid items wrapper
2821	 */
2822	function getGridItemsWrapper(objGrid, isSecond){
2823
2824		var classItems = "uc-items-wrapper";
2825
2826		if(isSecond == true)
2827			classItems = "uc-items-wrapper2";
2828
2829		if(objGrid.hasClass(classItems))
2830			return(objGrid);
2831
2832		var objItemsWrapper = objGrid.find("."+classItems);
2833
2834		if(objItemsWrapper.length == 0 && isSecond == false)
2835			throw new Error("Missing items wrapper - with class: uc-items-wrapper");
2836
2837		if(objItemsWrapper.length == 0)
2838			return(null);
2839
2840		return(objItemsWrapper);
2841	}
2842
2843
2844	/**
2845	 * set ajax loader
2846	 */
2847	function showAjaxLoader(objElement){
2848
2849		objElement.addClass("uc-ajax-loading");
2850	}
2851
2852	/**
2853	 * hide ajax loader
2854	 */
2855	function hideAjaxLoader(objElement){
2856
2857		objElement.removeClass("uc-ajax-loading");
2858	}
2859
2860
2861	/**
2862	 * show multiple ajax loader
2863	 */
2864	function showMultipleAjaxLoaders(objElements, isShow){
2865
2866		if(!objElements)
2867			return(false);
2868
2869		if(objElements.length == 0)
2870			return(false);
2871
2872		jQuery.each(objElements,function(index, objElement){
2873
2874			objElement = jQuery(objElement);
2875
2876			if(isShow == true){
2877
2878				showAjaxLoader(objElement);
2879			}
2880			else
2881				hideAjaxLoader(objElement);
2882		});
2883
2884	}
2885
2886
2887	/**
2888	 * refresh ajax grid
2889	 */
2890	function refreshAjaxGrid(objGrid, refreshType){
2891				
2892		var isLoadMore = (refreshType == g_vars.REFRESH_MODE_LOADMORE);	 //for the output
2893		var isFiltersInit = (refreshType == "filters" || refreshType == "filters_children");
2894		
2895		//for the options - not refresh other filters
2896		var isLoadMoreMode = (refreshType == g_vars.REFRESH_MODE_LOADMORE || refreshType == g_vars.REFRESH_MODE_PAGINATION);
2897		
2898		//get all grid filters
2899		var objFilters = objGrid.data("filters");
2900
2901		if(!objFilters)
2902			return(false);
2903
2904		if(objFilters.length == 0)
2905			return(false);
2906
2907		if(objGrid.hasClass(g_vars.CLASS_GRID_NOREFRESH))
2908			return(false);
2909
2910		var params = {};
2911		if(refreshType == "filters_children")
2912			params["filters_init_type"] = "children";
2913		
2914		params["refresh_type"] = refreshType;
2915		
2916		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid, isFiltersInit, isLoadMoreMode, params);
2917		
2918		if(!objAjaxOptions){
2919
2920			trace("ajax options are null");
2921			return(false);
2922		}
2923
2924		var ajaxUrl = objAjaxOptions["ajax_url"];
2925		var urlReplace = objAjaxOptions["url_replace"];
2926		var arrTerms = objAjaxOptions["terms"];
2927
2928		if(g_vars.DEBUG_AJAX_OPTIONS == true){
2929
2930			trace("DEBUG AJAX OPTIONS");
2931			trace(objAjaxOptions);
2932			return(false);
2933		}
2934
2935		//set the url params
2936		var behave = objGrid.data("filterbehave");
2937
2938		var isSetUrl = (behave == "mixed" || behave == "mixed_back");
2939
2940		if(isFiltersInit == false && isSetUrl === true){
2941			
2942			try{
2943				
2944				if(behave == "mixed_back"){
2945	
2946					//save state for back button
2947	
2948					var gridID = objGrid.attr("id");
2949	
2950					//save initial state
2951					var isStateEmpty = jQuery.isEmptyObject(history.state);
2952					
2953					var objState = {"ucaction":"change", "ajaxurl":ajaxUrl, "gridid":gridID, selected_terms:arrTerms};
2954	
2955					if(isStateEmpty){
2956	
2957						var ajaxUrlInitial = objGrid.data("initajaxurl");
2958	
2959						objState["ajaxurl"] = ajaxUrlInitial;
2960	
2961						history.replaceState(objState, null, urlReplace);
2962					}
2963	
2964					history.pushState(objState, null, urlReplace);		//with back
2965	
2966				}
2967				else
2968					history.replaceState({}, null, urlReplace);		//without back
2969			
2970			}catch(error){
2971				trace("history push state error");
2972				trace(error);
2973			}
2974		}
2975		
2976		
2977		initGrid_setActiveFiltersData(objGrid, objAjaxOptions);
2978		
2979		doGridAjaxRequest(ajaxUrl, objGrid, objFilters, isLoadMore, isFiltersInit);
2980
2981	}
2982
2983
2984	/**
2985	 * do the actual grid ajax request
2986	 */
2987	function doGridAjaxRequest(ajaxUrl, objGrid, objFilters, isLoadMore, isFiltersInit){
2988		
2989		var objEmptyMessage = getGridEmptyMessage(objGrid);
2990
2991		//set the loaders
2992
2993		if(isLoadMore !== true && isFiltersInit !== true){
2994
2995			showAjaxLoader(objGrid);
2996
2997			if(objEmptyMessage)
2998				showAjaxLoader(objEmptyMessage);
2999		}
3000
3001		var objFiltersToReload = objFilters.filter(function(objFilter){
3002
3003			return objFilter.hasClass(g_vars.CLASS_REFRESH_SOON);
3004		});
3005
3006		showMultipleAjaxLoaders(objFiltersToReload, true);
3007
3008		if(g_lastSyncGrids && isLoadMore !== true){
3009
3010			showMultipleAjaxLoaders(g_lastSyncGrids, true);
3011		}
3012
3013		//ajax reload
3014		g_lastGridAjaxCall = objGrid;
3015		
3016		objGrid.trigger(g_vars.EVENT_BEFORE_REFRESH);
3017		
3018		var lastAjaxHandle = objGrid.data("last_ajax_refresh_handle");
3019
3020		if(lastAjaxHandle){
3021			lastAjaxHandle.abort();
3022		}
3023		
3024		//--- debug before refresh
3025		
3026		if(g_debugBeforeRefreshMode == true){
3027			
3028			alert("Debug before refresh - please turn if off");
3029			return(false);
3030		}
3031		
3032		var ajaxHandle = ajaxRequest(ajaxUrl,null,null, function(response){
3033
3034			if(isLoadMore !== true){
3035				hideAjaxLoader(objGrid);
3036
3037				if(objEmptyMessage)
3038					hideAjaxLoader(objEmptyMessage);
3039			}
3040
3041			showMultipleAjaxLoaders(objFilters, false);
3042
3043			if(g_lastSyncGrids)
3044				showMultipleAjaxLoaders(g_lastSyncGrids, false);
3045			
3046			operateAjaxRefreshResponse(response, objGrid, objFilters, isLoadMore);
3047
3048			onAfterGridRefresh(objGrid);
3049
3050		});
3051
3052		objGrid.data("last_ajax_refresh_handle", ajaxHandle);
3053
3054	}
3055
3056	/**
3057	 * do some actions after grid refresh, if needed
3058	 */
3059	function onAfterGridRefresh(objGrid){
3060
3061		//refresh child grids
3062
3063		var isInitRefesh = objGrid.data("init_refresh_child_filters");
3064
3065		if(isInitRefesh === true){
3066
3067			objGrid.removeData("init_refresh_child_filters");
3068
3069			//refresh child filters if there are selected main after init
3070
3071			var objFilters = objGrid.data("filters");
3072
3073			var arrSelectedMain = getSelectedFilters(objFilters, "main");
3074
3075			if(arrSelectedMain.length)
3076				refreshAjaxGrid(objGrid, "filters_children");
3077		}
3078
3079	}
3080
3081
3082	function ________STATE_RELATED_______________(){}
3083
3084
3085	/**
3086	 * do history
3087	 */
3088	function changeToHistoryState(state){
3089
3090		if(g_showDebug == true){
3091			trace("change to history");
3092			trace(state);
3093		}
3094
3095		var ajaxUrl = getVal(state, "ajaxurl");
3096
3097		var gridID = getVal(state, "gridid");
3098
3099		var arrTerms = getVal(state, "selected_terms");
3100
3101		if(!gridID)
3102			return(false);
3103
3104		if(!ajaxUrl)
3105			return(false);
3106
3107		var objGrid = jQuery("#"+gridID);
3108
3109		var objFilters = objGrid.data("filters");
3110
3111		if(!objFilters)
3112			return(false);
3113
3114		//select by terms
3115
3116		selectFilterItemsByTerms(objFilters, arrTerms);
3117
3118		var responseFromCache = getResponseFromAjaxCache(ajaxUrl);
3119
3120		if(!responseFromCache){
3121
3122			//do ajax request
3123
3124			doGridAjaxRequest(ajaxUrl, objGrid, objFilters);
3125
3126			return(false);
3127		}
3128
3129		//get data from cache
3130
3131		//trace("restore");
3132		//trace(responseFromCache);
3133
3134		operateAjaxRefreshResponse(responseFromCache, objGrid, objFilters, false, true);
3135
3136	}
3137
3138	/**
3139	 * on pop state, if it's a grid state, set the grid
3140	 */
3141	function onPopState(){
3142
3143		if(!history.state)
3144			return(true);
3145
3146		var action = getVal(history.state, "ucaction");
3147
3148		if(!action)
3149			return(true);
3150
3151		switch(action){
3152			case "change":
3153
3154				changeToHistoryState(history.state);
3155
3156			break;
3157			default:
3158				throw new Error("Wrong history action: " + action);
3159			break;
3160		}
3161
3162	}
3163
3164
3165	function ________RUN_______________(){}
3166
3167
3168	/**
3169	 * get url filters string
3170	 */
3171	function getGridUrlFiltersString(objGrid){
3172
3173		var objAjaxOptions = getGridAjaxOptions_simple(objGrid);
3174
3175		if(!objAjaxOptions)
3176			return("");
3177
3178		var strFilters = getVal(objAjaxOptions, "filters_string");
3179		
3180		return(strFilters);
3181	}
3182
3183
3184	/**
3185	 * get simply the grid ajax options
3186	 */
3187	function getGridAjaxOptions_simple(objGrid){
3188
3189		var objFilters = objGrid.data("filters");
3190		
3191		if(!objFilters)
3192			return(null);
3193		
3194		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid, false,false,{getonly:true});
3195
3196		if(!objAjaxOptions)
3197			return(null);
3198
3199		return(objAjaxOptions);
3200	}
3201	
3202	/**
3203	 * check that element is hidden only by display:none. ":hidden" checks width and height as well
3204	 */
3205	function isElementHiddenByDisplayNone(objElement) {
3206	    	    
3207		var element = objElement[0];
3208		
3209		var hidden = window.getComputedStyle(element).display == "none";
3210		
3211	    return hidden;
3212	};	
3213
3214	/**
3215	* get operator term
3216	*/
3217	function getObjOperatorTerm(operator, dataTerms){
3218		var slug = (operator == "and")?"__ucand__":"__ucor__";
3219		var firstTerm = dataTerms[0];        
3220		var objOperatorTerm = {
3221			taxonomy: firstTerm.taxonomy,
3222			slug: slug,
3223			id:null
3224		};
3225		
3226		return(objOperatorTerm);
3227	}
3228
3229	/**
3230	 * get operator marker for meta items (same as terms __ucand__/__ucor__)
3231	 */
3232	function getObjOperatorMeta(operator, dataMeta){
3233
3234		var opValue = (operator == "and") ? "__ucand__" : "__ucor__";
3235		var firstMeta = dataMeta[0];
3236		var metaKey = getVal(firstMeta, "meta_key");
3237
3238		if(!metaKey)
3239			metaKey = getVal(firstMeta, "slug");
3240
3241		return({
3242			type: "meta",
3243			meta_key: metaKey,
3244			meta_value: opValue,
3245			compare: getVal(firstMeta, "compare", "="),
3246			slug: opValue,
3247			id: null
3248		});
3249	}
3250
3251	/**
3252	 * get grid ajax options
3253	 */
3254	function getGridAjaxOptions(objFilters, objGrid, isFiltersInitMode, isLoadMoreMode, params){
3255		
3256		if(!isLoadMoreMode)
3257			var isLoadMoreMode = false;
3258		
3259		if(g_showDebug){
3260			trace("getGridAjaxOptions");
3261
3262			trace("Filters:");
3263			trace(objFilters);
3264			
3265			trace("grid:");
3266			trace(objGrid);
3267			trace("is init: " + isFiltersInitMode);
3268
3269			trace("params: ");
3270			trace(params);
3271
3272		}
3273
3274		//filter only visible elements (by it's parents)
3275		
3276		var objVisibleFilters = objFilters.filter(function(objFilter){
3277			
3278			var objParent = getFilterWrapper(objFilter);
3279			
3280			var isHidden = isElementHiddenByDisplayNone(objParent);
3281			
3282			return(!isHidden);
3283		});
3284		
3285		
3286		if(objVisibleFilters.length < objFilters.length){
3287			
3288			if(objVisibleFilters.length == 0){
3289				
3290				if(g_showDebug)
3291					trace("no visible filters");
3292				
3293				var objFilters = [];
3294			}
3295			else{		//test for mobile drawer
3296				
3297				var objFirstFilter = jQuery(objVisibleFilters[0]);
3298				var visibleFilterType = getFilterType(objFirstFilter, true);
3299				
3300				//exception for mobile drawer
3301				if(visibleFilterType !=  g_types.GENERAL_MOBILE_DRAWER){
3302					
3303					var objFilters = objVisibleFilters;
3304					
3305					if(g_showDebug){
3306						trace("Visible Filters: ");
3307						trace(objFilters);
3308					}
3309				}
3310				
3311			}//end else
3312			
3313			
3314		} //end visible filters test
3315		
3316		
3317		if(!objFilters || objFilters.length == 0)
3318			return(null);
3319
3320		var urlReplace = g_urlBase;
3321
3322		var urlAjax = g_urlBase;
3323
3324		var strRefreshIDs = "";
3325
3326		var isReplaceMode = false;
3327		var page = null;
3328		var offset = null;
3329		var numItems = null;
3330		var arrTerms = [];
3331		var objTaxIDs = {};
3332		var objAuthorIDs = {};
3333		var strSelectedTerms = "";
3334		var strSelectedAuthors = "";
3335		var strSelectedMeta = "";
3336		var search = "";
3337		var price_from, price_to;
3338		var arrAuthors = [];
3339		var arrMeta = [];
3340		var orderby = null;
3341		var orderby_metaname = null;
3342		var orderby_metatype = null;
3343		var orderdir = null;
3344		var title_start = null;
3345		var addSyncedGrids = true;
3346		var arrAllFiltersData;		//all data gethered for the active filters
3347		var arrFiltersForInit = [];
3348		var urlAddFromFilters = "";
3349		var isPaginationClicked = false;
3350		var isGetUrlOnly = getVal(params,"getonly");
3351
3352		var initModeType = getVal(params,"filters_init_type");
3353
3354		var initModeChildrens = false;
3355		if(isFiltersInitMode == true && initModeType == "children")
3356			initModeChildrens = true;
3357
3358		var wasInitMode = objGrid.data("was_init_mode");
3359
3360		var arrFilterIDs = {};
3361		
3362		var advancedSearchFilterID;
3363		
3364		var refreshType = getVal(params,"refresh_type");
3365		
3366		if(refreshType == g_vars.REFRESH_MODE_PAGINATION)
3367			isPaginationClicked = true;
3368
3369		var child_auto, childAutoTaxonomy, childAutoSlug, childAutoString = "";
3370				
3371		//get ajax options
3372		jQuery.each(objFilters, function(index, objFilter){
3373			
3374			//protection against duplicate id's
3375			var id = objFilter.attr("id");
3376
3377			if(arrFilterIDs.hasOwnProperty(id) == true){
3378
3379				trace("problematic filter: ");
3380				trace(objFilter);
3381
3382				trace("original filter found: ");
3383				trace(arrFilterIDs[id]);
3384
3385				trace("filters list: ");
3386				trace(objFilters);
3387
3388				throw new Error("Duplicate Filter ID found: " + id);
3389			}
3390						
3391			arrFilterIDs[id] = objFilter;
3392
3393			var isNoRefresh = objFilter.data("uc_norefresh");
3394			var filterRole = objFilter.data("role");
3395						
3396			var type = getFilterType(objFilter);
3397			
3398			if(g_showDebug == true){
3399
3400				trace("filter: "+type+", role: "+filterRole);
3401				trace(objFilter);
3402			}
3403
3404			var urlAdd = objFilter.attr(g_vars.ATTRIBUTE_URLADD);
3405
3406			if(urlAdd)
3407				urlAddFromFilters = addUrlParam(urlAddFromFilters, urlAdd);
3408			
3409			switch(type){
3410				case g_types.PAGINATION:
3411						
3412						//run pagination only if it's clicked, unless reset pagination
3413						var isClicked = objFilter.hasClass(g_vars.CLASS_CLICKED);
3414						if(isClicked == true || isFiltersInitMode == true){
3415
3416							 var paginationData = getPaginationSelectedData(objFilter);
3417							 
3418							 var paginationPage = getVal(paginationData, "page");
3419							 
3420							 if(paginationPage)
3421								 page = paginationPage;		//never set the url
3422							 
3423							 //set page from url
3424							 if(isFiltersInitMode == true && !page && g_vars.ucpage_url)
3425								 page = g_vars.ucpage_url;
3426							
3427							 if(g_showDebug){
3428								 trace("pagination data");
3429								 trace(paginationData);
3430							 }
3431
3432							objFilter.removeClass(g_vars.CLASS_CLICKED);
3433						}
3434						
3435
3436				break;
3437				case g_types.LOADMORE:
3438
3439					//check if loadmore is before grid in init mode
3440					var isLoadMoreBeforeGrid = false;
3441					if(isFiltersInitMode == true){
3442						var offsetLoadMore = objFilter.offset();
3443						var offsetGrid = objGrid.offset();
3444						
3445						if(offsetLoadMore.top < offsetGrid.top){
3446							isLoadMoreBeforeGrid = true;
3447							
3448							if(g_showDebug == true)
3449								trace("Loadmore before grid - process in init mode");
3450						}
3451					}
3452					
3453					if(isFiltersInitMode == true && isLoadMoreBeforeGrid == false)
3454						return(true);
3455
3456					//run load more only if it's clicked, unless reset load more
3457					var isClicked = objFilter.hasClass(g_vars.CLASS_CLICKED);
3458					if(isClicked == true){
3459
3460						var loadMoreData = getLoadMoreUrlData(objFilter);
3461						offset = loadMoreData.offset;
3462						numItems = loadMoreData.numItems;
3463
3464						var isSingleGrid = loadMoreData.singlegrid;
3465
3466						if(isSingleGrid == true)
3467							addSyncedGrids = false;
3468
3469						if(!offset)
3470							urlAjax = null;
3471
3472						objFilter.removeClass(g_vars.CLASS_CLICKED);
3473					}
3474
3475				break;
3476				case g_types.TERMS_LIST:
3477				case g_types.SELECT:
3478
3479					//if not init mode - take first item
3480					var objTerm = getTermsListSelectedTerm(objFilter);
3481					var filterSource = objFilter.data("filtersource");
3482										
3483					if(objTerm){
3484						
3485						if(isFiltersInitMode == false){
3486							
3487							if(filterSource == "authors")
3488								arrAuthors.push(objTerm);
3489							else if(filterSource == "meta")
3490								arrMeta.push(objTerm);
3491							else
3492								arrTerms.push(objTerm);
3493						}
3494						else{
3495							
3496							//INIT MODE
3497							
3498							//add terms if the filter is not initing itself
3499							var isInit = objFilter.data("initafter");
3500							
3501							//add terms, if only children mode and the filter not child
3502							if(initModeChildrens == true && filterRole != "child")
3503								arrTerms.push(objTerm);
3504							else
3505								if(isInit != true){
3506									
3507									if(filterSource == "authors")
3508										arrAuthors.push(objTerm);
3509									else if(filterSource == "meta")
3510										arrMeta.push(objTerm);
3511									else
3512										arrTerms.push(objTerm);
3513									
3514								}
3515							
3516							//set selected terms string
3517							
3518							var termID = objTerm.id;
3519							
3520							if(filterSource == "authors"){
3521								
3522								if(strSelectedAuthors)
3523									strSelectedAuthors +=",";
3524								
3525								strSelectedAuthors += termID;
3526							}
3527							else if(filterSource == "meta"){
3528
3529								var metaPair = getMetaSelectedPair(objTerm);
3530
3531								if(metaPair){
3532									if(strSelectedMeta)
3533										strSelectedMeta +=",";
3534
3535									strSelectedMeta += metaPair;
3536								}
3537							}
3538							else{
3539								if(strSelectedTerms)
3540									strSelectedTerms +=",";
3541								
3542								strSelectedTerms += termID;
3543							}
3544							
3545						}
3546					}
3547
3548					//replace mode
3549
3550					var modeReplace = objFilter.data("replace-mode");
3551					if(modeReplace === true)
3552						isReplaceMode = true;
3553
3554					if(isLoadMoreMode == true)
3555						isNoRefresh = true;
3556
3557					//debug
3558					if(g_showDebug == true){
3559
3560						trace("Selected Term: ");
3561						trace(objTerm);
3562					}
3563
3564				break;
3565				case g_types.SUMMARY:
3566
3567					isNoRefresh = true;
3568
3569					//take nothing
3570				break;
3571				case g_types.SEARCH:
3572
3573					isNoRefresh = true;
3574
3575					var objInput = objFilter.find("input");
3576
3577					search = objInput.val();
3578					search = search.trim();
3579					
3580					//add id
3581					var isAdvancedSearch = objFilter.data("advancedsearch");
3582					
3583					if(isAdvancedSearch == true)
3584						advancedSearchFilterID = getElementWidgetID(objFilter);
3585										
3586				break;
3587				case g_types.GENERAL:
3588					
3589					var generalType = objFilter.data("generaltype");
3590				
3591					if(generalType == g_types.GENERAL_MOBILE_DRAWER)
3592						return(true);
3593					
3594					var generalIsNoRefresh = objFilter.data("norefresh");
3595					
3596					if(generalIsNoRefresh === true)
3597						isNoRefresh = true;
3598					
3599					var filterData = getGeneralFilterData(objFilter);
3600					
3601					//add terms
3602					
3603					var dataTerms = getVal(filterData,"terms");
3604										
3605					if(dataTerms && dataTerms.length){	
3606
3607						var isOperatoeAdded = false;
3608
3609						if(filterRole == "main"){
3610							
3611							var operator = getVal(filterData,"operator");
3612										
3613							if(operator === "and" || operator === "or"){									
3614								var objOperatorTerm = getObjOperatorTerm(operator, dataTerms);
3615						
3616								dataTerms.push(objOperatorTerm);	
3617								isOperatoeAdded = true;
3618							}
3619						}
3620
3621						if(dataTerms.length == 1){		//single term			
3622						  arrTerms.push(dataTerms[0]);
3623						}
3624						
3625						if(dataTerms.length > 1){	//multiple terms
3626							//push the end or or operator
3627							var operator = getVal(filterData,"operator");
3628									
3629							if(isOperatoeAdded == false){
3630
3631								if(operator === "and" || operator === "or"){								
3632									var objOperatorTerm = getObjOperatorTerm(operator, dataTerms);
3633		
3634									dataTerms.push(objOperatorTerm);
3635								}
3636							}
3637							
3638							arrTerms.push(dataTerms);	//multiple (grouping)
3639						}
3640						
3641						
3642						//set selected terms string if init mode
3643						
3644						if(isFiltersInitMode == true && dataTerms && dataTerms.length){
3645							
3646							var arrTermsForSelect = [];
3647							
3648							if(jQuery.isArray(arrTerms))
3649								arrTermsForSelect = arrTerms.flat();
3650							
3651							jQuery.each(arrTermsForSelect, function(index, term){
3652								
3653								var termID = getVal(term,"id");
3654								
3655								if(!termID)
3656									return(true);
3657								
3658								if(strSelectedTerms)
3659									strSelectedTerms +=",";
3660								
3661								strSelectedTerms += termID;
3662							});
3663							
3664						}
3665					}
3666					
3667					//add authors
3668					var dataAuthors = getVal(filterData,"authors");
3669					
3670					if(dataAuthors && dataAuthors.length){
3671						
3672						//gather authors list
3673						jQuery.each(dataAuthors, function(index, author){
3674							arrAuthors.push(author);
3675						});
3676						
3677						//set selected authors string if init mode
3678						
3679						if(isFiltersInitMode == true){
3680							
3681							jQuery.each(dataAuthors, function(index, author){
3682								
3683								var authorID = getVal(author,"id");
3684								
3685								if(!authorID)
3686									return(true);
3687								
3688								if(strSelectedAuthors)
3689									strSelectedAuthors +=",";
3690								
3691								strSelectedAuthors += authorID;
3692							});
3693							
3694						}
3695					}
3696
3697					//add meta - same grouping as terms (checkbox OR = group, no .*)
3698					var dataMeta = getVal(filterData,"meta");
3699
3700					if(dataMeta && dataMeta.length){
3701
3702						var isMetaOperatorAdded = false;
3703
3704						if(filterRole == "main"){
3705
3706							var metaOperator = getVal(filterData,"operator");
3707
3708							if(metaOperator === "and" || metaOperator === "or"){
3709								dataMeta.push(getObjOperatorMeta(metaOperator, dataMeta));
3710								isMetaOperatorAdded = true;
3711							}
3712						}
3713
3714						if(dataMeta.length == 1){
3715							arrMeta.push(dataMeta[0]);
3716						}
3717
3718						if(dataMeta.length > 1){
3719
3720							var metaOperator = getVal(filterData,"operator");
3721
3722							if(isMetaOperatorAdded == false){
3723
3724								if(metaOperator === "and" || metaOperator === "or")
3725									dataMeta.push(getObjOperatorMeta(metaOperator, dataMeta));
3726							}
3727
3728							arrMeta.push(dataMeta);	//multiple (grouping) - OR by default
3729						}
3730
3731						if(isFiltersInitMode == true){
3732
3733							jQuery.each(dataMeta, function(index, metaItem){
3734
3735								var metaValue = getVal(metaItem,"meta_value");
3736
3737								if(metaValue === "__ucand__" || metaValue === "__ucor__")
3738									return(true);
3739
3740								var metaPair = getMetaSelectedPair(metaItem);
3741
3742								if(!metaPair)
3743									return(true);
3744
3745								if(strSelectedMeta)
3746									strSelectedMeta +=",";
3747
3748								strSelectedMeta += metaPair;
3749							});
3750
3751						}
3752					}
3753					
3754					
3755					if(g_showDebug == true){
3756						trace("Filter Data:");
3757						trace(filterData);
3758					}
3759					
3760					if(generalType == "price" && isFiltersInitMode == false){
3761						
3762						var priceFromArg = getVal(filterData,"price_from");
3763						var priceToArg = getVal(filterData,"price_to");
3764
3765						if(priceFromArg)
3766							price_from = roundToOneDecimal(priceFromArg);
3767
3768						if(priceToArg)
3769							price_to = roundToOneDecimal(priceToArg);
3770					}
3771					
3772					
3773					//add title start
3774					
3775					var titleStartArg = getVal(filterData, "title_start");
3776					if(titleStartArg)
3777						title_start = titleStartArg;
3778					
3779					//handle sort
3780					var argOrderby = getVal(filterData,"orderby");
3781					if(argOrderby && argOrderby != "default"){
3782						orderby = argOrderby;
3783
3784						orderby_metaname = getVal(filterData,"metaname");
3785						orderby_metatype = getVal(filterData,"metatype");
3786					}
3787
3788					var argOrderDir = getVal(filterData,"orderdir");
3789					if(argOrderDir && argOrderDir != "default")
3790						orderdir = argOrderDir;
3791
3792					if(isLoadMoreMode == true)
3793						isNoRefresh = true;
3794					
3795				break;
3796				default:
3797					throw new Error("Unknown filter type: "+type);
3798				break;
3799			}
3800
3801			
3802			//handle filters init mode
3803			
3804			if(isFiltersInitMode == true){
3805								
3806				var isInit = objFilter.data("initafter");
3807
3808					
3809				if(isInit != true){
3810					isNoRefresh = true;
3811				}
3812
3813				//refresh parents only
3814				if(initModeChildrens == false && filterRole == "child")
3815					isNoRefresh = true;
3816
3817				//refresh children only
3818				if(initModeChildrens == true && filterRole != "child")
3819					isNoRefresh = true;
3820				
3821				if(isNoRefresh == false){
3822					arrFiltersForInit.push(objFilter);					
3823				}
3824								
3825			}
3826			
3827			
3828			//if hidden - no refresh
3829			
3830			var isFilterHidden = objFilter.hasClass(g_vars.CLASS_HIDDEN);
3831			if(isFilterHidden == true)
3832				isNoRefresh = true;
3833			
3834			objFilter.data("uc_norefresh",false);
3835			
3836			var isMainFilter = (filterRole == "main");
3837			var isTermChild = (filterRole == "term_child");
3838			
3839			//add to refresh filter if it's qualify
3840
3841			var isRefresh = true;
3842			
3843			if(isFiltersInitMode == false && (isMainFilter === true || isTermChild == true))
3844				isRefresh = false;
3845
3846			if(isNoRefresh === true)
3847				isRefresh = false;
3848						
3849			if(g_showDebug == true){
3850				trace("Filter Refresh: "+isRefresh);
3851				if(isRefresh == true){
3852					trace("isFiltersInitMode: "+isFiltersInitMode);
3853					trace("isMainFilter: "+isMainFilter);
3854					trace("isTermChild: "+isTermChild);
3855					trace("isNoRefresh: "+isNoRefresh);
3856				}
3857			}
3858			
3859			if(isRefresh == true){
3860
3861				var filterWidgetID = getElementWidgetID(objFilter);
3862
3863				//add test tax id's for init mode
3864				var filterSource = objFilter.data("filtersource");
3865				if(filterSource == "authors" && isFiltersInitMode == true){
3866					//add test author id's for init mode
3867					objAuthorIDs = getFilterTaxIDs(objFilter, objAuthorIDs);
3868				}else{
3869					objTaxIDs = getFilterTaxIDs(objFilter, objTaxIDs);
3870				}
3871
3872				if(strRefreshIDs)
3873					strRefreshIDs += ",";
3874
3875				strRefreshIDs += filterWidgetID;
3876
3877				if(!isGetUrlOnly)
3878					objFilter.addClass(g_vars.CLASS_REFRESH_SOON);
3879			}
3880			
3881			if(filterRole == "main"){
3882				var objTerm = getTermsListSelectedTerm(objFilter);
3883
3884				if(objTerm && objTerm != null){
3885
3886					childAutoTaxonomy = objTerm.taxonomy;
3887					childAutoSlug = objTerm.slug;
3888				}
3889			}
3890			
3891			if(filterRole == "child_auto" && arrTerms.length){
3892				child_auto = true;
3893
3894				if(childAutoTaxonomy && childAutoSlug){
3895					childAutoString = "&ucmainterm=" + childAutoTaxonomy + ":" + childAutoSlug;
3896				}
3897			
3898			}
3899
3900
3901		});		//end filters iteration
3902
3903		
3904		//add init filters additions
3905
3906		var urlAddition_filtersTest = "";
3907		var strTaxIDs = getTermDsList(objTaxIDs);
3908		var strAuthorIDs = getTermDsList(objAuthorIDs);
3909				
3910		if(isFiltersInitMode == true){
3911
3912			if(!strTaxIDs && !strAuthorIDs && arrFiltersForInit.length == 0)
3913				urlAjax = null;
3914			else{
3915
3916				if(urlAddition_filtersTest)
3917					urlAddition_filtersTest += "&";
3918				
3919				urlAddition_filtersTest += "modeinit=true";
3920			}
3921		}
3922
3923		//test terms - only if there are terms in query, or mode init
3924				
3925		if(strTaxIDs && (search || arrTerms.length || isFiltersInitMode == true || wasInitMode === true) ){
3926			 
3927			if(urlAddition_filtersTest)
3928				urlAddition_filtersTest += "&";
3929			
3930			urlAddition_filtersTest += "testtermids="+strTaxIDs;
3931		}
3932		
3933		//test authors - only if there are authors in query, or mode init (author mode)
3934		if(strAuthorIDs && (search || arrAuthors.length || isFiltersInitMode == true || wasInitMode === true) ){
3935			
3936			if(urlAddition_filtersTest)
3937				urlAddition_filtersTest += "&";
3938			
3939			urlAddition_filtersTest += "testauthorids="+strAuthorIDs;
3940		}
3941
3942		g_lastSyncGrids = null;
3943
3944		if(urlAjax == null)
3945			return(null);
3946
3947		var dataLayout = getElementLayoutData(objGrid, addSyncedGrids);
3948
3949		var widgetID = dataLayout["widgetid"];
3950		var layoutID = dataLayout["layoutid"];
3951
3952		//disable synced
3953
3954		if(addSyncedGrids == false){
3955
3956			var syncedWidgetIDs = false;
3957			g_lastSyncGrids = null;
3958
3959		}else{
3960
3961			var syncedWidgetIDs = getVal(dataLayout,"synced_widgetids");
3962			g_lastSyncGrids = getVal(dataLayout,"synced_grids");
3963		}
3964		
3965		var urlFilterString = "";
3966		
3967		var urlAddition = "ucfrontajaxaction=getfiltersdata&layoutid="+layoutID+"&elid="+widgetID;
3968		
3969		urlAjax = addUrlParam(urlAjax, urlAddition);
3970		
3971		if(g_isGutenberg == true)
3972			urlAjax = addUrlParam(urlAjax, "platform=gutenberg");
3973
3974		if(syncedWidgetIDs)
3975			urlAjax += "&syncelids="+syncedWidgetIDs;
3976
3977		if(urlAddition_filtersTest)
3978			urlAjax = addUrlParam(urlAjax, urlAddition_filtersTest);
3979
3980		if(price_from){
3981			urlAjax += "&ucpricefrom="+price_from;
3982
3983			if(g_showDebug == true){
3984				trace("add price from");
3985				trace(urlAjax);
3986			}
3987		}
3988
3989		if(price_to){
3990			urlAjax += "&ucpriceto="+price_to;
3991
3992			if(g_showDebug == true){
3993				trace("add price to");
3994				trace(urlAjax);
3995			}
3996		}
3997		
3998		if(title_start){
3999			
4000			if(g_showDebug == true)
4001				trace("add title start: "+title_start);
4002			
4003			urlAjax += "&titlestart="+title_start;
4004			urlReplace = addUrlParam(urlReplace, "titlestart="+title_start);
4005		}
4006			
4007		
4008		if(page){
4009			urlAjax += "&ucpage="+page;
4010			
4011			urlReplace = addUrlParam(urlReplace, "ucpage="+page);
4012		}
4013
4014		if(numItems)
4015			urlAjax += "&uccount="+numItems;
4016				
4017		if(arrTerms.length){
4018			
4019			var strTerms = buildTermsQuery(arrTerms);
4020		
4021			if(strTerms){
4022				urlAjax += "&ucterms="+strTerms;
4023				//set the url params as well
4024				urlReplace = addUrlParam(urlReplace, "ucterms="+strTerms);
4025				urlFilterString = addUrlParam(urlFilterString, "ucterms="+strTerms);
4026			}
4027			
4028		}
4029		
4030		//add authors
4031		if(arrAuthors.length){
4032			
4033			var strAuthors = "";
4034			jQuery.each(arrAuthors, function(index, author){
4035				var authorID = getVal(author, "id");
4036				if(authorID){
4037					if(strAuthors)
4038						strAuthors += ",";
4039					strAuthors += authorID;
4040				}
4041			});
4042			
4043			if(strAuthors){
4044				urlAjax += "&ucauthors="+strAuthors;
4045				urlReplace = addUrlParam(urlReplace, "ucauthors="+strAuthors);
4046				urlFilterString = addUrlParam(urlFilterString, "ucauthors="+strAuthors);
4047			}
4048		}
4049
4050		//add meta
4051		if(arrMeta.length){
4052
4053			var strMeta = buildMetaQuery(arrMeta);
4054
4055			if(strMeta){
4056				urlAjax += "&ucmeta="+strMeta;
4057				urlReplace = addUrlParam(urlReplace, "ucmeta="+strMeta);
4058				urlFilterString = addUrlParam(urlFilterString, "ucmeta="+strMeta);
4059			}
4060		}
4061		
4062		 if(child_auto && arrTerms.length && childAutoString != ""){
4063			 urlAjax += childAutoString;
4064		 }
4065
4066		if(orderby){
4067			
4068			urlAjax += "&ucorderby="+orderby;
4069			urlReplace = addUrlParam(urlReplace, "ucorderby="+orderby);
4070
4071			if(orderby_metaname){
4072				urlAjax += "&ucorderby_meta="+orderby_metaname;
4073				urlReplace = addUrlParam(urlReplace, "ucorderby_meta="+orderby_metaname);
4074			}
4075
4076			if(orderby_metatype){
4077				urlAjax += "&ucorderby_metatype="+orderby_metatype;
4078				urlReplace = addUrlParam(urlReplace, "ucorderby_metatype="+orderby_metatype);
4079			}
4080
4081		}
4082
4083		if(orderdir){
4084			urlAjax += "&ucorderdir="+orderdir;
4085
4086			urlReplace = addUrlParam(urlReplace, "ucorderdir="+orderdir);
4087		}
4088		
4089		if(isFiltersInitMode && strSelectedTerms && strSelectedTerms !== "undefined")
4090			urlAjax += "&ucinitselectedterms="+strSelectedTerms;
4091		
4092		if(isFiltersInitMode && strSelectedAuthors && strSelectedAuthors !== "undefined")
4093			urlAjax += "&ucinitselectedauthors="+strSelectedAuthors;
4094
4095		if(isFiltersInitMode && strSelectedMeta && strSelectedMeta !== "undefined")
4096			urlAjax += "&ucinitselectedmeta="+strSelectedMeta;
4097		
4098		//add refresh ids
4099		if(strRefreshIDs)
4100			urlAjax += "&addelids="+strRefreshIDs;
4101		
4102		if(isReplaceMode == true)
4103			urlAjax += "&ucreplace=1";
4104
4105		//search
4106		if(search){
4107			search = encodeURIComponent(search);
4108			
4109			//search = escape(search);
4110
4111			urlAjax = addUrlParam(urlAjax, "ucs=" + search);
4112
4113			urlFilterString = addUrlParam(urlFilterString, "ucs=" + search);
4114			
4115			urlReplace = addUrlParam(urlReplace, "ucs=" + search);
4116			
4117			//add special search id
4118			if(advancedSearchFilterID)
4119				urlAjax = addUrlParam(urlAjax, "ucsid=" + advancedSearchFilterID);
4120			
4121		}
4122		
4123		//avoid duplicates - exclude, disable the offset
4124		
4125		if(objGrid.hasClass("uc-avoid-duplicates")){
4126			
4127			var objCurrentGrid = objGrid;
4128			if(isLoadMoreMode == true)
4129				objCurrentGrid = null;		//load with exclude but without offset
4130			
4131			var strExcludePostIDs = getExcludePostIDs(objCurrentGrid);		//exclude current grid
4132			
4133			if(strExcludePostIDs){
4134				urlAjax += "&ucexclude="+strExcludePostIDs;
4135				
4136				if(isLoadMoreMode == true)
4137					offset = null;
4138	
4139				urlFilterString = addUrlParam(urlFilterString, "ucexclude=" + strExcludePostIDs);
4140			}
4141		
4142		}
4143		
4144		
4145		if(offset){
4146			urlAjax += "&ucoffset="+offset;
4147
4148			urlFilterString = addUrlParam(urlFilterString, "offset=" + offset);
4149			
4150		}
4151
4152		//add custom additional attributes
4153
4154		if(urlAddFromFilters){
4155			urlAjax += addUrlParam(urlAjax, urlAddFromFilters);
4156			urlFilterString = addUrlParam(urlFilterString, urlAddFromFilters);
4157		}
4158
4159		//remove the "?" from first
4160		if(urlFilterString)
4161			urlFilterString = urlFilterString.substring(1);
4162
4163
4164		//remember init mode
4165		if(isFiltersInitMode == true)
4166			objGrid.data("was_init_mode",true);
4167
4168
4169		if(g_showDebug == true){
4170
4171			trace("url ajax: " + urlAjax);
4172		}
4173
4174		var output = {};
4175		output["ajax_url"] = urlAjax;
4176		output["url_replace"] = urlReplace;
4177		output["terms"] = arrTerms;
4178		output["meta"] = arrMeta;
4179		output["authors"] = arrAuthors;
4180		output["search"] = search;
4181		output["title_start"] = title_start;
4182		output["filters_string"] = urlFilterString;
4183		
4184		if(g_showDebug == true){
4185
4186			trace("output: ");
4187			trace(output);
4188
4189			trace("End getGridAjaxOptions function");
4190		}
4191
4192
4193
4194		return(output);
4195	}
4196
4197
4198	/**
4199	 * get all exclude post ids from all avoid duplicates grids
4200	 * if it's a single avoid duplicates grid - don't get excludes
4201	 */
4202	function getExcludePostIDs(objCurrentGrid){
4203		
4204		//check if it's only one grid involved
4205		if(!objCurrentGrid)
4206			var objGrids = jQuery(".uc-avoid-duplicates");
4207		else
4208			var objGrids = jQuery(".uc-avoid-duplicates").not(objCurrentGrid);
4209		
4210		if(objGrids.length == 0)
4211			return("");
4212		
4213		//check if rand of only grid, get id's, else not
4214		
4215		if(objGrids.length == 1 && !objCurrentGrid){
4216			var queryData = objGrids.attr("querydata");
4217			
4218			var objQueryData = JSON.parse(queryData);
4219			var orderby = getVal(objQueryData,"orderby");
4220			
4221			if(orderby != "rand")
4222				return("");
4223		}
4224		
4225		
4226		//get all the id's of all including the existing.
4227		
4228		var strIDs = "";
4229
4230		jQuery.each(objGrids, function(index, grid){
4231			var objGrid = jQuery(grid);
4232
4233			var postIDs = objGrid.data("postids");
4234
4235			if(!postIDs)
4236				return(true);
4237
4238			if(strIDs)
4239				strIDs += ",";
4240
4241			strIDs += postIDs;
4242		});
4243
4244
4245		return(strIDs);
4246	}
4247
4248	function ________INIT_AFTER_______________(){}
4249
4250	/**
4251	 * add filter to grid init after array
4252	 */
4253	function addFilterToInitAfter(objFilter, objGrid){
4254		
4255		var role = objFilter.data("role");
4256		
4257		var key = "filters_init_after";
4258
4259		if(role == "child")
4260			key = "filters_init_after_children";
4261
4262		objFilter.data("initafter",true);
4263
4264		var arrFiltersInitAfter = objGrid.data(key);
4265
4266		if(!arrFiltersInitAfter)
4267			arrFiltersInitAfter = [];
4268
4269		arrFiltersInitAfter.push(objFilter);
4270
4271		if(g_showDebug == true)
4272			trace("Add init after: "+key+" | "+objFilter.attr("id") );
4273		
4274		objGrid.data(key, arrFiltersInitAfter);
4275
4276	}
4277
4278	/**
4279	 * check filters init after
4280	 */
4281	function isSpecialFilterInitAfter(objFilter, objGrid){
4282		
4283		var type = getFilterType(objFilter);
4284				
4285		if(type != g_types.PAGINATION && type != g_types.LOADMORE)
4286			return(false);
4287
4288		var offsetPagination = objFilter.offset();
4289		var offsetGrid = objGrid.offset();
4290
4291		if(offsetPagination.top < offsetGrid.top){
4292
4293			if(g_showDebug == true)
4294				trace("Set "+type+" to ajax init");
4295
4296			return(true);
4297		}
4298
4299		return(false);
4300	}
4301
4302	/**
4303	 * check if there is a need to refresh child filters
4304	 * grid related, other filters are set in the settings
4305	 */
4306	function initGrid_setInitFiltersAfterLoad(objGrid){
4307		
4308		//get all grid filters
4309		var objFilters = objGrid.data("filters");
4310		
4311		if(!objFilters)
4312			return(false);
4313
4314		if(objFilters.length == 0)
4315			return(false);
4316				
4317		//check if there are filters with selected
4318		
4319		var arrSelectedFilters = getSelectedFilters(objFilters);
4320		
4321		if(arrSelectedFilters.length == 0)
4322			return(false);
4323
4324		//add to refresh all not selected filters
4325		
4326		jQuery.each(objFilters, function(index, filter){
4327						
4328			var objFilter = jQuery(filter);
4329			var type = getFilterType(objFilter);
4330			
4331			//skip not related to filter types
4332			switch(type){
4333				case g_types.PAGINATION:
4334				case g_types.LOADMORE:
4335					return(true);
4336				break;
4337			}
4338			
4339			var isSelected = objFilter.hasClass("uc-has-selected");
4340			
4341			if(isSelected == true)
4342				return(true);
4343			
4344			//skip by role. main don't add to init after
4345			var filterRole = objFilter.data("role");
4346			if(filterRole == "main")
4347				return(true);
4348			
4349			//add to grid and option to refresh
4350			
4351			var objGrid = objFilter.data("grid");
4352			
4353			addFilterToInitAfter(objFilter, objGrid);
4354			
4355		});
4356
4357	}
4358	
4359	
4360	function ________INIT_______________(){}
4361
4362
4363	/**
4364	 * init the globals
4365	 */
4366	function initGlobals(){
4367
4368		if(typeof g_strFiltersData === "undefined")
4369			return(false);
4370
4371		g_filtersData = JSON.parse(g_strFiltersData);
4372
4373		if(jQuery.isEmptyObject(g_filtersData)){
4374
4375			trace("filters error - filters data not found");
4376			return(false);
4377		}
4378		
4379		g_urlBase = getVal(g_filtersData, "urlbase");
4380		g_urlAjax = getVal(g_filtersData, "urlajax");
4381		
4382		var platform = getVal(g_filtersData, "platform");
4383		
4384		//switch to gutenberg
4385		
4386		if(platform == "gutenberg"){
4387			g_isGutenberg = true;
4388			g_vars.class_widget_wrapper = "ue-widget-root";
4389			g_vars.current_postid = getVal(g_filtersData, "postid");
4390		}
4391		
4392		//ucpage url
4393		var ucpage = getVal(g_filtersData,"ucpage");
4394		if(jQuery.isNumeric(ucpage))
4395			g_vars.ucpage_url = ucpage;
4396		
4397		//url keys
4398
4399		var objUrlKeys = getVal(g_filtersData, "urlkeys");
4400		
4401		var taxSap = getVal(objUrlKeys, "tax_sap");
4402		if(taxSap)
4403			g_options.urlkey_taxsap = taxSap;
4404		
4405		var isShowDebug = getVal(g_filtersData, "debug");
4406
4407		if(isShowDebug == true)
4408			g_showDebug = true;
4409
4410		if(g_showDebug == true)
4411			trace("Show Filters Debug");
4412
4413		if(!g_urlBase){
4414			trace("ue filters error - base url not inited");
4415			return(false);
4416		}
4417
4418		if(!g_urlAjax){
4419			trace("ue filters error - ajax url not inited");
4420			return(false);
4421		}
4422		
4423		//trace(g_options);
4424		
4425		return(true);
4426	}
4427
4428
4429	/**
4430	 * init filter and bing to grid
4431	 */
4432	function initFilter(objFilter, type){
4433
4434		var objGrid = getClosestGrid(objFilter);
4435
4436		var error = "Filter Parent not found! Please put the posts element on the page, and turn on 'Enable Post Filtering' option on it";
4437
4438		if(!objGrid){
4439			
4440			
4441			//pagination can work without parent as regular link
4442			
4443			var type = getFilterType(objFilter);
4444			if(type == g_types.PAGINATION)
4445				return(false);
4446			
4447			showElementError(objFilter, error);
4448			return(null);
4449		}
4450
4451		var isAjax = objGrid.data("ajax");
4452
4453		if(isAjax == false){
4454			showElementError(objFilter, error);
4455			return(false);
4456		}
4457
4458		//bind grid to filter
4459		objFilter.data("grid", objGrid);
4460		
4461		//bind filter to grid
4462		bindFilterToGrid(objGrid, objFilter);
4463		
4464		
4465		//set data var
4466		if(g_showDebug == true)
4467			objFilter.attr("data-showdebug", true);
4468		
4469		switch(type){
4470			case g_types.TERMS_LIST:
4471				initTermsRelatedFilter(objFilter);
4472			break;
4473			case g_types.SELECT:
4474				initSelectFilter(objFilter);
4475				initTermsRelatedFilter(objFilter);				
4476			break;
4477			case g_types.GENERAL:		//general filter events
4478				initGeneralFilter(objFilter);
4479			break;
4480		}
4481
4482
4483		objFilter.trigger(g_vars.EVENT_INIT_FILTER);
4484
4485	}
4486
4487
4488	/**
4489	 * init filter events by types
4490	 */
4491	function initFilterEventsByTypes(arrTypes, arrGeneralTypes, objFilters, objParent){
4492
4493		if(!arrTypes || arrTypes.length == 0)
4494			return(false);
4495
4496		if(g_showDebug == true){
4497			trace("Init filter events for parent");
4498			trace(arrTypes);
4499			trace(objParent);
4500		}
4501
4502		for(var type in arrTypes){
4503
4504			switch(type){
4505				case g_types.PAGINATION:
4506										
4507					objParent.on("click",".uc-filter-pagination a", onAjaxPaginationLinkClick);
4508					
4509				break;
4510				case g_types.LOADMORE:
4511
4512					//load more
4513					objParent.on("click",".uc-filter-load-more__link", onLoadMoreClick);
4514				break;
4515				case g_types.TERMS_LIST:
4516
4517					objParent.on("click",".ue_taxonomy.uc-grid-filter a.ue_taxonomy_item", onTermsLinkClick);
4518
4519				break;
4520				case g_types.SEARCH:
4521
4522					//do nothing for init
4523
4524				break;
4525				case g_types.SELECT:
4526
4527					objParent.on("change", ".uc-select-filter__select", onTermsLinkClick);
4528
4529				break;
4530				case g_types.SUMMARY:
4531					//do nothing for now
4532				break;
4533				case g_types.GENERAL:
4534					//the init is from the general types
4535				break;
4536				default:
4537					trace("init by type - unrecognized type: "+type);
4538				break;
4539			}
4540		}
4541
4542		if(!arrGeneralTypes || arrGeneralTypes.length == 0)
4543			return(false);
4544
4545
4546		//init the general types
4547
4548		for(var generalType in arrGeneralTypes){
4549
4550			var objFirstFilter = arrGeneralTypes[generalType];
4551
4552			objFirstFilter.trigger(g_vars.EVENT_INIT_FILTER_TYPE,[objParent]);
4553
4554		}
4555
4556	}
4557
4558
4559
4560
4561	/**
4562	 * init pagination filter
4563	 */
4564	function initFilters(objFilters){
4565		
4566		if(g_showDebug == true){
4567
4568			trace("init filters");
4569
4570			if(objFilters.length == 0)
4571				trace("no filters found");
4572			else
4573				trace(objFilters);
4574		}
4575
4576		var numFilters = objFilters.length;
4577
4578		if(numFilters == 0)
4579			return(false);
4580
4581		var arrTypes = {};
4582		var arrGeneralTypes = {};
4583
4584		var objParent = getFiltersParent(objFilters);
4585
4586		jQuery.each(objFilters, function(index, filter){
4587
4588			var objFilter = jQuery(filter);
4589			var type = getFilterType(objFilter);
4590
4591			//set single filter
4592			if(numFilters === 1){
4593				objFilter.attr("data-singlefilter",true);
4594			}
4595
4596			initFilter(objFilter, type);
4597
4598			//collect the general type
4599
4600			arrTypes[type] = true;
4601
4602			if(type == g_types.GENERAL){
4603				var generalType = objFilter.data("generaltype");
4604				
4605				if(!generalType){
4606					trace(objFilter);
4607					throw new Error("The filter is missing generaltype data");
4608				}
4609
4610				if(arrGeneralTypes.hasOwnProperty(generalType) == false)
4611					arrGeneralTypes[generalType] = objFilter;
4612
4613			}
4614
4615			objFilter.addClass(g_vars.CLASS_FILTER_INITED);
4616
4617		});
4618
4619		initFilterEventsByTypes(arrTypes, arrGeneralTypes, objFilters, objParent);
4620
4621	}
4622
4623
4624	/**
4625	 * set init state ajax url for each grid (for go back)
4626	 */
4627	function initGrid_setAjaxUrl(objGrid){
4628
4629		var behave = objGrid.data("filterbehave");
4630
4631		if(behave != "mixed_back")
4632			return(false);
4633
4634		//get all grid filters
4635		var objFilters = objGrid.data("filters");
4636
4637		if(!objFilters)
4638			return(false);
4639
4640		if(objFilters.length == 0)
4641			return(false);
4642
4643		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid,false,false,{getonly:true});
4644
4645		var ajaxUrlInit = getVal(objAjaxOptions, "ajax_url");
4646
4647		objGrid.data("initajaxurl", ajaxUrlInit);
4648
4649	}
4650
4651
4652	/**
4653	 * set active filters data - for third party connections, active filters and clear button
4654	 */
4655	function initGrid_setActiveFiltersData(objGrid, objAjaxOptions){
4656		
4657		if(!objAjaxOptions)
4658			var objAjaxOptions = getGridAjaxOptions_simple(objGrid);
4659		
4660
4661		var arrTerms = getVal(objAjaxOptions, "terms");
4662		var arrMeta = getVal(objAjaxOptions, "meta");
4663		var arrAuthors = getVal(objAjaxOptions, "authors");
4664
4665		if(!jQuery.isArray(arrTerms))
4666			arrTerms = [];
4667
4668		if(!jQuery.isArray(arrMeta))
4669			arrMeta = [];
4670
4671		if(!jQuery.isArray(arrAuthors))
4672			arrAuthors = [];
4673
4674		arrTerms = arrTerms.concat(arrMeta, arrAuthors);
4675
4676		if(jQuery.isArray(arrTerms))
4677			arrTerms = arrTerms.flat();
4678
4679		// Create a new array for filtered items
4680		var filteredTerms = [];
4681		
4682		jQuery.each(arrTerms, function(index, term) {
4683			
4684			if(!term)
4685				return(true);
4686
4687			var slug = getVal(term, "slug");
4688			var metaValue = getVal(term, "meta_value");
4689
4690			// Skip operator markers used for grouping (__ucand__/__ucor__)
4691			if (slug === "__ucand__" || slug === "__ucor__" || slug === "__and__" || slug === "__or__")
4692				return(true);
4693
4694			if (metaValue === "__ucand__" || metaValue === "__ucor__")
4695				return(true);
4696				
4697			filteredTerms.push(term);
4698		});
4699
4700		// Assign the filtered array back to arrTerms
4701		arrTerms = filteredTerms;
4702		
4703		var search = getVal(objAjaxOptions, "search");
4704
4705		if(search)
4706			search = search.trim();
4707
4708		if(search){
4709			var objSearch = {
4710				type:"search",
4711				"key": "search|"+search,
4712				"title": search
4713			};
4714
4715			if(!arrTerms)
4716				var arrTerms = [];
4717
4718			arrTerms.push(objSearch);
4719		}
4720		
4721		//title start
4722		var titleStart = getVal(objAjaxOptions, "title_start");
4723		
4724		if(titleStart){
4725			
4726			var objTitleStart = {
4727					type:"titlestart",
4728					"key": "titlestart|"+titleStart,
4729					"title": titleStart
4730				};
4731
4732			if(!arrTerms)
4733				var arrTerms = [];
4734
4735			arrTerms.push(objTitleStart);
4736		}
4737			
4738		
4739		objGrid.data("active_filters_items", arrTerms);
4740		objGrid.trigger(g_vars.EVENT_UPDATE_ACTIVE_FILTER_ITEMS, [arrTerms]);
4741		
4742	}
4743
4744
4745	/**
4746	 * init the grids, ininital filters refresh,
4747	 * set active filters, and update initial url's
4748	 */
4749	function initGrids(){
4750
4751		var objGrids = getAllGrids("loaded_only");
4752
4753		if(objGrids.length == 0)
4754			return(false);
4755
4756		if(g_showDebug == true){
4757			trace("init grids");
4758			trace(objGrids);
4759		}
4760
4761		jQuery.each(objGrids, function(index, grid){
4762
4763			var objGrid = jQuery(grid);
4764
4765			//--- set go back url if needed
4766
4767			initGrid_setAjaxUrl(objGrid);
4768
4769			initGrid_setInitFiltersAfterLoad(objGrid);
4770
4771			//--- set active filters (for clear and active filters links)
4772
4773			initGrid_setActiveFiltersData(objGrid);
4774			
4775						
4776			//--- refresh init filters
4777			
4778			var objInitFilters = objGrid.data("filters_init_after");
4779						
4780			var isMainFiltersRefreshed = false;
4781			if(objInitFilters && objInitFilters.length > 0){
4782
4783				isMainFiltersRefreshed = true;
4784
4785				if(g_showDebug == true){
4786					trace("ajax init Filters");
4787					trace(objInitFilters);
4788				}
4789
4790				refreshAjaxGrid(objGrid, "filters");
4791			}
4792
4793			//--- refresh init filters - children
4794
4795			var objInitFiltersChildren = objGrid.data("filters_init_after_children");
4796
4797			if(objInitFiltersChildren && objInitFiltersChildren.length > 0){
4798
4799				if(isMainFiltersRefreshed == false){
4800
4801					if(g_showDebug == true){
4802						trace("ajax init child Filters");
4803						trace(objInitFiltersChildren);
4804					}
4805					
4806					refreshAjaxGrid(objGrid, "filters_children");
4807					
4808				}
4809				else
4810					objGrid.data("init_refresh_child_filters", true);
4811			}
4812
4813			objGrid.addClass("ucfilters--grid-inited");
4814
4815		});
4816
4817
4818		return(objGrids);
4819	}
4820
4821	/**
4822	 * init grids events
4823	 */
4824	function initGridsEvents(objGrids){
4825
4826		//init grids events
4827
4828		if(!objGrids || objGrids.length == 0)
4829			return(false);
4830
4831
4832		//grid several action
4833
4834		objGrids.on(g_vars.ACTION_REFRESH_GRID,function(){
4835
4836			var objGrid = jQuery(this);
4837
4838			if(g_showDebug == true){
4839				trace("Refresh grid - by event:" + g_vars.ACTION_REFRESH_GRID);
4840				console.trace();
4841			}
4842			
4843			refreshAjaxGrid(objGrid);
4844		});
4845
4846
4847		objGrids.on(g_vars.ACTION_GET_FILTERS_URL,function(){
4848
4849			var objGrid = jQuery(this);
4850
4851			var urlFilters = getGridUrlFiltersString(objGrid);
4852
4853			return(urlFilters);
4854		});
4855
4856		//clear filters from event
4857
4858		objGrids.on(g_vars.ACTION_CLEAR_FILTERS, function(){
4859			
4860			var objGrid = jQuery(this);
4861
4862			var arrActiveFilterItems = getGridActiveFilterItems(objGrid);
4863
4864			//if already cleared - no need
4865			if(!arrActiveFilterItems)
4866				return(null);
4867			
4868			clearAllFilters(objGrid, null, true);
4869			
4870			objGrid.trigger(g_vars.ACTION_REFRESH_GRID);
4871
4872		});
4873
4874		//unselect filter from event
4875
4876		objGrids.on(g_vars.EVENT_UNSELECT_FILTER, function(event, key){
4877						
4878			var objGrid = jQuery(this);
4879			
4880			unselectFilterItem(objGrid, key);
4881			
4882			objGrid.trigger(g_vars.ACTION_REFRESH_GRID);
4883		});
4884
4885	}
4886
4887	/**
4888	 * init events
4889	 */
4890	function initGeneralEvents(){
4891
4892		addEventListener('popstate', onPopState);
4893
4894		g_objBody.on(g_vars.EVENT_DOM_UPDATED, runInitFilters);
4895
4896	}
4897
4898
4899	/**
4900	 * validate the grids
4901	 */
4902	function validateGrid(objGrid){
4903
4904		//check for |raw absence
4905
4906		var isAjax = objGrid.data("ajax");
4907
4908		if(isAjax === "'true'")
4909			showElementError(objGrid, "This grid configured wrong way, missing |raw in html attributes");
4910
4911	}
4912
4913
4914	/**
4915	 * add some validation to the grids
4916	 */
4917	function validateGrids(){
4918
4919		var objGrids = getAllGrids("loaded_only");
4920
4921		jQuery.each(objGrids, function(index, grid){
4922
4923			var objGrid = jQuery(grid);
4924
4925			validateGrid(objGrids);
4926		});
4927	}
4928
4929
4930	/**
4931	 * run init filters
4932	 */
4933	function runInitFilters(){
4934
4935		validateGrids();
4936
4937		//get the filters
4938		var objFilters = jQuery(".uc-grid-filter, .uc-filter-pagination").not("." + g_vars.CLASS_FILTER_INITED);
4939		
4940		//wait for load...
4941
4942		var objFiltersLoading = objFilters.filter(".uc-waitforload");
4943
4944		if(objFiltersLoading.length && g_initFiltersCounter < 2){
4945
4946			if(g_showDebug == true){
4947				trace(objFiltersLoading);
4948				trace("Wait for Load!");
4949			}
4950
4951			setTimeout(runInitFilters, 500);
4952
4953			g_initFiltersCounter++;
4954
4955			objFilters = null;
4956			objFiltersLoading = null;
4957
4958			return(false);
4959		}
4960
4961		//init for the next time
4962		g_initFiltersCounter = 0;
4963
4964		initFilters(objFilters);
4965
4966		//init all grids with several stuff like init filters, active modes and url's
4967		var objGrids = initGrids();
4968
4969		initGridsEvents(objGrids);
4970
4971	}
4972
4973
4974	/**
4975	 * init
4976	 */
4977	function init(){
4978
4979		g_objBody = jQuery("body");
4980
4981		var success = initGlobals();
4982					//run again on fail 3 times
4983		if(success == false){
4984
4985			if(typeof window.ueFiltersTimeoutCounter != "undefined")
4986					window.ueFiltersTimeoutCounter++;
4987			else
4988				window.ueFiltersTimeoutCounter = 0;
4989
4990			if(window.ueFiltersTimeoutCounter == 3){
4991				trace("Failed to init filters");
4992				return(false);
4993			}
4994
4995			setTimeout(init, 200);
4996
4997			return(false);
4998		}
4999
5000		//init remote object if exists
5001		if(typeof UERemoteConnection == "function")
5002			g_remote = window.ueRemoteConnection;
5003
5004		runInitFilters();
5005
5006		initGeneralEvents();
5007		
5008		
5009		//run init again on elementor popup
5010		
5011		jQuery( document ).on( 'elementor/popup/show', function(event, id, objPopup){
5012			
5013			g_objBody.trigger(g_vars.EVENT_DOM_UPDATED);
5014			
5015		});
5016		
5017		
5018	}
5019
5020
5021	/**
5022	 * is element in viewport
5023	 */
5024	this.isElementInViewport = function(objElement) {
5025
5026		  var elementTop = objElement.offset().top;
5027		  var elementBottom = elementTop + objElement.outerHeight();
5028
5029		  var viewportTop = jQuery(window).scrollTop();
5030		  var viewportBottom = viewportTop + jQuery(window).height();
5031
5032		  return (elementBottom > viewportTop && elementTop < viewportBottom);
5033	}
5034
5035	/**
5036	 * run function with trashold, default is 500
5037	 */
5038	this.runWithTrashold = function(func, trashold){
5039
5040		if(!trashold)
5041			 var trashold = 500;
5042
5043		if(g_vars.trashold_handle)
5044			clearTimeout(g_vars.trashold_handle);
5045
5046		g_vars.trashold_handle = setTimeout(func, trashold);
5047
5048	};
5049
5050	/**
5051	 * get filter element data
5052	 */
5053	this.getFilterElementData = function(objElement){
5054		
5055		var objData = getFilterElementData(objElement);
5056
5057		return(objData);
5058	}
5059
5060	/**
5061	 * get filter parent query data
5062	 */
5063	this.getFilterGridQueryData = function(objFilter){
5064
5065     	 var objGrid = objFilter.data("grid");
5066      	 if(!objGrid)
5067           	return(null);
5068
5069         var queryData = objGrid.attr("querydata");
5070      	  if(!queryData)
5071            return(null);
5072
5073      	 var objData = jQuery.parseJSON(queryData);
5074
5075      	 if(g_showDebug == true){
5076      		 console.log("getQueryData (filter, grid, querydata): ",objFilter, objGrid, queryData);
5077      	 }
5078
5079		return(objData);
5080	}
5081
5082	/**
5083	 * get key
5084	 */
5085	this.getFilterItemKey = function(objItem){
5086
5087		if(!objItem || objItem.length == 0)
5088			return(null);
5089
5090		var key = objItem.data("key");
5091
5092		if(key)
5093			return(key);
5094
5095		//fallback
5096
5097		key = "term|" + objItem.data("taxonomy") + "|" + objItem.data("slug");
5098
5099		return(key);
5100	}
5101
5102
5103	/**
5104	 * get value
5105	 */
5106	this.getVal = function(obj, name, defaultValue){
5107
5108		return getVal(obj, name, defaultValue);
5109	}
5110	
5111	/**
5112	 * get filters by type
5113	 * return jquery object
5114	 */
5115	this.getGridFiltersByType = function(objGrid, filterType){
5116		
5117		if(!filterType)
5118			throw new Error("getGridFiltersByType error - enter type as second param");
5119		
5120		var arrFilters = getGridFilters(objGrid);
5121		
5122		if(arrFilters.length == 0)
5123			return(jQuery());
5124		
5125		var objChosenFilters = jQuery();
5126		
5127		jQuery.each(arrFilters, function(index, objFilter){
5128			
5129			var type = getFilterType(objFilter, true);
5130						
5131			if(type == filterType){
5132				objChosenFilters = objChosenFilters.add(objFilter);
5133			}
5134			
5135		});
5136		
5137		return(objChosenFilters);
5138	}
5139
5140
5141	/**
5142	 * init the class
5143	 */
5144	function construct(){
5145
5146		if(!jQuery){
5147			trace("Filters not loaded, jQuery not loaded");
5148			return(false);
5149		}
5150		
5151		jQuery("document").ready(function(){
5152			setTimeout(init, 200);
5153		});
5154		
5155	}
5156
5157	construct();
5158
5159}
5160
5161g_ucDynamicFilters = new UEDynamicFilters();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.