PageSourceSearch

https://teacherplus.org/wp-content/plugins/unlimited-elements-for-…/filters/ue_filters.js?ver=2.0.17

js teacherplus.org collected 2026-09-24 19:58:25 UTC 102,194 bytes, 5,042 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	 * handle item, add to key->values map
1713	 * keyName/valueName: "taxonomy"/"slug" for terms, "meta_key"/"meta_value" for meta
1714	 */
1715	function buildGroupedValuesQuery_handleItem(objItem, arrGrouped, keyName, valueName){
1716
1717		var key = objItem[keyName];
1718		var value = objItem[valueName];
1719
1720		if(!key)
1721			return(arrGrouped);
1722
1723		if(value === null || typeof value === "undefined")
1724			value = "";
1725
1726		var objValues = getVal(arrGrouped, key);
1727		if(!objValues)
1728			objValues = {};
1729
1730		objValues[value] = true;
1731		arrGrouped[key] = objValues;
1732
1733		return(arrGrouped);
1734	}
1735
1736	/**
1737	 * get values string (dot separated)
1738	 * adds .* for AND relation when multiple values
1739	 */
1740	function buildGroupedValuesQuery_getStrValues(objValues, isGroup){
1741		
1742		var isDebug = false;
1743		
1744		if(isDebug == true){
1745			trace("get str values");
1746			trace(objValues);
1747			trace("is group:" + isGroup);
1748		}
1749		
1750		var strValues = "";
1751
1752		var moreThenOne = false;
1753		var isEndSlugFound = false;
1754		var isOrSlugFound = false;
1755		
1756		for (var value in objValues){
1757				
1758			if(value === "__ucand__"){
1759				isEndSlugFound = true;
1760				continue
1761			}
1762			
1763			if(value === "__ucor__"){
1764				isOrSlugFound = true;
1765				continue
1766			}
1767
1768			if(strValues){
1769				moreThenOne = true;
1770				strValues += ".";
1771			}
1772
1773			strValues += value;
1774		}
1775
1776		if(isDebug == true){
1777			trace("more then one: "+moreThenOne);
1778			trace("is end found: "+isEndSlugFound);
1779		}
1780		
1781		var addAnd = (moreThenOne == true && isGroup !== true || isEndSlugFound);
1782		
1783		if(isOrSlugFound === true)
1784			addAnd = false;
1785		
1786		if(addAnd)
1787			strValues += ".*";
1788
1789		if(isDebug)
1790			trace("str values: "+strValues);
1791		
1792		return(strValues);
1793	}
1794
1795
1796	/**
1797	 * build grouped values query string
1798	 * format: key:value1.value2.*;key2:value3
1799	 * used for ucterms (taxonomy:slugs) and ucmeta (meta_key:values)
1800	 */
1801	function buildGroupedValuesQuery(arrItems, keyName, valueName){
1802		
1803		var isDebug = false;
1804
1805		if(!keyName)
1806			keyName = "taxonomy";
1807
1808		if(!valueName)
1809			valueName = "slug";
1810
1811		var query = "";
1812
1813		var arrGrouped = {};
1814		var arrGroupItems = [];
1815
1816		if(isDebug == true){
1817			trace("arr items");
1818			trace(arrItems);
1819		}
1820		
1821		jQuery.each(arrItems, function(index, objItem){
1822
1823			//group
1824			if(jQuery.isArray(objItem) && objItem.length != 0){
1825				
1826				if(objItem.length == 1){
1827					arrGrouped = buildGroupedValuesQuery_handleItem(objItem[0], arrGrouped, keyName, valueName);
1828					return;
1829				}
1830
1831				var arrGroupMap = {};
1832				
1833				jQuery.each(objItem, function(index, groupItem){
1834					
1835					arrGroupMap = buildGroupedValuesQuery_handleItem(groupItem, arrGroupMap, keyName, valueName);
1836				});
1837
1838				arrGroupItems.push(arrGroupMap);
1839
1840			}else{	//single
1841
1842				arrGrouped = buildGroupedValuesQuery_handleItem(objItem, arrGrouped, keyName, valueName);
1843			}
1844
1845		});
1846		
1847		if(isDebug == true){
1848			trace("first arr grouped");
1849			trace(arrGrouped);
1850		}
1851
1852		if(jQuery.isEmptyObject(arrGrouped) && jQuery.isEmptyObject(arrGroupItems))
1853			return(null);
1854
1855		if(isDebug == true){
1856			trace("group items");
1857			trace(arrGroupItems);
1858		}
1859		
1860		var isMultipleGroups = (arrGroupItems.length > 1);
1861		
1862		jQuery.each(arrGroupItems, function(index, objGroupKeys){
1863			
1864			jQuery.each(objGroupKeys, function(key, objValues){
1865				
1866			var strValues = buildGroupedValuesQuery_getStrValues(objValues, true);
1867			
1868			var strAdd = strValues;
1869			if(isMultipleGroups === true && strValues.indexOf(".") !== -1){
1870				strAdd = "|"+strValues+"|";	//OR inside the group - only when multiple groups
1871			}
1872				
1873				var objKeyValues = getVal(arrGrouped, key);
1874				if(!objKeyValues)
1875					objKeyValues = {};
1876		
1877				objKeyValues[strAdd] = true;
1878		
1879				arrGrouped[key] = objKeyValues;
1880			});
1881
1882		});
1883
1884		
1885		if(isDebug == true){
1886			trace("The result after grouping");
1887			trace(arrGrouped);
1888		}
1889
1890		jQuery.each(arrGrouped, function(key, objValues){
1891			
1892			var strValues = buildGroupedValuesQuery_getStrValues(objValues);
1893				
1894			var strPart = key + g_options.urlkey_taxsap + strValues;
1895			
1896			if(query)
1897				query += ";";
1898
1899			query += strPart;
1900
1901		});
1902
1903		if(isDebug == true){
1904			trace("query");
1905			trace(query);
1906		}
1907
1908		return(query);
1909	}
1910
1911	/**
1912	 * build terms query
1913	 * ucterms=category:blog.cocktails.design.*
1914	 */
1915	function buildTermsQuery(arrTerms){
1916
1917		return buildGroupedValuesQuery(arrTerms, "taxonomy", "slug");
1918	}
1919
1920	/**
1921	 * build meta query - same format as terms
1922	 * ucmeta=meta_key:value1.value2.*
1923	 */
1924	function buildMetaQuery(arrMeta){
1925
1926		//normalize: ensure meta_key exists (fallback from slug)
1927		var arrNormalized = [];
1928
1929		jQuery.each(arrMeta, function(index, item){
1930
1931			if(jQuery.isArray(item)){
1932
1933				var arrGroup = [];
1934
1935				jQuery.each(item, function(groupIndex, groupItem){
1936
1937					if(!groupItem)
1938						return(true);
1939
1940					if(!groupItem.meta_key && groupItem.slug)
1941						groupItem.meta_key = groupItem.slug;
1942
1943					if(typeof groupItem.meta_value === "undefined" || groupItem.meta_value === null)
1944						groupItem.meta_value = "";
1945
1946					arrGroup.push(groupItem);
1947				});
1948
1949				arrNormalized.push(arrGroup);
1950
1951			}else{
1952
1953				if(!item)
1954					return(true);
1955
1956				if(!item.meta_key && item.slug)
1957					item.meta_key = item.slug;
1958
1959				if(typeof item.meta_value === "undefined" || item.meta_value === null)
1960					item.meta_value = "";
1961
1962				arrNormalized.push(item);
1963			}
1964
1965		});
1966
1967		return buildGroupedValuesQuery(arrNormalized, "meta_key", "meta_value");
1968	}
1969
1970	/**
1971	 * get selected filter element data
1972	 */
1973	function getFilterElementData(objElement){
1974				
1975		var id = objElement.data("id");
1976		var title = objElement.data("title");
1977		var key = objElement.data("key");
1978		var type = objElement.data("type");
1979		
1980		if(!id && !key)
1981			return(null);
1982		
1983		
1984		switch(type){
1985		case "taxonomy":
1986		default:
1987			var slug = objElement.data("slug");
1988			var taxonomy = objElement.data("taxonomy");
1989			
1990			var objTerm = {
1991				"type": type,
1992				"id": id,
1993				"slug": slug,
1994				"taxonomy": taxonomy,
1995				"title": title,
1996				"key": key
1997			};
1998			return(objTerm);
1999			
2000		break;
2001		case "author":
2002			
2003			var username = objElement.data("username");
2004			
2005			var objAuthor = {
2006					"type": type,
2007					"id": id,
2008					"username": username,
2009					"title": title,
2010					"key": key
2011				};
2012				return(objAuthor);
2013			
2014		break;
2015		case "meta":
2016
2017			var slug = objElement.data("slug");
2018			var metaKey = objElement.data("metakey");
2019			var metaValue = objElement.data("metavalue");
2020
2021			if(!metaKey)
2022				metaKey = slug;
2023
2024			if(!metaValue)
2025				metaValue = "";
2026
2027			var objMeta = {
2028				"type": type,
2029				"id": id,
2030				"slug": slug,
2031				"meta_key": metaKey,
2032				"meta_value": metaValue,
2033				"title": title,
2034				"key": key
2035			};
2036			return(objMeta);
2037
2038		break;
2039		}
2040		
2041	}
2042
2043
2044	function ________AJAX_CACHE_________(){}
2045
2046	/**
2047	 * get ajax url
2048	 */
2049	function getAjaxCacheKeyFromUrl(ajaxUrl){
2050
2051		var key = ajaxUrl;
2052
2053		key = key.replace(g_urlAjax, "");
2054		key = key.replace(g_urlBase, "");
2055
2056		//replace special signs
2057		key = replaceAll(key, "/","");
2058		key = replaceAll(key, "?","_");
2059		key = replaceAll(key, "&","_");
2060		key = replaceAll(key, "=","_");
2061
2062		return(key);
2063	}
2064
2065	/**
2066	 * get ajax cache key
2067	 */
2068	function getAjaxCacheKey(ajaxUrl, action, objData){
2069
2070	    if(g_options.is_cache_enabled == false)
2071	    	return(false);
2072
2073	    //cache only by url meanwhile
2074
2075	    if(jQuery.isEmptyObject(objData) == false)
2076	    	return(false);
2077
2078	    if(action)
2079	    	return(false);
2080
2081	    var cacheKey = getAjaxCacheKeyFromUrl(ajaxUrl);
2082
2083	    if(!cacheKey)
2084	    	return(false);
2085
2086	    return(cacheKey);
2087	}
2088
2089
2090	/**
2091	 * cache ajax response
2092	 */
2093	function cacheAjaxResponse(ajaxUrl, action, objData, response){
2094
2095	    var cacheKey = getAjaxCacheKey(ajaxUrl, action, objData);
2096
2097	    if(!cacheKey)
2098	    	return(false);
2099
2100	    //some precoutions for overload
2101	    if(g_cache.length > 100)
2102	    	return(false);
2103
2104	    g_cache[cacheKey] = response;
2105
2106	}
2107
2108
2109	function ________AJAX_RESPONSE_______________(){}
2110
2111	/**
2112	 * replace the grid debug
2113	 */
2114	function operateAjax_setHtmlDebug(response, objGrid){
2115
2116		//replace the debug
2117		var htmlDebug = getVal(response, "html_debug");
2118
2119		if(!htmlDebug)
2120			return(false);
2121		
2122		var gridParent = objGrid.parents("." + g_vars.class_widget_wrapper);
2123		
2124		var objDebug = gridParent.find(".uc-debug-query-wrapper");
2125
2126		if(objDebug.length == 0)
2127			return(false);
2128
2129		objDebug.replaceWith(htmlDebug);
2130	}
2131
2132
2133	/**
2134	 * set html grid from ajax response
2135	 */
2136	function operateAjax_setHtmlGrid(response, objGrid, isLoadMore){
2137		
2138		if(g_showDebug == true){
2139			trace("set html grid, response: ");
2140			trace(response);
2141
2142			trace("obj grid:");
2143			trace(objGrid);
2144		}
2145
2146		if(objGrid.length == 0)
2147			return(false);
2148		
2149		//skip set html if exists
2150		if(objGrid.data(g_vars.GRID_DATA_SKIP_HTML) === true){
2151			
2152			if(g_showDebug == true)
2153				trace("skip set html");
2154			
2155			objGrid.data(g_vars.GRID_DATA_SKIP_HTML,false);
2156			return(false);
2157		}
2158		
2159		var objItemsWrapper = getGridItemsWrapper(objGrid);
2160		var objItemsWrapper2 = getGridItemsWrapper(objGrid, true);
2161
2162		if(g_showDebug == true){
2163			trace("items wrapper 1: ");
2164			trace(objItemsWrapper);
2165
2166			trace("items wrapper 2:");
2167			trace(objItemsWrapper2);
2168		}
2169
2170
2171		if(!objItemsWrapper || objItemsWrapper.length == 0)
2172			throw new Error("Missing items wrapper: .uc-items-wrapper");
2173
2174		operateAjax_setHtmlDebug(response, objGrid);
2175
2176		//set grid items
2177
2178		//if init filters mode, and no items response - don't set
2179		if(response.hasOwnProperty("html_items") == false)
2180			return(false);
2181		
2182		var htmlItems = getVal(response, "html_items");
2183				
2184		var htmlItems2 = null;
2185
2186		if(objItemsWrapper2)
2187			htmlItems2 = getVal(response, "html_items2");
2188
2189		//replace widget id
2190		var gridID = objGrid.attr("id");
2191
2192		htmlItems = replaceAll(htmlItems, "%uc_widget_id%", gridID);
2193		
2194		if(htmlItems2)
2195			htmlItems2 = replaceAll(htmlItems2, "%uc_widget_id%", gridID);
2196
2197		var isCustomRefresh = objGrid.data("custom-sethtml");
2198
2199		//show / hide empty message if available and empty response
2200		var objEmptyMessage = getGridEmptyMessage(objGrid);
2201
2202		if(objEmptyMessage){
2203			if(htmlItems == "")
2204				objEmptyMessage.show();
2205			else
2206				objEmptyMessage.hide();
2207		}
2208
2209		//set the query data
2210		var queryDataOriginal = getVal(response, "query_data");
2211		var queryIDs = getVal(response,"query_ids");
2212
2213		var queryData = jQuery.extend({}, queryDataOriginal);
2214
2215		//add to old data
2216
2217		if(isLoadMore == true){
2218
2219			var currentQueryData = objGrid.attr("querydata");
2220
2221			var objCurrentData = jQuery.parseJSON(currentQueryData);
2222			var currentNumPosts = getVal(objCurrentData, "count_posts");
2223
2224			queryData.count_posts += currentNumPosts;
2225
2226			var currentQueryIDs = objGrid.data("postids");
2227
2228			if(queryIDs && currentQueryIDs)
2229				queryIDs = currentQueryIDs + "," + queryIDs;
2230		}
2231
2232		//query data replace
2233
2234		if(queryData){
2235
2236			objGrid.removeAttr("querydata");
2237
2238			var jsonData = JSON.stringify(queryData);
2239			objGrid.attr("querydata", jsonData);
2240
2241			objGrid.data("querydata", queryData);
2242		}
2243
2244		//post id's replace
2245
2246		objGrid.removeAttr("data-postids");
2247		objGrid.attr("data-postids", queryIDs);
2248		objGrid.data("postids", queryIDs);
2249
2250
2251		//if custom refresh - just save the new html in data
2252		if(isCustomRefresh == true){
2253
2254			objGrid.trigger(g_vars.EVENT_SET_HTML_ITEMS,[htmlItems, isLoadMore, htmlItems2]);
2255			return(false);
2256		}
2257
2258
2259		if(!htmlItems2)
2260			htmlItems2 = "";
2261
2262		if(isLoadMore === true){
2263
2264			if(g_showDebug == true){
2265				trace("append load more");
2266			}
2267
2268			objItemsWrapper.append(htmlItems);
2269
2270			if(objItemsWrapper)
2271				objItemsWrapper.append(htmlItems2);
2272
2273		}else{
2274						
2275			objItemsWrapper.html(htmlItems);
2276
2277			if(objItemsWrapper2 && objItemsWrapper2.length)
2278				objItemsWrapper2.html(htmlItems2);
2279
2280		}
2281		
2282		
2283		return(true);
2284	}
2285
2286
2287	/**
2288	 * refresh synced grids
2289	 */
2290	function operateAjax_setHtmlSyngGrids(response, objGrid, isLoadMore){
2291		
2292		var objSyncWidgetsResponse = getVal(response, "html_sync_widgets");
2293
2294		if(g_showDebug == true){
2295			trace("set html sync grids");
2296			trace(objSyncWidgetsResponse);
2297		}
2298
2299		var queryData = getVal(response,"query_data");
2300
2301		if(!objSyncWidgetsResponse){
2302			
2303			if(g_showDebug == true){
2304				trace("no sync widgets response");
2305			}
2306			
2307			return(false);
2308		}
2309		
2310		var group = objGrid.data("filtergroup");
2311		
2312		jQuery.each(objSyncWidgetsResponse, function(elementID, childResponse){
2313			
2314			var objGridWidget = getGridFromElementorElementID(elementID, group);
2315			
2316			if(!objGridWidget){
2317				
2318				if(g_showDebug == true){
2319					trace("no grid widget found: "+elementID);
2320					
2321					getGridFromElementorElementID(elementID,group,true);	//for debug
2322				}
2323				
2324				return(true);
2325			}
2326
2327			if(g_showDebug == true){
2328				trace("set sync grid!");
2329				trace(objGridWidget);
2330				trace(childResponse);
2331			}
2332			
2333			
2334			objGridWidget.removeClass(g_vars.CLASS_REFRESH_SOON);
2335			
2336			childResponse.query_data = queryData;
2337			
2338			operateAjax_setHtmlGrid(childResponse, objGridWidget, isLoadMore);
2339			
2340			objGridWidget.trigger(g_vars.EVENT_AJAX_REFRESHED);
2341			g_objBody.trigger(g_vars.EVENT_AJAX_REFRESHED_BODY, [objGridWidget]);
2342
2343		});
2344
2345	}
2346
2347
2348	/**
2349	 * replace filters html
2350	 */
2351	function operateAjax_setHtmlWidgets(response, objFilters){
2352
2353		if(!objFilters)
2354			return(false);
2355
2356		if(objFilters.length == 0)
2357			return(false);
2358
2359		var objHtmlWidgets = getVal(response, "html_widgets");
2360
2361		if(!objHtmlWidgets)
2362			return(false);
2363
2364		if(objHtmlWidgets.length == 0)
2365			return(false);
2366
2367		var objHtmlDebug = getVal(response, "html_widgets_debug");
2368
2369		jQuery.each(objFilters, function(index, objFilter){
2370
2371			var widgetID = getElementWidgetID(objFilter);
2372
2373			if(!widgetID)
2374				return(true);
2375
2376			var html = getVal(objHtmlWidgets, widgetID);
2377
2378			if(!html)
2379				return(true);
2380
2381			var objHtml = jQuery(html);
2382
2383			var htmlInner = objHtml.html();
2384
2385			//set the class
2386
2387			var filterClassName = objHtml.attr("class");
2388
2389			filterClassName += " "+g_vars.CLASS_FILTER_INITED;
2390
2391			objFilter.attr("class", filterClassName);
2392
2393			objFilter.removeClass(g_vars.CLASS_INITING);
2394			objFilter.removeClass(g_vars.CLASS_REFRESH_SOON);
2395
2396			objFilter.html(htmlInner);
2397
2398
2399
2400			//---- put the debug if exists
2401
2402			var htmlDebug = null;
2403
2404			if(objHtmlDebug)
2405				var htmlDebug = getVal(objHtmlDebug, widgetID);
2406
2407			if(htmlDebug){
2408				var objParent = objFilter.parents("." + g_vars.class_widget_wrapper);
2409				var objDebug = objParent.find(".uc-div-ajax-debug");
2410
2411				if(objDebug.length)
2412					objDebug.replaceWith(htmlDebug);
2413			}
2414			
2415			objFilter.trigger(g_vars.EVENT_FILTER_RELOADED);
2416
2417		});
2418
2419	}
2420
2421	/**
2422	 * scroll to grid top
2423	 */
2424	function scrollToGridTop(objGrid){
2425
2426		var gapTop = 150;
2427
2428		var gridOffset = objGrid.offset().top;
2429
2430		var gridTop = gridOffset - gapTop;
2431
2432		if(gridTop < 0)
2433			gridTop = 0;
2434
2435		//check if the grid top is visible
2436
2437		var currentPos = jQuery(window).scrollTop();
2438
2439		if(currentPos <= gridOffset)
2440			return(false);
2441
2442		window.scrollTo({ top: gridTop, behavior: 'smooth' });
2443
2444	}
2445
2446
2447	/**
2448	 * operate the response
2449	 */
2450	function operateAjaxRefreshResponse(response, objGrid, objFilters, isLoadMore, isNoScroll){
2451		
2452		var isGridRefreshed = operateAjax_setHtmlGrid(response, objGrid, isLoadMore);
2453		
2454		operateAjax_setHtmlWidgets(response, objFilters);
2455		
2456		operateAjax_setHtmlSyngGrids(response, objGrid, isLoadMore);
2457		
2458		objGrid.trigger(g_vars.EVENT_AJAX_REFRESHED,[{isLoadMore:isLoadMore}]);
2459		g_objBody.trigger(g_vars.EVENT_AJAX_REFRESHED_BODY, [objGrid]);
2460		
2461		//trigger body as well
2462
2463		//scroll to grid top
2464		if(isLoadMore == false && isGridRefreshed == true && isNoScroll !== true){
2465						
2466			setTimeout(function(){
2467				
2468				scrollToGridTop(objGrid);
2469					
2470			},200);
2471
2472		}
2473
2474	}
2475
2476
2477	/**
2478	 * replace all occurances
2479	 */
2480	function replaceAll(text, from, to){
2481
2482		return text.split(from).join(to);
2483	};
2484
2485
2486
2487
2488	/**
2489	 * get response from ajax cache
2490	 */
2491	function getResponseFromAjaxCache(ajaxUrl, action, objData){
2492
2493	    var cacheKey = getAjaxCacheKey(ajaxUrl, action, objData);
2494
2495	    if(!cacheKey)
2496	    	return(false);
2497
2498	    var response = getVal(g_cache, cacheKey);
2499
2500	    return(response);
2501	}
2502
2503
2504	function ________AJAX_______________(){}
2505
2506	/**
2507	 * set this filter not to refresh next time
2508	 */
2509	function setNoRefreshFilter(objFilter){
2510
2511		objFilter.data("uc_norefresh",true);
2512
2513	}
2514
2515	/**
2516	 * show ajax error, should be something visible
2517	 */
2518	function showAjaxError(message){
2519
2520		alert(message);
2521
2522	}
2523
2524	/**
2525	 * get the debug object
2526	 */
2527	function getDebugObject(){
2528
2529		var objGrid = g_lastGridAjaxCall;
2530
2531		if(!objGrid)
2532			return(null);
2533
2534		var objDebug = objGrid.find("."+g_vars.CLASS_DIV_DEBUG);
2535
2536		if(objDebug.length)
2537			return(objDebug);
2538
2539		//insert if not exists
2540
2541		objGrid.after("<div class='"+g_vars.CLASS_DIV_DEBUG+"' style='padding:10px;display:none;background-color:#D8FCC6'></div>");
2542
2543		var objDebug = jQuery("body").find("."+g_vars.CLASS_DIV_DEBUG);
2544
2545		return(objDebug);
2546	}
2547
2548
2549	/**
2550	 * show ajax debug
2551	 */
2552	function showAjaxDebug(str){
2553
2554		trace("Ajax Error! - Check the debug");
2555
2556		str = jQuery.trim(str);
2557
2558		if(!str || str.length == 0)
2559			return(false);
2560
2561		var objStr = jQuery(str);
2562
2563		if(objStr.find("header").length || objStr.find("body").length){
2564			str = "Wrong ajax response!";
2565		}
2566
2567		var objDebug = getDebugObject();
2568
2569		if(!objDebug || objDebug.length == 0){
2570
2571			alert(str);
2572
2573			throw new Error("debug not found");
2574		}
2575
2576		objDebug.show();
2577		objDebug.html(str);
2578
2579	}
2580
2581
2582	/**
2583	 * small ajax request
2584	 */
2585	function ajaxRequest(ajaxUrl, action, objData, onSuccess){
2586				
2587		if(g_debugInitMode === true){
2588
2589			trace("debug init mode - skip request");
2590			return(false);
2591		}
2592
2593		if(g_showDebug == true){
2594			trace("ajax request");
2595			trace(ajaxUrl);
2596		}
2597
2598		if(!objData)
2599			var objData = {};
2600
2601		if(typeof objData != "object")
2602			throw new Error("wrong ajax param");
2603
2604		//check response from cache
2605		var responseFromCache = getResponseFromAjaxCache(ajaxUrl, action, objData);
2606
2607		if(responseFromCache){
2608
2609			//simulate ajax request
2610			setTimeout(function(){
2611				onSuccess(responseFromCache);
2612			}, 300);
2613
2614			return(false);
2615		}
2616
2617		var ajaxData = {};
2618		ajaxData["action"] = "unlimitedelements_ajax_action";
2619		ajaxData["client_action"] = action;
2620
2621		var ajaxtype = "get";
2622
2623		if(jQuery.isEmptyObject(objData) == false){
2624			ajaxData["data"] = objData;
2625			ajaxtype = "post";
2626		}
2627
2628
2629		var ajaxOptions = {
2630				type:ajaxtype,
2631				url:ajaxUrl,
2632				success:function(response){
2633
2634					if(!response){
2635						showAjaxError("Empty ajax response!");
2636						return(false);
2637					}
2638
2639					if(typeof response != "object"){
2640
2641						try{
2642
2643							response = jQuery.parseJSON(response);
2644
2645						}catch(e){
2646
2647							showAjaxDebug(response);
2648
2649							showAjaxError("Ajax Error!!! not ajax response");
2650							return(false);
2651						}
2652					}
2653
2654					if(response == -1){
2655						showAjaxError("ajax error!!!");
2656						return(false);
2657					}
2658
2659					if(response == 0){
2660						showAjaxError("ajax error, action: <b>"+action+"</b> not found");
2661						return(false);
2662					}
2663
2664					if(response.success == undefined){
2665						showAjaxError("The 'success' param is a must!");
2666						return(false);
2667					}
2668
2669
2670					if(response.success == false){
2671						showAjaxError(response.message);
2672						return(false);
2673					}
2674
2675					cacheAjaxResponse(ajaxUrl, action, objData, response);
2676
2677					if(typeof onSuccess == "function"){
2678
2679						onSuccess(response);
2680					}
2681
2682				},
2683				error:function(jqXHR, textStatus, errorThrown){
2684
2685					switch(textStatus){
2686						case "parsererror":
2687						case "error":
2688
2689							//showAjaxError("parse error");
2690
2691							showAjaxDebug(jqXHR.responseText);
2692
2693						break;
2694					}
2695				}
2696		}
2697
2698		if(ajaxtype == "post"){
2699			ajaxOptions.dataType = 'json';
2700			ajaxOptions.data = ajaxData
2701		}
2702
2703		var handle = jQuery.ajax(ajaxOptions);
2704
2705		return(handle);
2706	}
2707
2708
2709
2710	/**
2711	 * get grid items wrapper
2712	 */
2713	function getGridItemsWrapper(objGrid, isSecond){
2714
2715		var classItems = "uc-items-wrapper";
2716
2717		if(isSecond == true)
2718			classItems = "uc-items-wrapper2";
2719
2720		if(objGrid.hasClass(classItems))
2721			return(objGrid);
2722
2723		var objItemsWrapper = objGrid.find("."+classItems);
2724
2725		if(objItemsWrapper.length == 0 && isSecond == false)
2726			throw new Error("Missing items wrapper - with class: uc-items-wrapper");
2727
2728		if(objItemsWrapper.length == 0)
2729			return(null);
2730
2731		return(objItemsWrapper);
2732	}
2733
2734
2735	/**
2736	 * set ajax loader
2737	 */
2738	function showAjaxLoader(objElement){
2739
2740		objElement.addClass("uc-ajax-loading");
2741	}
2742
2743	/**
2744	 * hide ajax loader
2745	 */
2746	function hideAjaxLoader(objElement){
2747
2748		objElement.removeClass("uc-ajax-loading");
2749	}
2750
2751
2752	/**
2753	 * show multiple ajax loader
2754	 */
2755	function showMultipleAjaxLoaders(objElements, isShow){
2756
2757		if(!objElements)
2758			return(false);
2759
2760		if(objElements.length == 0)
2761			return(false);
2762
2763		jQuery.each(objElements,function(index, objElement){
2764
2765			objElement = jQuery(objElement);
2766
2767			if(isShow == true){
2768
2769				showAjaxLoader(objElement);
2770			}
2771			else
2772				hideAjaxLoader(objElement);
2773		});
2774
2775	}
2776
2777
2778	/**
2779	 * refresh ajax grid
2780	 */
2781	function refreshAjaxGrid(objGrid, refreshType){
2782				
2783		var isLoadMore = (refreshType == g_vars.REFRESH_MODE_LOADMORE);	 //for the output
2784		var isFiltersInit = (refreshType == "filters" || refreshType == "filters_children");
2785		
2786		//for the options - not refresh other filters
2787		var isLoadMoreMode = (refreshType == g_vars.REFRESH_MODE_LOADMORE || refreshType == g_vars.REFRESH_MODE_PAGINATION);
2788		
2789		//get all grid filters
2790		var objFilters = objGrid.data("filters");
2791
2792		if(!objFilters)
2793			return(false);
2794
2795		if(objFilters.length == 0)
2796			return(false);
2797
2798		if(objGrid.hasClass(g_vars.CLASS_GRID_NOREFRESH))
2799			return(false);
2800
2801		var params = {};
2802		if(refreshType == "filters_children")
2803			params["filters_init_type"] = "children";
2804		
2805		params["refresh_type"] = refreshType;
2806		
2807		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid, isFiltersInit, isLoadMoreMode, params);
2808		
2809		if(!objAjaxOptions){
2810
2811			trace("ajax options are null");
2812			return(false);
2813		}
2814
2815		var ajaxUrl = objAjaxOptions["ajax_url"];
2816		var urlReplace = objAjaxOptions["url_replace"];
2817		var arrTerms = objAjaxOptions["terms"];
2818
2819		if(g_vars.DEBUG_AJAX_OPTIONS == true){
2820
2821			trace("DEBUG AJAX OPTIONS");
2822			trace(objAjaxOptions);
2823			return(false);
2824		}
2825
2826		//set the url params
2827		var behave = objGrid.data("filterbehave");
2828
2829		var isSetUrl = (behave == "mixed" || behave == "mixed_back");
2830
2831		if(isFiltersInit == false && isSetUrl === true){
2832			
2833			try{
2834				
2835				if(behave == "mixed_back"){
2836	
2837					//save state for back button
2838	
2839					var gridID = objGrid.attr("id");
2840	
2841					//save initial state
2842					var isStateEmpty = jQuery.isEmptyObject(history.state);
2843					
2844					var objState = {"ucaction":"change", "ajaxurl":ajaxUrl, "gridid":gridID, selected_terms:arrTerms};
2845	
2846					if(isStateEmpty){
2847	
2848						var ajaxUrlInitial = objGrid.data("initajaxurl");
2849	
2850						objState["ajaxurl"] = ajaxUrlInitial;
2851	
2852						history.replaceState(objState, null, urlReplace);
2853					}
2854	
2855					history.pushState(objState, null, urlReplace);		//with back
2856	
2857				}
2858				else
2859					history.replaceState({}, null, urlReplace);		//without back
2860			
2861			}catch(error){
2862				trace("history push state error");
2863				trace(error);
2864			}
2865		}
2866		
2867		
2868		initGrid_setActiveFiltersData(objGrid, objAjaxOptions);
2869		
2870		doGridAjaxRequest(ajaxUrl, objGrid, objFilters, isLoadMore, isFiltersInit);
2871
2872	}
2873
2874
2875	/**
2876	 * do the actual grid ajax request
2877	 */
2878	function doGridAjaxRequest(ajaxUrl, objGrid, objFilters, isLoadMore, isFiltersInit){
2879		
2880		var objEmptyMessage = getGridEmptyMessage(objGrid);
2881
2882		//set the loaders
2883
2884		if(isLoadMore !== true && isFiltersInit !== true){
2885
2886			showAjaxLoader(objGrid);
2887
2888			if(objEmptyMessage)
2889				showAjaxLoader(objEmptyMessage);
2890		}
2891
2892		var objFiltersToReload = objFilters.filter(function(objFilter){
2893
2894			return objFilter.hasClass(g_vars.CLASS_REFRESH_SOON);
2895		});
2896
2897		showMultipleAjaxLoaders(objFiltersToReload, true);
2898
2899		if(g_lastSyncGrids && isLoadMore !== true){
2900
2901			showMultipleAjaxLoaders(g_lastSyncGrids, true);
2902		}
2903
2904		//ajax reload
2905		g_lastGridAjaxCall = objGrid;
2906		
2907		objGrid.trigger(g_vars.EVENT_BEFORE_REFRESH);
2908		
2909		var lastAjaxHandle = objGrid.data("last_ajax_refresh_handle");
2910
2911		if(lastAjaxHandle){
2912			lastAjaxHandle.abort();
2913		}
2914		
2915		//--- debug before refresh
2916		
2917		if(g_debugBeforeRefreshMode == true){
2918			
2919			alert("Debug before refresh - please turn if off");
2920			return(false);
2921		}
2922		
2923		var ajaxHandle = ajaxRequest(ajaxUrl,null,null, function(response){
2924
2925			if(isLoadMore !== true){
2926				hideAjaxLoader(objGrid);
2927
2928				if(objEmptyMessage)
2929					hideAjaxLoader(objEmptyMessage);
2930			}
2931
2932			showMultipleAjaxLoaders(objFilters, false);
2933
2934			if(g_lastSyncGrids)
2935				showMultipleAjaxLoaders(g_lastSyncGrids, false);
2936			
2937			operateAjaxRefreshResponse(response, objGrid, objFilters, isLoadMore);
2938
2939			onAfterGridRefresh(objGrid);
2940
2941		});
2942
2943		objGrid.data("last_ajax_refresh_handle", ajaxHandle);
2944
2945	}
2946
2947	/**
2948	 * do some actions after grid refresh, if needed
2949	 */
2950	function onAfterGridRefresh(objGrid){
2951
2952		//refresh child grids
2953
2954		var isInitRefesh = objGrid.data("init_refresh_child_filters");
2955
2956		if(isInitRefesh === true){
2957
2958			objGrid.removeData("init_refresh_child_filters");
2959
2960			//refresh child filters if there are selected main after init
2961
2962			var objFilters = objGrid.data("filters");
2963
2964			var arrSelectedMain = getSelectedFilters(objFilters, "main");
2965
2966			if(arrSelectedMain.length)
2967				refreshAjaxGrid(objGrid, "filters_children");
2968		}
2969
2970	}
2971
2972
2973	function ________STATE_RELATED_______________(){}
2974
2975
2976	/**
2977	 * do history
2978	 */
2979	function changeToHistoryState(state){
2980
2981		if(g_showDebug == true){
2982			trace("change to history");
2983			trace(state);
2984		}
2985
2986		var ajaxUrl = getVal(state, "ajaxurl");
2987
2988		var gridID = getVal(state, "gridid");
2989
2990		var arrTerms = getVal(state, "selected_terms");
2991
2992		if(!gridID)
2993			return(false);
2994
2995		if(!ajaxUrl)
2996			return(false);
2997
2998		var objGrid = jQuery("#"+gridID);
2999
3000		var objFilters = objGrid.data("filters");
3001
3002		if(!objFilters)
3003			return(false);
3004
3005		//select by terms
3006
3007		selectFilterItemsByTerms(objFilters, arrTerms);
3008
3009		var responseFromCache = getResponseFromAjaxCache(ajaxUrl);
3010
3011		if(!responseFromCache){
3012
3013			//do ajax request
3014
3015			doGridAjaxRequest(ajaxUrl, objGrid, objFilters);
3016
3017			return(false);
3018		}
3019
3020		//get data from cache
3021
3022		//trace("restore");
3023		//trace(responseFromCache);
3024
3025		operateAjaxRefreshResponse(responseFromCache, objGrid, objFilters, false, true);
3026
3027	}
3028
3029	/**
3030	 * on pop state, if it's a grid state, set the grid
3031	 */
3032	function onPopState(){
3033
3034		if(!history.state)
3035			return(true);
3036
3037		var action = getVal(history.state, "ucaction");
3038
3039		if(!action)
3040			return(true);
3041
3042		switch(action){
3043			case "change":
3044
3045				changeToHistoryState(history.state);
3046
3047			break;
3048			default:
3049				throw new Error("Wrong history action: " + action);
3050			break;
3051		}
3052
3053	}
3054
3055
3056	function ________RUN_______________(){}
3057
3058
3059	/**
3060	 * get url filters string
3061	 */
3062	function getGridUrlFiltersString(objGrid){
3063
3064		var objAjaxOptions = getGridAjaxOptions_simple(objGrid);
3065
3066		if(!objAjaxOptions)
3067			return("");
3068
3069		var strFilters = getVal(objAjaxOptions, "filters_string");
3070		
3071		return(strFilters);
3072	}
3073
3074
3075	/**
3076	 * get simply the grid ajax options
3077	 */
3078	function getGridAjaxOptions_simple(objGrid){
3079
3080		var objFilters = objGrid.data("filters");
3081		
3082		if(!objFilters)
3083			return(null);
3084		
3085		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid, false,false,{getonly:true});
3086
3087		if(!objAjaxOptions)
3088			return(null);
3089
3090		return(objAjaxOptions);
3091	}
3092	
3093	/**
3094	 * check that element is hidden only by display:none. ":hidden" checks width and height as well
3095	 */
3096	function isElementHiddenByDisplayNone(objElement) {
3097	    	    
3098		var element = objElement[0];
3099		
3100		var hidden = window.getComputedStyle(element).display == "none";
3101		
3102	    return hidden;
3103	};	
3104
3105	/**
3106	* get operator term
3107	*/
3108	function getObjOperatorTerm(operator, dataTerms){
3109		var slug = (operator == "and")?"__ucand__":"__ucor__";
3110		var firstTerm = dataTerms[0];        
3111		var objOperatorTerm = {
3112			taxonomy: firstTerm.taxonomy,
3113			slug: slug,
3114			id:null
3115		};
3116		
3117		return(objOperatorTerm);
3118	}
3119
3120	/**
3121	 * get operator marker for meta items (same as terms __ucand__/__ucor__)
3122	 */
3123	function getObjOperatorMeta(operator, dataMeta){
3124
3125		var opValue = (operator == "and") ? "__ucand__" : "__ucor__";
3126		var firstMeta = dataMeta[0];
3127		var metaKey = getVal(firstMeta, "meta_key");
3128
3129		if(!metaKey)
3130			metaKey = getVal(firstMeta, "slug");
3131
3132		return({
3133			type: "meta",
3134			meta_key: metaKey,
3135			meta_value: opValue,
3136			slug: opValue,
3137			id: null
3138		});
3139	}
3140
3141	/**
3142	 * get grid ajax options
3143	 */
3144	function getGridAjaxOptions(objFilters, objGrid, isFiltersInitMode, isLoadMoreMode, params){
3145		
3146		if(!isLoadMoreMode)
3147			var isLoadMoreMode = false;
3148		
3149		if(g_showDebug){
3150			trace("getGridAjaxOptions");
3151
3152			trace("Filters:");
3153			trace(objFilters);
3154			
3155			trace("grid:");
3156			trace(objGrid);
3157			trace("is init: " + isFiltersInitMode);
3158
3159			trace("params: ");
3160			trace(params);
3161
3162		}
3163
3164		//filter only visible elements (by it's parents)
3165		
3166		var objVisibleFilters = objFilters.filter(function(objFilter){
3167			
3168			var objParent = getFilterWrapper(objFilter);
3169			
3170			var isHidden = isElementHiddenByDisplayNone(objParent);
3171			
3172			return(!isHidden);
3173		});
3174		
3175		
3176		if(objVisibleFilters.length < objFilters.length){
3177			
3178			if(objVisibleFilters.length == 0){
3179				
3180				if(g_showDebug)
3181					trace("no visible filters");
3182				
3183				var objFilters = [];
3184			}
3185			else{		//test for mobile drawer
3186				
3187				var objFirstFilter = jQuery(objVisibleFilters[0]);
3188				var visibleFilterType = getFilterType(objFirstFilter, true);
3189				
3190				//exception for mobile drawer
3191				if(visibleFilterType !=  g_types.GENERAL_MOBILE_DRAWER){
3192					
3193					var objFilters = objVisibleFilters;
3194					
3195					if(g_showDebug){
3196						trace("Visible Filters: ");
3197						trace(objFilters);
3198					}
3199				}
3200				
3201			}//end else
3202			
3203			
3204		} //end visible filters test
3205		
3206		
3207		if(!objFilters || objFilters.length == 0)
3208			return(null);
3209
3210		var urlReplace = g_urlBase;
3211
3212		var urlAjax = g_urlBase;
3213
3214		var strRefreshIDs = "";
3215
3216		var isReplaceMode = false;
3217		var page = null;
3218		var offset = null;
3219		var numItems = null;
3220		var arrTerms = [];
3221		var objTaxIDs = {};
3222		var objAuthorIDs = {};
3223		var strSelectedTerms = "";
3224		var strSelectedAuthors = "";
3225		var strSelectedMeta = "";
3226		var search = "";
3227		var price_from, price_to;
3228		var arrAuthors = [];
3229		var arrMeta = [];
3230		var orderby = null;
3231		var orderby_metaname = null;
3232		var orderby_metatype = null;
3233		var orderdir = null;
3234		var title_start = null;
3235		var addSyncedGrids = true;
3236		var arrAllFiltersData;		//all data gethered for the active filters
3237		var arrFiltersForInit = [];
3238		var urlAddFromFilters = "";
3239		var isPaginationClicked = false;
3240		var isGetUrlOnly = getVal(params,"getonly");
3241
3242		var initModeType = getVal(params,"filters_init_type");
3243
3244		var initModeChildrens = false;
3245		if(isFiltersInitMode == true && initModeType == "children")
3246			initModeChildrens = true;
3247
3248		var wasInitMode = objGrid.data("was_init_mode");
3249
3250		var arrFilterIDs = {};
3251		
3252		var advancedSearchFilterID;
3253		
3254		var refreshType = getVal(params,"refresh_type");
3255		
3256		if(refreshType == g_vars.REFRESH_MODE_PAGINATION)
3257			isPaginationClicked = true;
3258
3259		var child_auto, childAutoTaxonomy, childAutoSlug, childAutoString = "";
3260				
3261		//get ajax options
3262		jQuery.each(objFilters, function(index, objFilter){
3263			
3264			//protection against duplicate id's
3265			var id = objFilter.attr("id");
3266
3267			if(arrFilterIDs.hasOwnProperty(id) == true){
3268
3269				trace("problematic filter: ");
3270				trace(objFilter);
3271
3272				trace("original filter found: ");
3273				trace(arrFilterIDs[id]);
3274
3275				trace("filters list: ");
3276				trace(objFilters);
3277
3278				throw new Error("Duplicate Filter ID found: " + id);
3279			}
3280						
3281			arrFilterIDs[id] = objFilter;
3282
3283			var isNoRefresh = objFilter.data("uc_norefresh");
3284			var filterRole = objFilter.data("role");
3285						
3286			var type = getFilterType(objFilter);
3287			
3288			if(g_showDebug == true){
3289
3290				trace("filter: "+type+", role: "+filterRole);
3291				trace(objFilter);
3292			}
3293
3294			var urlAdd = objFilter.attr(g_vars.ATTRIBUTE_URLADD);
3295
3296			if(urlAdd)
3297				urlAddFromFilters = addUrlParam(urlAddFromFilters, urlAdd);
3298			
3299			switch(type){
3300				case g_types.PAGINATION:
3301						
3302						//run pagination only if it's clicked, unless reset pagination
3303						var isClicked = objFilter.hasClass(g_vars.CLASS_CLICKED);
3304						if(isClicked == true || isFiltersInitMode == true){
3305
3306							 var paginationData = getPaginationSelectedData(objFilter);
3307							 
3308							 var paginationPage = getVal(paginationData, "page");
3309							 
3310							 if(paginationPage)
3311								 page = paginationPage;		//never set the url
3312							 
3313							 //set page from url
3314							 if(isFiltersInitMode == true && !page && g_vars.ucpage_url)
3315								 page = g_vars.ucpage_url;
3316							
3317							 if(g_showDebug){
3318								 trace("pagination data");
3319								 trace(paginationData);
3320							 }
3321
3322							objFilter.removeClass(g_vars.CLASS_CLICKED);
3323						}
3324						
3325
3326				break;
3327				case g_types.LOADMORE:
3328
3329					//check if loadmore is before grid in init mode
3330					var isLoadMoreBeforeGrid = false;
3331					if(isFiltersInitMode == true){
3332						var offsetLoadMore = objFilter.offset();
3333						var offsetGrid = objGrid.offset();
3334						
3335						if(offsetLoadMore.top < offsetGrid.top){
3336							isLoadMoreBeforeGrid = true;
3337							
3338							if(g_showDebug == true)
3339								trace("Loadmore before grid - process in init mode");
3340						}
3341					}
3342					
3343					if(isFiltersInitMode == true && isLoadMoreBeforeGrid == false)
3344						return(true);
3345
3346					//run load more only if it's clicked, unless reset load more
3347					var isClicked = objFilter.hasClass(g_vars.CLASS_CLICKED);
3348					if(isClicked == true){
3349
3350						var loadMoreData = getLoadMoreUrlData(objFilter);
3351						offset = loadMoreData.offset;
3352						numItems = loadMoreData.numItems;
3353
3354						var isSingleGrid = loadMoreData.singlegrid;
3355
3356						if(isSingleGrid == true)
3357							addSyncedGrids = false;
3358
3359						if(!offset)
3360							urlAjax = null;
3361
3362						objFilter.removeClass(g_vars.CLASS_CLICKED);
3363					}
3364
3365				break;
3366				case g_types.TERMS_LIST:
3367				case g_types.SELECT:
3368
3369					//if not init mode - take first item
3370					var objTerm = getTermsListSelectedTerm(objFilter);
3371					var filterSource = objFilter.data("filtersource");
3372										
3373					if(objTerm){
3374						
3375						if(isFiltersInitMode == false){
3376							
3377							if(filterSource == "authors")
3378								arrAuthors.push(objTerm);
3379							else if(filterSource == "meta")
3380								arrMeta.push(objTerm);
3381							else
3382								arrTerms.push(objTerm);
3383						}
3384						else{
3385							
3386							//INIT MODE
3387							
3388							//add terms if the filter is not initing itself
3389							var isInit = objFilter.data("initafter");
3390							
3391							//add terms, if only children mode and the filter not child
3392							if(initModeChildrens == true && filterRole != "child")
3393								arrTerms.push(objTerm);
3394							else
3395								if(isInit != true){
3396									
3397									if(filterSource == "authors")
3398										arrAuthors.push(objTerm);
3399									else if(filterSource == "meta")
3400										arrMeta.push(objTerm);
3401									else
3402										arrTerms.push(objTerm);
3403									
3404								}
3405							
3406							//set selected terms string
3407							
3408							var termID = objTerm.id;
3409							
3410							if(filterSource == "authors"){
3411								
3412								if(strSelectedAuthors)
3413									strSelectedAuthors +=",";
3414								
3415								strSelectedAuthors += termID;
3416							}
3417							else if(filterSource == "meta"){
3418
3419								var metaKey = getVal(objTerm, "meta_key");
3420								if(!metaKey)
3421									metaKey = getVal(objTerm, "slug");
3422
3423								if(metaKey){
3424									var metaValue = getVal(objTerm, "meta_value");
3425									if(!metaValue)
3426										metaValue = "";
3427
3428									var metaPair = metaKey + g_options.urlkey_taxsap + metaValue;
3429
3430									if(strSelectedMeta)
3431										strSelectedMeta +=",";
3432
3433									strSelectedMeta += metaPair;
3434								}
3435							}
3436							else{
3437								if(strSelectedTerms)
3438									strSelectedTerms +=",";
3439								
3440								strSelectedTerms += termID;
3441							}
3442							
3443						}
3444					}
3445
3446					//replace mode
3447
3448					var modeReplace = objFilter.data("replace-mode");
3449					if(modeReplace === true)
3450						isReplaceMode = true;
3451
3452					if(isLoadMoreMode == true)
3453						isNoRefresh = true;
3454
3455					//debug
3456					if(g_showDebug == true){
3457
3458						trace("Selected Term: ");
3459						trace(objTerm);
3460					}
3461
3462				break;
3463				case g_types.SUMMARY:
3464
3465					isNoRefresh = true;
3466
3467					//take nothing
3468				break;
3469				case g_types.SEARCH:
3470
3471					isNoRefresh = true;
3472
3473					var objInput = objFilter.find("input");
3474
3475					search = objInput.val();
3476					search = search.trim();
3477					
3478					//add id
3479					var isAdvancedSearch = objFilter.data("advancedsearch");
3480					
3481					if(isAdvancedSearch == true)
3482						advancedSearchFilterID = getElementWidgetID(objFilter);
3483										
3484				break;
3485				case g_types.GENERAL:
3486					
3487					var generalType = objFilter.data("generaltype");
3488				
3489					if(generalType == g_types.GENERAL_MOBILE_DRAWER)
3490						return(true);
3491					
3492					var generalIsNoRefresh = objFilter.data("norefresh");
3493					
3494					if(generalIsNoRefresh === true)
3495						isNoRefresh = true;
3496					
3497					var filterData = getGeneralFilterData(objFilter);
3498					
3499					//add terms
3500					
3501					var dataTerms = getVal(filterData,"terms");
3502										
3503					if(dataTerms && dataTerms.length){	
3504
3505						var isOperatoeAdded = false;
3506
3507						if(filterRole == "main"){
3508							
3509							var operator = getVal(filterData,"operator");
3510										
3511							if(operator === "and" || operator === "or"){									
3512								var objOperatorTerm = getObjOperatorTerm(operator, dataTerms);
3513						
3514								dataTerms.push(objOperatorTerm);	
3515								isOperatoeAdded = true;
3516							}
3517						}
3518
3519						if(dataTerms.length == 1){		//single term			
3520						  arrTerms.push(dataTerms[0]);
3521						}
3522						
3523						if(dataTerms.length > 1){	//multiple terms
3524							//push the end or or operator
3525							var operator = getVal(filterData,"operator");
3526									
3527							if(isOperatoeAdded == false){
3528
3529								if(operator === "and" || operator === "or"){								
3530									var objOperatorTerm = getObjOperatorTerm(operator, dataTerms);
3531		
3532									dataTerms.push(objOperatorTerm);
3533								}
3534							}
3535							
3536							arrTerms.push(dataTerms);	//multiple (grouping)
3537						}
3538						
3539						
3540						//set selected terms string if init mode
3541						
3542						if(isFiltersInitMode == true && dataTerms && dataTerms.length){
3543							
3544							var arrTermsForSelect = [];
3545							
3546							if(jQuery.isArray(arrTerms))
3547								arrTermsForSelect = arrTerms.flat();
3548							
3549							jQuery.each(arrTermsForSelect, function(index, term){
3550								
3551								var termID = getVal(term,"id");
3552								
3553								if(!termID)
3554									return(true);
3555								
3556								if(strSelectedTerms)
3557									strSelectedTerms +=",";
3558								
3559								strSelectedTerms += termID;
3560							});
3561							
3562						}
3563					}
3564					
3565					//add authors
3566					var dataAuthors = getVal(filterData,"authors");
3567					
3568					if(dataAuthors && dataAuthors.length){
3569						
3570						//gather authors list
3571						jQuery.each(dataAuthors, function(index, author){
3572							arrAuthors.push(author);
3573						});
3574						
3575						//set selected authors string if init mode
3576						
3577						if(isFiltersInitMode == true){
3578							
3579							jQuery.each(dataAuthors, function(index, author){
3580								
3581								var authorID = getVal(author,"id");
3582								
3583								if(!authorID)
3584									return(true);
3585								
3586								if(strSelectedAuthors)
3587									strSelectedAuthors +=",";
3588								
3589								strSelectedAuthors += authorID;
3590							});
3591							
3592						}
3593					}
3594
3595					//add meta - same grouping as terms (checkbox OR = group, no .*)
3596					var dataMeta = getVal(filterData,"meta");
3597
3598					if(dataMeta && dataMeta.length){
3599
3600						var isMetaOperatorAdded = false;
3601
3602						if(filterRole == "main"){
3603
3604							var metaOperator = getVal(filterData,"operator");
3605
3606							if(metaOperator === "and" || metaOperator === "or"){
3607								dataMeta.push(getObjOperatorMeta(metaOperator, dataMeta));
3608								isMetaOperatorAdded = true;
3609							}
3610						}
3611
3612						if(dataMeta.length == 1){
3613							arrMeta.push(dataMeta[0]);
3614						}
3615
3616						if(dataMeta.length > 1){
3617
3618							var metaOperator = getVal(filterData,"operator");
3619
3620							if(isMetaOperatorAdded == false){
3621
3622								if(metaOperator === "and" || metaOperator === "or")
3623									dataMeta.push(getObjOperatorMeta(metaOperator, dataMeta));
3624							}
3625
3626							arrMeta.push(dataMeta);	//multiple (grouping) - OR by default
3627						}
3628
3629						if(isFiltersInitMode == true){
3630
3631							jQuery.each(dataMeta, function(index, metaItem){
3632
3633								var metaKey = getVal(metaItem,"meta_key");
3634								if(!metaKey)
3635									metaKey = getVal(metaItem,"slug");
3636
3637								if(!metaKey)
3638									return(true);
3639
3640								var metaValue = getVal(metaItem,"meta_value");
3641								if(!metaValue)
3642									metaValue = "";
3643
3644								if(metaValue === "__ucand__" || metaValue === "__ucor__")
3645									return(true);
3646
3647								var metaPair = metaKey + g_options.urlkey_taxsap + metaValue;
3648
3649								if(strSelectedMeta)
3650									strSelectedMeta +=",";
3651
3652								strSelectedMeta += metaPair;
3653							});
3654
3655						}
3656					}
3657					
3658					
3659					if(g_showDebug == true){
3660						trace("Filter Data:");
3661						trace(filterData);
3662					}
3663					
3664					if(generalType == "price" && isFiltersInitMode == false){
3665						
3666						var priceFromArg = getVal(filterData,"price_from");
3667						var priceToArg = getVal(filterData,"price_to");
3668
3669						if(priceFromArg)
3670							price_from = roundToOneDecimal(priceFromArg);
3671
3672						if(priceToArg)
3673							price_to = roundToOneDecimal(priceToArg);
3674					}
3675					
3676					
3677					//add title start
3678					
3679					var titleStartArg = getVal(filterData, "title_start");
3680					if(titleStartArg)
3681						title_start = titleStartArg;
3682					
3683					//handle sort
3684					var argOrderby = getVal(filterData,"orderby");
3685					if(argOrderby && argOrderby != "default"){
3686						orderby = argOrderby;
3687
3688						orderby_metaname = getVal(filterData,"metaname");
3689						orderby_metatype = getVal(filterData,"metatype");
3690					}
3691
3692					var argOrderDir = getVal(filterData,"orderdir");
3693					if(argOrderDir && argOrderDir != "default")
3694						orderdir = argOrderDir;
3695
3696					if(isLoadMoreMode == true)
3697						isNoRefresh = true;
3698					
3699				break;
3700				default:
3701					throw new Error("Unknown filter type: "+type);
3702				break;
3703			}
3704
3705			
3706			//handle filters init mode
3707			
3708			if(isFiltersInitMode == true){
3709								
3710				var isInit = objFilter.data("initafter");
3711
3712					
3713				if(isInit != true){
3714					isNoRefresh = true;
3715				}
3716
3717				//refresh parents only
3718				if(initModeChildrens == false && filterRole == "child")
3719					isNoRefresh = true;
3720
3721				//refresh children only
3722				if(initModeChildrens == true && filterRole != "child")
3723					isNoRefresh = true;
3724				
3725				if(isNoRefresh == false){
3726					arrFiltersForInit.push(objFilter);					
3727				}
3728								
3729			}
3730			
3731			
3732			//if hidden - no refresh
3733			
3734			var isFilterHidden = objFilter.hasClass(g_vars.CLASS_HIDDEN);
3735			if(isFilterHidden == true)
3736				isNoRefresh = true;
3737			
3738			objFilter.data("uc_norefresh",false);
3739			
3740			var isMainFilter = (filterRole == "main");
3741			var isTermChild = (filterRole == "term_child");
3742			
3743			//add to refresh filter if it's qualify
3744
3745			var isRefresh = true;
3746			
3747			if(isFiltersInitMode == false && (isMainFilter === true || isTermChild == true))
3748				isRefresh = false;
3749
3750			if(isNoRefresh === true)
3751				isRefresh = false;
3752						
3753			if(g_showDebug == true){
3754				trace("Filter Refresh: "+isRefresh);
3755				if(isRefresh == true){
3756					trace("isFiltersInitMode: "+isFiltersInitMode);
3757					trace("isMainFilter: "+isMainFilter);
3758					trace("isTermChild: "+isTermChild);
3759					trace("isNoRefresh: "+isNoRefresh);
3760				}
3761			}
3762			
3763			if(isRefresh == true){
3764
3765				var filterWidgetID = getElementWidgetID(objFilter);
3766
3767				//add test tax id's for init mode
3768				var filterSource = objFilter.data("filtersource");
3769				if(filterSource == "authors" && isFiltersInitMode == true){
3770					//add test author id's for init mode
3771					objAuthorIDs = getFilterTaxIDs(objFilter, objAuthorIDs);
3772				}else{
3773					objTaxIDs = getFilterTaxIDs(objFilter, objTaxIDs);
3774				}
3775
3776				if(strRefreshIDs)
3777					strRefreshIDs += ",";
3778
3779				strRefreshIDs += filterWidgetID;
3780
3781				if(!isGetUrlOnly)
3782					objFilter.addClass(g_vars.CLASS_REFRESH_SOON);
3783			}
3784			
3785			if(filterRole == "main"){
3786				var objTerm = getTermsListSelectedTerm(objFilter);
3787
3788				if(objTerm && objTerm != null){
3789
3790					childAutoTaxonomy = objTerm.taxonomy;
3791					childAutoSlug = objTerm.slug;
3792				}
3793			}
3794			
3795			if(filterRole == "child_auto" && arrTerms.length){
3796				child_auto = true;
3797
3798				if(childAutoTaxonomy && childAutoSlug){
3799					childAutoString = "&ucmainterm=" + childAutoTaxonomy + ":" + childAutoSlug;
3800				}
3801			
3802			}
3803
3804
3805		});		//end filters iteration
3806
3807		
3808		//add init filters additions
3809
3810		var urlAddition_filtersTest = "";
3811		var strTaxIDs = getTermDsList(objTaxIDs);
3812		var strAuthorIDs = getTermDsList(objAuthorIDs);
3813				
3814		if(isFiltersInitMode == true){
3815
3816			if(!strTaxIDs && !strAuthorIDs && arrFiltersForInit.length == 0)
3817				urlAjax = null;
3818			else{
3819
3820				if(urlAddition_filtersTest)
3821					urlAddition_filtersTest += "&";
3822				
3823				urlAddition_filtersTest += "modeinit=true";
3824			}
3825		}
3826
3827		//test terms - only if there are terms in query, or mode init
3828				
3829		if(strTaxIDs && (search || arrTerms.length || isFiltersInitMode == true || wasInitMode === true) ){
3830			 
3831			if(urlAddition_filtersTest)
3832				urlAddition_filtersTest += "&";
3833			
3834			urlAddition_filtersTest += "testtermids="+strTaxIDs;
3835		}
3836		
3837		//test authors - only if there are authors in query, or mode init (author mode)
3838		if(strAuthorIDs && (search || arrAuthors.length || isFiltersInitMode == true || wasInitMode === true) ){
3839			
3840			if(urlAddition_filtersTest)
3841				urlAddition_filtersTest += "&";
3842			
3843			urlAddition_filtersTest += "testauthorids="+strAuthorIDs;
3844		}
3845
3846		g_lastSyncGrids = null;
3847
3848		if(urlAjax == null)
3849			return(null);
3850
3851		var dataLayout = getElementLayoutData(objGrid, addSyncedGrids);
3852
3853		var widgetID = dataLayout["widgetid"];
3854		var layoutID = dataLayout["layoutid"];
3855
3856		//disable synced
3857
3858		if(addSyncedGrids == false){
3859
3860			var syncedWidgetIDs = false;
3861			g_lastSyncGrids = null;
3862
3863		}else{
3864
3865			var syncedWidgetIDs = getVal(dataLayout,"synced_widgetids");
3866			g_lastSyncGrids = getVal(dataLayout,"synced_grids");
3867		}
3868		
3869		var urlFilterString = "";
3870		
3871		var urlAddition = "ucfrontajaxaction=getfiltersdata&layoutid="+layoutID+"&elid="+widgetID;
3872		
3873		urlAjax = addUrlParam(urlAjax, urlAddition);
3874		
3875		if(g_isGutenberg == true)
3876			urlAjax = addUrlParam(urlAjax, "platform=gutenberg");
3877
3878		if(syncedWidgetIDs)
3879			urlAjax += "&syncelids="+syncedWidgetIDs;
3880
3881		if(urlAddition_filtersTest)
3882			urlAjax = addUrlParam(urlAjax, urlAddition_filtersTest);
3883
3884		if(price_from){
3885			urlAjax += "&ucpricefrom="+price_from;
3886
3887			if(g_showDebug == true){
3888				trace("add price from");
3889				trace(urlAjax);
3890			}
3891		}
3892
3893		if(price_to){
3894			urlAjax += "&ucpriceto="+price_to;
3895
3896			if(g_showDebug == true){
3897				trace("add price to");
3898				trace(urlAjax);
3899			}
3900		}
3901		
3902		if(title_start){
3903			
3904			if(g_showDebug == true)
3905				trace("add title start: "+title_start);
3906			
3907			urlAjax += "&titlestart="+title_start;
3908			urlReplace = addUrlParam(urlReplace, "titlestart="+title_start);
3909		}
3910			
3911		
3912		if(page){
3913			urlAjax += "&ucpage="+page;
3914			
3915			urlReplace = addUrlParam(urlReplace, "ucpage="+page);
3916		}
3917
3918		if(numItems)
3919			urlAjax += "&uccount="+numItems;
3920				
3921		if(arrTerms.length){
3922			
3923			var strTerms = buildTermsQuery(arrTerms);
3924		
3925			if(strTerms){
3926				urlAjax += "&ucterms="+strTerms;
3927				//set the url params as well
3928				urlReplace = addUrlParam(urlReplace, "ucterms="+strTerms);
3929				urlFilterString = addUrlParam(urlFilterString, "ucterms="+strTerms);
3930			}
3931			
3932		}
3933		
3934		//add authors
3935		if(arrAuthors.length){
3936			
3937			var strAuthors = "";
3938			jQuery.each(arrAuthors, function(index, author){
3939				var authorID = getVal(author, "id");
3940				if(authorID){
3941					if(strAuthors)
3942						strAuthors += ",";
3943					strAuthors += authorID;
3944				}
3945			});
3946			
3947			if(strAuthors){
3948				urlAjax += "&ucauthors="+strAuthors;
3949				urlReplace = addUrlParam(urlReplace, "ucauthors="+strAuthors);
3950				urlFilterString = addUrlParam(urlFilterString, "ucauthors="+strAuthors);
3951			}
3952		}
3953
3954		//add meta
3955		if(arrMeta.length){
3956
3957			var strMeta = buildMetaQuery(arrMeta);
3958
3959			if(strMeta){
3960				urlAjax += "&ucmeta="+strMeta;
3961				urlReplace = addUrlParam(urlReplace, "ucmeta="+strMeta);
3962				urlFilterString = addUrlParam(urlFilterString, "ucmeta="+strMeta);
3963			}
3964		}
3965		
3966		 if(child_auto && arrTerms.length && childAutoString != ""){
3967			 urlAjax += childAutoString;
3968		 }
3969
3970		if(orderby){
3971			
3972			urlAjax += "&ucorderby="+orderby;
3973			urlReplace = addUrlParam(urlReplace, "ucorderby="+orderby);
3974
3975			if(orderby_metaname){
3976				urlAjax += "&ucorderby_meta="+orderby_metaname;
3977				urlReplace = addUrlParam(urlReplace, "ucorderby_meta="+orderby_metaname);
3978			}
3979
3980			if(orderby_metatype){
3981				urlAjax += "&ucorderby_metatype="+orderby_metatype;
3982				urlReplace = addUrlParam(urlReplace, "ucorderby_metatype="+orderby_metatype);
3983			}
3984
3985		}
3986
3987		if(orderdir){
3988			urlAjax += "&ucorderdir="+orderdir;
3989
3990			urlReplace = addUrlParam(urlReplace, "ucorderdir="+orderdir);
3991		}
3992		
3993		if(isFiltersInitMode && strSelectedTerms && strSelectedTerms !== "undefined")
3994			urlAjax += "&ucinitselectedterms="+strSelectedTerms;
3995		
3996		if(isFiltersInitMode && strSelectedAuthors && strSelectedAuthors !== "undefined")
3997			urlAjax += "&ucinitselectedauthors="+strSelectedAuthors;
3998
3999		if(isFiltersInitMode && strSelectedMeta && strSelectedMeta !== "undefined")
4000			urlAjax += "&ucinitselectedmeta="+strSelectedMeta;
4001		
4002		//add refresh ids
4003		if(strRefreshIDs)
4004			urlAjax += "&addelids="+strRefreshIDs;
4005		
4006		if(isReplaceMode == true)
4007			urlAjax += "&ucreplace=1";
4008
4009		//search
4010		if(search){
4011			search = encodeURIComponent(search);
4012			
4013			//search = escape(search);
4014
4015			urlAjax = addUrlParam(urlAjax, "ucs=" + search);
4016
4017			urlFilterString = addUrlParam(urlFilterString, "ucs=" + search);
4018			
4019			urlReplace = addUrlParam(urlReplace, "ucs=" + search);
4020			
4021			//add special search id
4022			if(advancedSearchFilterID)
4023				urlAjax = addUrlParam(urlAjax, "ucsid=" + advancedSearchFilterID);
4024			
4025		}
4026		
4027		//avoid duplicates - exclude, disable the offset
4028		
4029		if(objGrid.hasClass("uc-avoid-duplicates")){
4030			
4031			var objCurrentGrid = objGrid;
4032			if(isLoadMoreMode == true)
4033				objCurrentGrid = null;		//load with exclude but without offset
4034			
4035			var strExcludePostIDs = getExcludePostIDs(objCurrentGrid);		//exclude current grid
4036			
4037			if(strExcludePostIDs){
4038				urlAjax += "&ucexclude="+strExcludePostIDs;
4039				
4040				if(isLoadMoreMode == true)
4041					offset = null;
4042	
4043				urlFilterString = addUrlParam(urlFilterString, "ucexclude=" + strExcludePostIDs);
4044			}
4045		
4046		}
4047		
4048		
4049		if(offset){
4050			urlAjax += "&ucoffset="+offset;
4051
4052			urlFilterString = addUrlParam(urlFilterString, "offset=" + offset);
4053			
4054		}
4055
4056		//add custom additional attributes
4057
4058		if(urlAddFromFilters){
4059			urlAjax += addUrlParam(urlAjax, urlAddFromFilters);
4060			urlFilterString = addUrlParam(urlFilterString, urlAddFromFilters);
4061		}
4062
4063		//remove the "?" from first
4064		if(urlFilterString)
4065			urlFilterString = urlFilterString.substring(1);
4066
4067
4068		//remember init mode
4069		if(isFiltersInitMode == true)
4070			objGrid.data("was_init_mode",true);
4071
4072
4073		if(g_showDebug == true){
4074
4075			trace("url ajax: " + urlAjax);
4076		}
4077
4078		var output = {};
4079		output["ajax_url"] = urlAjax;
4080		output["url_replace"] = urlReplace;
4081		output["terms"] = arrTerms;
4082		output["search"] = search;
4083		output["title_start"] = title_start;
4084		output["filters_string"] = urlFilterString;
4085		
4086		if(g_showDebug == true){
4087
4088			trace("output: ");
4089			trace(output);
4090
4091			trace("End getGridAjaxOptions function");
4092		}
4093
4094
4095
4096		return(output);
4097	}
4098
4099
4100	/**
4101	 * get all exclude post ids from all avoid duplicates grids
4102	 * if it's a single avoid duplicates grid - don't get excludes
4103	 */
4104	function getExcludePostIDs(objCurrentGrid){
4105		
4106		//check if it's only one grid involved
4107		if(!objCurrentGrid)
4108			var objGrids = jQuery(".uc-avoid-duplicates");
4109		else
4110			var objGrids = jQuery(".uc-avoid-duplicates").not(objCurrentGrid);
4111		
4112		if(objGrids.length == 0)
4113			return("");
4114		
4115		//check if rand of only grid, get id's, else not
4116		
4117		if(objGrids.length == 1 && !objCurrentGrid){
4118			var queryData = objGrids.attr("querydata");
4119			
4120			var objQueryData = JSON.parse(queryData);
4121			var orderby = getVal(objQueryData,"orderby");
4122			
4123			if(orderby != "rand")
4124				return("");
4125		}
4126		
4127		
4128		//get all the id's of all including the existing.
4129		
4130		var strIDs = "";
4131
4132		jQuery.each(objGrids, function(index, grid){
4133			var objGrid = jQuery(grid);
4134
4135			var postIDs = objGrid.data("postids");
4136
4137			if(!postIDs)
4138				return(true);
4139
4140			if(strIDs)
4141				strIDs += ",";
4142
4143			strIDs += postIDs;
4144		});
4145
4146
4147		return(strIDs);
4148	}
4149
4150	function ________INIT_AFTER_______________(){}
4151
4152	/**
4153	 * add filter to grid init after array
4154	 */
4155	function addFilterToInitAfter(objFilter, objGrid){
4156		
4157		var role = objFilter.data("role");
4158		
4159		var key = "filters_init_after";
4160
4161		if(role == "child")
4162			key = "filters_init_after_children";
4163
4164		objFilter.data("initafter",true);
4165
4166		var arrFiltersInitAfter = objGrid.data(key);
4167
4168		if(!arrFiltersInitAfter)
4169			arrFiltersInitAfter = [];
4170
4171		arrFiltersInitAfter.push(objFilter);
4172
4173		if(g_showDebug == true)
4174			trace("Add init after: "+key+" | "+objFilter.attr("id") );
4175		
4176		objGrid.data(key, arrFiltersInitAfter);
4177
4178	}
4179
4180	/**
4181	 * check filters init after
4182	 */
4183	function isSpecialFilterInitAfter(objFilter, objGrid){
4184		
4185		var type = getFilterType(objFilter);
4186				
4187		if(type != g_types.PAGINATION && type != g_types.LOADMORE)
4188			return(false);
4189
4190		var offsetPagination = objFilter.offset();
4191		var offsetGrid = objGrid.offset();
4192
4193		if(offsetPagination.top < offsetGrid.top){
4194
4195			if(g_showDebug == true)
4196				trace("Set "+type+" to ajax init");
4197
4198			return(true);
4199		}
4200
4201		return(false);
4202	}
4203
4204	/**
4205	 * check if there is a need to refresh child filters
4206	 * grid related, other filters are set in the settings
4207	 */
4208	function initGrid_setInitFiltersAfterLoad(objGrid){
4209		
4210		//get all grid filters
4211		var objFilters = objGrid.data("filters");
4212		
4213		if(!objFilters)
4214			return(false);
4215
4216		if(objFilters.length == 0)
4217			return(false);
4218				
4219		//check if there are filters with selected
4220		
4221		var arrSelectedFilters = getSelectedFilters(objFilters);
4222		
4223		if(arrSelectedFilters.length == 0)
4224			return(false);
4225
4226		//add to refresh all not selected filters
4227		
4228		jQuery.each(objFilters, function(index, filter){
4229						
4230			var objFilter = jQuery(filter);
4231			var type = getFilterType(objFilter);
4232			
4233			//skip not related to filter types
4234			switch(type){
4235				case g_types.PAGINATION:
4236				case g_types.LOADMORE:
4237					return(true);
4238				break;
4239			}
4240			
4241			var isSelected = objFilter.hasClass("uc-has-selected");
4242			
4243			if(isSelected == true)
4244				return(true);
4245			
4246			//skip by role. main don't add to init after
4247			var filterRole = objFilter.data("role");
4248			if(filterRole == "main")
4249				return(true);
4250			
4251			//add to grid and option to refresh
4252			
4253			var objGrid = objFilter.data("grid");
4254			
4255			addFilterToInitAfter(objFilter, objGrid);
4256			
4257		});
4258
4259	}
4260	
4261	
4262	function ________INIT_______________(){}
4263
4264
4265	/**
4266	 * init the globals
4267	 */
4268	function initGlobals(){
4269
4270		if(typeof g_strFiltersData === "undefined")
4271			return(false);
4272
4273		g_filtersData = JSON.parse(g_strFiltersData);
4274
4275		if(jQuery.isEmptyObject(g_filtersData)){
4276
4277			trace("filters error - filters data not found");
4278			return(false);
4279		}
4280		
4281		g_urlBase = getVal(g_filtersData, "urlbase");
4282		g_urlAjax = getVal(g_filtersData, "urlajax");
4283		
4284		var platform = getVal(g_filtersData, "platform");
4285		
4286		//switch to gutenberg
4287		
4288		if(platform == "gutenberg"){
4289			g_isGutenberg = true;
4290			g_vars.class_widget_wrapper = "ue-widget-root";
4291			g_vars.current_postid = getVal(g_filtersData, "postid");
4292		}
4293		
4294		//ucpage url
4295		var ucpage = getVal(g_filtersData,"ucpage");
4296		if(jQuery.isNumeric(ucpage))
4297			g_vars.ucpage_url = ucpage;
4298		
4299		//url keys
4300
4301		var objUrlKeys = getVal(g_filtersData, "urlkeys");
4302		
4303		var taxSap = getVal(objUrlKeys, "tax_sap");
4304		if(taxSap)
4305			g_options.urlkey_taxsap = taxSap;
4306		
4307		var isShowDebug = getVal(g_filtersData, "debug");
4308
4309		if(isShowDebug == true)
4310			g_showDebug = true;
4311
4312		if(g_showDebug == true)
4313			trace("Show Filters Debug");
4314
4315		if(!g_urlBase){
4316			trace("ue filters error - base url not inited");
4317			return(false);
4318		}
4319
4320		if(!g_urlAjax){
4321			trace("ue filters error - ajax url not inited");
4322			return(false);
4323		}
4324		
4325		//trace(g_options);
4326		
4327		return(true);
4328	}
4329
4330
4331	/**
4332	 * init filter and bing to grid
4333	 */
4334	function initFilter(objFilter, type){
4335
4336		var objGrid = getClosestGrid(objFilter);
4337
4338		var error = "Filter Parent not found! Please put the posts element on the page, and turn on 'Enable Post Filtering' option on it";
4339
4340		if(!objGrid){
4341			
4342			
4343			//pagination can work without parent as regular link
4344			
4345			var type = getFilterType(objFilter);
4346			if(type == g_types.PAGINATION)
4347				return(false);
4348			
4349			showElementError(objFilter, error);
4350			return(null);
4351		}
4352
4353		var isAjax = objGrid.data("ajax");
4354
4355		if(isAjax == false){
4356			showElementError(objFilter, error);
4357			return(false);
4358		}
4359
4360		//bind grid to filter
4361		objFilter.data("grid", objGrid);
4362		
4363		//bind filter to grid
4364		bindFilterToGrid(objGrid, objFilter);
4365		
4366		
4367		//set data var
4368		if(g_showDebug == true)
4369			objFilter.attr("data-showdebug", true);
4370		
4371		switch(type){
4372			case g_types.TERMS_LIST:
4373				initTermsRelatedFilter(objFilter);
4374			break;
4375			case g_types.SELECT:
4376				initSelectFilter(objFilter);
4377				initTermsRelatedFilter(objFilter);				
4378			break;
4379			case g_types.GENERAL:		//general filter events
4380				initGeneralFilter(objFilter);
4381			break;
4382		}
4383
4384
4385		objFilter.trigger(g_vars.EVENT_INIT_FILTER);
4386
4387	}
4388
4389
4390	/**
4391	 * init filter events by types
4392	 */
4393	function initFilterEventsByTypes(arrTypes, arrGeneralTypes, objFilters, objParent){
4394
4395		if(!arrTypes || arrTypes.length == 0)
4396			return(false);
4397
4398		if(g_showDebug == true){
4399			trace("Init filter events for parent");
4400			trace(arrTypes);
4401			trace(objParent);
4402		}
4403
4404		for(var type in arrTypes){
4405
4406			switch(type){
4407				case g_types.PAGINATION:
4408										
4409					objParent.on("click",".uc-filter-pagination a", onAjaxPaginationLinkClick);
4410					
4411				break;
4412				case g_types.LOADMORE:
4413
4414					//load more
4415					objParent.on("click",".uc-filter-load-more__link", onLoadMoreClick);
4416				break;
4417				case g_types.TERMS_LIST:
4418
4419					objParent.on("click",".ue_taxonomy.uc-grid-filter a.ue_taxonomy_item", onTermsLinkClick);
4420
4421				break;
4422				case g_types.SEARCH:
4423
4424					//do nothing for init
4425
4426				break;
4427				case g_types.SELECT:
4428
4429					objParent.on("change", ".uc-select-filter__select", onTermsLinkClick);
4430
4431				break;
4432				case g_types.SUMMARY:
4433					//do nothing for now
4434				break;
4435				case g_types.GENERAL:
4436					//the init is from the general types
4437				break;
4438				default:
4439					trace("init by type - unrecognized type: "+type);
4440				break;
4441			}
4442		}
4443
4444		if(!arrGeneralTypes || arrGeneralTypes.length == 0)
4445			return(false);
4446
4447
4448		//init the general types
4449
4450		for(var generalType in arrGeneralTypes){
4451
4452			var objFirstFilter = arrGeneralTypes[generalType];
4453
4454			objFirstFilter.trigger(g_vars.EVENT_INIT_FILTER_TYPE,[objParent]);
4455
4456		}
4457
4458	}
4459
4460
4461
4462
4463	/**
4464	 * init pagination filter
4465	 */
4466	function initFilters(objFilters){
4467		
4468		if(g_showDebug == true){
4469
4470			trace("init filters");
4471
4472			if(objFilters.length == 0)
4473				trace("no filters found");
4474			else
4475				trace(objFilters);
4476		}
4477
4478		var numFilters = objFilters.length;
4479
4480		if(numFilters == 0)
4481			return(false);
4482
4483		var arrTypes = {};
4484		var arrGeneralTypes = {};
4485
4486		var objParent = getFiltersParent(objFilters);
4487
4488		jQuery.each(objFilters, function(index, filter){
4489
4490			var objFilter = jQuery(filter);
4491			var type = getFilterType(objFilter);
4492
4493			//set single filter
4494			if(numFilters === 1){
4495				objFilter.attr("data-singlefilter",true);
4496			}
4497
4498			initFilter(objFilter, type);
4499
4500			//collect the general type
4501
4502			arrTypes[type] = true;
4503
4504			if(type == g_types.GENERAL){
4505				var generalType = objFilter.data("generaltype");
4506				
4507				if(!generalType){
4508					trace(objFilter);
4509					throw new Error("The filter is missing generaltype data");
4510				}
4511
4512				if(arrGeneralTypes.hasOwnProperty(generalType) == false)
4513					arrGeneralTypes[generalType] = objFilter;
4514
4515			}
4516
4517			objFilter.addClass(g_vars.CLASS_FILTER_INITED);
4518
4519		});
4520
4521		initFilterEventsByTypes(arrTypes, arrGeneralTypes, objFilters, objParent);
4522
4523	}
4524
4525
4526	/**
4527	 * set init state ajax url for each grid (for go back)
4528	 */
4529	function initGrid_setAjaxUrl(objGrid){
4530
4531		var behave = objGrid.data("filterbehave");
4532
4533		if(behave != "mixed_back")
4534			return(false);
4535
4536		//get all grid filters
4537		var objFilters = objGrid.data("filters");
4538
4539		if(!objFilters)
4540			return(false);
4541
4542		if(objFilters.length == 0)
4543			return(false);
4544
4545		var objAjaxOptions = getGridAjaxOptions(objFilters, objGrid,false,false,{getonly:true});
4546
4547		var ajaxUrlInit = getVal(objAjaxOptions, "ajax_url");
4548
4549		objGrid.data("initajaxurl", ajaxUrlInit);
4550
4551	}
4552
4553
4554	/**
4555	 * set active filters data - for third party connections, active filters and clear button
4556	 */
4557	function initGrid_setActiveFiltersData(objGrid, objAjaxOptions){
4558		
4559		if(!objAjaxOptions)
4560			var objAjaxOptions = getGridAjaxOptions_simple(objGrid);
4561		
4562		var arrTerms = getVal(objAjaxOptions, "terms");
4563	
4564		if(jQuery.isArray(arrTerms))
4565			arrTerms = arrTerms.flat();
4566
4567		// Create a new array for filtered items
4568		var filteredTerms = [];
4569		
4570		jQuery.each(arrTerms, function(index, term) {
4571			
4572			// Skip if the term is an object with slug "__or__", "__and__", or "__ucor__"
4573				if (term.slug === "__ucand__" || term.slug === "__ucor__") {
4574					return(true);
4575				}
4576				
4577				// Add the term to the filtered array
4578				filteredTerms.push(term);
4579		});
4580
4581		// Assign the filtered array back to arrTerms
4582		arrTerms = filteredTerms;
4583		
4584		var search = getVal(objAjaxOptions, "search");
4585
4586		if(search)
4587			search = search.trim();
4588
4589		if(search){
4590			var objSearch = {
4591				type:"search",
4592				"key": "search|"+search,
4593				"title": search
4594			};
4595
4596			if(!arrTerms)
4597				var arrTerms = [];
4598
4599			arrTerms.push(objSearch);
4600		}
4601		
4602		//title start
4603		var titleStart = getVal(objAjaxOptions, "title_start");
4604		
4605		if(titleStart){
4606			
4607			var objTitleStart = {
4608					type:"titlestart",
4609					"key": "titlestart|"+titleStart,
4610					"title": titleStart
4611				};
4612
4613			if(!arrTerms)
4614				var arrTerms = [];
4615
4616			arrTerms.push(objTitleStart);
4617		}
4618			
4619		
4620		objGrid.data("active_filters_items", arrTerms);
4621		objGrid.trigger(g_vars.EVENT_UPDATE_ACTIVE_FILTER_ITEMS, [arrTerms]);
4622		
4623	}
4624
4625
4626	/**
4627	 * init the grids, ininital filters refresh,
4628	 * set active filters, and update initial url's
4629	 */
4630	function initGrids(){
4631
4632		var objGrids = getAllGrids("loaded_only");
4633
4634		if(objGrids.length == 0)
4635			return(false);
4636
4637		if(g_showDebug == true){
4638			trace("init grids");
4639			trace(objGrids);
4640		}
4641
4642		jQuery.each(objGrids, function(index, grid){
4643
4644			var objGrid = jQuery(grid);
4645
4646			//--- set go back url if needed
4647
4648			initGrid_setAjaxUrl(objGrid);
4649
4650			initGrid_setInitFiltersAfterLoad(objGrid);
4651
4652			//--- set active filters (for clear and active filters links)
4653
4654			initGrid_setActiveFiltersData(objGrid);
4655			
4656						
4657			//--- refresh init filters
4658			
4659			var objInitFilters = objGrid.data("filters_init_after");
4660						
4661			var isMainFiltersRefreshed = false;
4662			if(objInitFilters && objInitFilters.length > 0){
4663
4664				isMainFiltersRefreshed = true;
4665
4666				if(g_showDebug == true){
4667					trace("ajax init Filters");
4668					trace(objInitFilters);
4669				}
4670
4671				refreshAjaxGrid(objGrid, "filters");
4672			}
4673
4674			//--- refresh init filters - children
4675
4676			var objInitFiltersChildren = objGrid.data("filters_init_after_children");
4677
4678			if(objInitFiltersChildren && objInitFiltersChildren.length > 0){
4679
4680				if(isMainFiltersRefreshed == false){
4681
4682					if(g_showDebug == true){
4683						trace("ajax init child Filters");
4684						trace(objInitFiltersChildren);
4685					}
4686					
4687					refreshAjaxGrid(objGrid, "filters_children");
4688					
4689				}
4690				else
4691					objGrid.data("init_refresh_child_filters", true);
4692			}
4693
4694			objGrid.addClass("ucfilters--grid-inited");
4695
4696		});
4697
4698
4699		return(objGrids);
4700	}
4701
4702	/**
4703	 * init grids events
4704	 */
4705	function initGridsEvents(objGrids){
4706
4707		//init grids events
4708
4709		if(!objGrids || objGrids.length == 0)
4710			return(false);
4711
4712
4713		//grid several action
4714
4715		objGrids.on(g_vars.ACTION_REFRESH_GRID,function(){
4716
4717			var objGrid = jQuery(this);
4718
4719			if(g_showDebug == true){
4720				trace("Refresh grid - by event:" + g_vars.ACTION_REFRESH_GRID);
4721				console.trace();
4722			}
4723			
4724			refreshAjaxGrid(objGrid);
4725		});
4726
4727
4728		objGrids.on(g_vars.ACTION_GET_FILTERS_URL,function(){
4729
4730			var objGrid = jQuery(this);
4731
4732			var urlFilters = getGridUrlFiltersString(objGrid);
4733
4734			return(urlFilters);
4735		});
4736
4737		//clear filters from event
4738
4739		objGrids.on(g_vars.ACTION_CLEAR_FILTERS, function(){
4740			
4741			var objGrid = jQuery(this);
4742
4743			var arrActiveFilterItems = getGridActiveFilterItems(objGrid);
4744
4745			//if already cleared - no need
4746			if(!arrActiveFilterItems)
4747				return(null);
4748			
4749			clearAllFilters(objGrid, null, true);
4750			
4751			objGrid.trigger(g_vars.ACTION_REFRESH_GRID);
4752
4753		});
4754
4755		//unselect filter from event
4756
4757		objGrids.on(g_vars.EVENT_UNSELECT_FILTER, function(event, key){
4758						
4759			var objGrid = jQuery(this);
4760			
4761			unselectFilterItem(objGrid, key);
4762			
4763			objGrid.trigger(g_vars.ACTION_REFRESH_GRID);
4764		});
4765
4766	}
4767
4768	/**
4769	 * init events
4770	 */
4771	function initGeneralEvents(){
4772
4773		addEventListener('popstate', onPopState);
4774
4775		g_objBody.on(g_vars.EVENT_DOM_UPDATED, runInitFilters);
4776
4777	}
4778
4779
4780	/**
4781	 * validate the grids
4782	 */
4783	function validateGrid(objGrid){
4784
4785		//check for |raw absence
4786
4787		var isAjax = objGrid.data("ajax");
4788
4789		if(isAjax === "'true'")
4790			showElementError(objGrid, "This grid configured wrong way, missing |raw in html attributes");
4791
4792	}
4793
4794
4795	/**
4796	 * add some validation to the grids
4797	 */
4798	function validateGrids(){
4799
4800		var objGrids = getAllGrids("loaded_only");
4801
4802		jQuery.each(objGrids, function(index, grid){
4803
4804			var objGrid = jQuery(grid);
4805
4806			validateGrid(objGrids);
4807		});
4808	}
4809
4810
4811	/**
4812	 * run init filters
4813	 */
4814	function runInitFilters(){
4815
4816		validateGrids();
4817
4818		//get the filters
4819		var objFilters = jQuery(".uc-grid-filter, .uc-filter-pagination").not("." + g_vars.CLASS_FILTER_INITED);
4820		
4821		//wait for load...
4822
4823		var objFiltersLoading = objFilters.filter(".uc-waitforload");
4824
4825		if(objFiltersLoading.length && g_initFiltersCounter < 2){
4826
4827			if(g_showDebug == true){
4828				trace(objFiltersLoading);
4829				trace("Wait for Load!");
4830			}
4831
4832			setTimeout(runInitFilters, 500);
4833
4834			g_initFiltersCounter++;
4835
4836			objFilters = null;
4837			objFiltersLoading = null;
4838
4839			return(false);
4840		}
4841
4842		//init for the next time
4843		g_initFiltersCounter = 0;
4844
4845		initFilters(objFilters);
4846
4847		//init all grids with several stuff like init filters, active modes and url's
4848		var objGrids = initGrids();
4849
4850		initGridsEvents(objGrids);
4851
4852	}
4853
4854
4855	/**
4856	 * init
4857	 */
4858	function init(){
4859
4860		g_objBody = jQuery("body");
4861
4862		var success = initGlobals();
4863					//run again on fail 3 times
4864		if(success == false){
4865
4866			if(typeof window.ueFiltersTimeoutCounter != "undefined")
4867					window.ueFiltersTimeoutCounter++;
4868			else
4869				window.ueFiltersTimeoutCounter = 0;
4870
4871			if(window.ueFiltersTimeoutCounter == 3){
4872				trace("Failed to init filters");
4873				return(false);
4874			}
4875
4876			setTimeout(init, 200);
4877
4878			return(false);
4879		}
4880
4881		//init remote object if exists
4882		if(typeof UERemoteConnection == "function")
4883			g_remote = window.ueRemoteConnection;
4884
4885		runInitFilters();
4886
4887		initGeneralEvents();
4888		
4889		
4890		//run init again on elementor popup
4891		
4892		jQuery( document ).on( 'elementor/popup/show', function(event, id, objPopup){
4893			
4894			g_objBody.trigger(g_vars.EVENT_DOM_UPDATED);
4895			
4896		});
4897		
4898		
4899	}
4900
4901
4902	/**
4903	 * is element in viewport
4904	 */
4905	this.isElementInViewport = function(objElement) {
4906
4907		  var elementTop = objElement.offset().top;
4908		  var elementBottom = elementTop + objElement.outerHeight();
4909
4910		  var viewportTop = jQuery(window).scrollTop();
4911		  var viewportBottom = viewportTop + jQuery(window).height();
4912
4913		  return (elementBottom > viewportTop && elementTop < viewportBottom);
4914	}
4915
4916	/**
4917	 * run function with trashold, default is 500
4918	 */
4919	this.runWithTrashold = function(func, trashold){
4920
4921		if(!trashold)
4922			 var trashold = 500;
4923
4924		if(g_vars.trashold_handle)
4925			clearTimeout(g_vars.trashold_handle);
4926
4927		g_vars.trashold_handle = setTimeout(func, trashold);
4928
4929	};
4930
4931	/**
4932	 * get filter element data
4933	 */
4934	this.getFilterElementData = function(objElement){
4935		
4936		var objData = getFilterElementData(objElement);
4937
4938		return(objData);
4939	}
4940
4941	/**
4942	 * get filter parent query data
4943	 */
4944	this.getFilterGridQueryData = function(objFilter){
4945
4946     	 var objGrid = objFilter.data("grid");
4947      	 if(!objGrid)
4948           	return(null);
4949
4950         var queryData = objGrid.attr("querydata");
4951      	  if(!queryData)
4952            return(null);
4953
4954      	 var objData = jQuery.parseJSON(queryData);
4955
4956      	 if(g_showDebug == true){
4957      		 console.log("getQueryData (filter, grid, querydata): ",objFilter, objGrid, queryData);
4958      	 }
4959
4960		return(objData);
4961	}
4962
4963	/**
4964	 * get key
4965	 */
4966	this.getFilterItemKey = function(objItem){
4967
4968		if(!objItem || objItem.length == 0)
4969			return(null);
4970
4971		var key = objItem.data("key");
4972
4973		if(key)
4974			return(key);
4975
4976		//fallback
4977
4978		key = "term|" + objItem.data("taxonomy") + "|" + objItem.data("slug");
4979
4980		return(key);
4981	}
4982
4983
4984	/**
4985	 * get value
4986	 */
4987	this.getVal = function(obj, name, defaultValue){
4988
4989		return getVal(obj, name, defaultValue);
4990	}
4991	
4992	/**
4993	 * get filters by type
4994	 * return jquery object
4995	 */
4996	this.getGridFiltersByType = function(objGrid, filterType){
4997		
4998		if(!filterType)
4999			throw new Error("getGridFiltersByType error - enter type as second param");
5000		
5001		var arrFilters = getGridFilters(objGrid);
5002		
5003		if(arrFilters.length == 0)
5004			return(jQuery());
5005		
5006		var objChosenFilters = jQuery();
5007		
5008		jQuery.each(arrFilters, function(index, objFilter){
5009			
5010			var type = getFilterType(objFilter, true);
5011						
5012			if(type == filterType){
5013				objChosenFilters = objChosenFilters.add(objFilter);
5014			}
5015			
5016		});
5017		
5018		return(objChosenFilters);
5019	}
5020
5021
5022	/**
5023	 * init the class
5024	 */
5025	function construct(){
5026
5027		if(!jQuery){
5028			trace("Filters not loaded, jQuery not loaded");
5029			return(false);
5030		}
5031		
5032		jQuery("document").ready(function(){
5033			setTimeout(init, 200);
5034		});
5035		
5036	}
5037
5038	construct();
5039
5040}
5041
5042g_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.