PageSourceSearch

https://www.trbo.com/wp-content/plugins/unlimited-elements-for-ele…/filters/ue_filters.js?ver=1.5.141

js trbo.com collected 2026-09-28 23:53:05 UTC 92,216 bytes, 4,462 lines download raw bytes

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