PageSourceSearch

https://www.jooz.nu/wp-content/plugins/wp-views/embedded/res/js/wpv-pagination-embedded_ver-2.5.2.js

js jooz.nu collected 2026-10-07 13:19:07 UTC 148,747 bytes, 4,073 lines download raw bytes

1var WPViews = WPViews || {};
2
3var wpv_stop_rollover = {};
4window.wpvPaginationAjaxLoaded = {};
5window.wpvPaginationAnimationFinished = {};
6window.wpvPaginationQueue = {};
7
8// ------------------------------------
9// Clone
10// ------------------------------------
11
12// Textarea and select clone() bug workaround | Spencer Tipping
13// Licensed under the terms of the MIT source code license
14// Motivation.
15// jQuery's clone() method works in most cases, but it fails to copy the value of textareas and select elements. This patch replaces jQuery's clone() method with a wrapper that fills in the
16// values after the fact.
17// An interesting error case submitted by Piotr Przybyl: If two <select> options had the same value, the clone() method would select the wrong one in the cloned box. The fix, suggested by Piotr
18// and implemented here, is to use the selectedIndex property on the <select> box itself rather than relying on jQuery's value-based val().
19;( function() {
20    jQuery.fn.wpv_clone = function() {
21        var result = jQuery.fn.clone.apply( this, arguments ),
22		my_textareas = this.find( 'textarea' ).add( this.filter( 'textarea' ) ),
23		result_textareas = result.find( 'textarea' ).add( result.filter( 'textarea' ) ),
24		my_selects = this.find( 'select' ).add( this.filter( 'select' ) ),
25		result_selects = result.find( 'select' ).add( result.filter( 'select' ) );
26		for ( var i = 0, l = my_textareas.length; i < l; ++i ) {
27			jQuery( result_textareas[i] ).val( jQuery( my_textareas[i] ).val() );
28		}
29		for ( var i = 0, l = my_selects.length; i < l; ++i ) {
30			for ( var j = 0, m = my_selects[i].options.length; j < m; ++j ) {
31				if ( my_selects[i].options[j].selected === true ) {
32					result_selects[i].options[j].selected = true;
33				} else {
34					result_selects[i].options[j].selected = false;
35				}
36			}
37		}
38        return result;
39    };
40})();
41
42WPViews.ViewFrontendUtils = function( $ ) {
43	
44	// ------------------------------------
45	// Constants and variables
46	// ------------------------------------
47	
48	var self = this;
49	
50	self.datepicker_style_id		= 'js-toolset-datepicker-style';
51	self.is_datepicker_style_loaded	= false;
52	
53	// ------------------------------------
54	// Methods
55	// ------------------------------------
56	
57	self.just_return = function() {
58		return;
59	};
60	
61	/**
62	* extract_url_query_parameters
63	*
64	* Extracts parameters from a query string, managing arrays, and returns an array of pairs key => value
65	*
66	* @param string query_string
67	*
68	* @return array
69	*
70	* @note ##URLARRAYVALHACK## is a hacky constant
71	*
72	* @uses decodeURIComponent
73	*
74	* @since 1.9
75	*/
76	
77	self.extract_url_query_parameters = function( query_string ) {
78		var query_string_pairs = {};
79		if ( query_string == "" ) {
80			return query_string_pairs;
81		}
82		var query_string_split = query_string.split( '&' ),
83		query_string_split_length = query_string_split.length;
84		for ( var i = 0; i < query_string_split_length; ++i ) {
85			var qs_part = query_string_split[i].split( '=' );
86			if ( qs_part.length != 2 ) {
87				continue;
88			};
89			var thiz_key = qs_part[0],
90			thiz_val = decodeURIComponent( qs_part[1].replace( /\+/g, " " ) );
91			// Adjust thiz_key to work with POSTed arrays
92			thiz_key = thiz_key.replace( /(\[)\d?(\])/, "" );
93			thiz_key = thiz_key.replace( "[]", "" );// Just in case
94			thiz_key = thiz_key.replace( /(%5B)\d?(%5D)/, "" );
95			thiz_key = thiz_key.replace( "%5B%5D", "" );// Just in case
96			thiz_key = thiz_key.replace( /(%255B)\d?(%255D)/, "" );
97			thiz_key = thiz_key.replace( "%255B%255D", "" );// Just in case
98			if ( query_string_pairs.hasOwnProperty( thiz_key ) ) {
99				if ( query_string_pairs[thiz_key] != thiz_val ) {
100					// @hack alert!! We can not avoid using this :-(
101					query_string_pairs[thiz_key] += '##URLARRAYVALHACK##' + thiz_val;
102				} else {
103					query_string_pairs[thiz_key] = thiz_val;
104				}
105			} else {
106				query_string_pairs[thiz_key] = thiz_val;
107			}
108		}
109		return query_string_pairs;
110	};
111	
112	/**
113	* get_extra_url_query_parameters
114	*
115	* Gets the current URL query parameters, but only those that do not belong to the current form already.
116	*
117	* @note Arrays are returned on a single key with values on a single str
117ing, separated by the ##URLARRAYVALHACK## placeholder. We might review that later
118	* @note Since 2.2, force include URL parameters that belong to form controls when the form does not use dependency nor AJAX results.
119	* 		As the form should be posted with page reload in this case, and we are not performing a dependency call, URL parameters win over optios in the form
120	* 		and have been not recorded yet in the AJAX method manager.
121	*
122	* @return array
123	*
124	* @uses self.extract_url_query_parameters
125	*
126	* @since 2.1
127	*/
128
129	self.get_extra_url_query_parameters_by_form = function( form ) {
130		var query_string = self.extract_url_query_parameters( window.location.search.substr( 1 ) ),
131		data = {},
132		force_from_form = ! ( form.hasClass( 'js-wpv-dps-enabled' ) 
133			|| form.hasClass( 'js-wpv-ajax-results-enabled' ) 
134			|| form.hasClass( 'js-wpv-ajax-results-submit-enabled' ) 
135		);
136		for ( var prop in query_string ) {
137			if ( 
138				query_string.hasOwnProperty( prop ) 
139				&& ! data.hasOwnProperty( prop )
140				&& (
141					force_from_form 
142					|| form.find( '[name="' + prop + '"], [name="' + prop + '\\[\\]"]' ).length === 0 
143				)
144			) {
145				data[ prop ] = query_string[ prop ];
146			}
147		}
148		return data;
149	};
150	
151	/**
152	* set_extra_url_query_parameters
153	*
154	* Forces the current URL query parameters in a form, but only those that do not belong to the form already.
155	*
156	* @uses self.extract_url_query_parameters
157	*
158	* @since 2.1
159	*/
160
161	self.set_extra_url_query_parameters_by_form = function( form ) {
162		var extra = self.get_extra_url_query_parameters_by_form( form );
163		$.each( extra, function( key, value ) {
164			if ( form.find( '[name="' + key + '"], [name="' + key + '\\[\\]"]' ).length === 0 ) {
165				// @hack alert!! WE can not avoid this :-(
166				var pieces = value.split( '##URLARRAYVALHACK##' ),
167				pieces_length = pieces.length;
168				if ( pieces_length < 2 ) {
169					$( '<input>' ).attr({
170						type: 'hidden',
171						name: key,
172						value: value
173					})
174					.appendTo( form );
175				} else {
176					for ( var iter = 0; iter < pieces_length; iter++ ) {
177						$( '<input>' ).attr({
178							type: 'hidden',
179							name: key + "[]",
180							value: pieces[iter]
181						})
182						.appendTo( form );
183					}
184				}
185			}
186		});
187	};
188	
189	/**
190	 * Dynamically load the Toolset datepicker style, only when needed.
191	 *
192	 * @note we should do the same with mediaelement and wp-mediaelement
193	 * @note the handle for this used to be wptoolset-field-datepicker
194	 *
195	 * @since 2.3.0
196	 */
197	
198	self.maybe_load_datepicker_style = function() {
199		
200		if ( ! self.is_datepicker_style_loaded ) {
201			
202			if ( document.getElementById( self.datepicker_style_id ) ) {
203				
204				self.is_datepicker_style_loaded = true;
205				
206			} else {
207				
208				var head	= document.getElementsByTagName( 'head' )[0],
209					link	= document.createElement( 'link' );
210				
211				link.id 	= self.datepicker_style_id;
212				link.rel	= 'stylesheet';
213				link.type	= 'text/css';
214				link.href	= wpv_pagination_local.datepicker_style_url;
215				link.media	= 'all';
216				head.appendChild( link );
217				
218				self.is_datepicker_style_loaded = true;
219				
220			}
221				
222		}
223		
224	};
225	
226	/**
227	 * Destroy all initialized datepickers in the page, before doing changes and initializing them again.
228	 *
229	 * @since 2.3.0
230	 */
231	
232	self.destroy_frontend_datepicker = function() {
233		
234		$( ".js-wpv-frontend-datepicker.js-wpv-frontend-datepicker-inited" )
235			.removeClass( 'js-wpv-frontend-datepicker-inited' )
236			.datepicker( "destroy" );
237			
238	};
239	
240	/**
241	* render_frontend_datepicker
242	*
243	* Adds a datepicker to a selector but only if it has not been added before.
244	*
245	* Fired on document.ready, after AJAX pagination and after AJAX parametric search events.
246	*
247	* @since 1.9
248	*/
249	
250	self.render_frontend_datepicker = function() {
251		$( '.js-wpv-frontend-datepicker:not(.js-wpv-frontend-datepicker-inited)' ).each( function() {
252			self.maybe_load_datepicker_style();
253			var thiz = $( this );
254			thiz
255				.addClass( 'js-wpv-frontend-datepicker-inited' )
256				.datepicker({
257					onSelect: function( dateText, inst ) {
258						var url_param = thiz.data( 'param' ),
259						data = 'date=' + dateText,
260						form = thiz.closest( 'form' );
261						data += '&date-format=' + $( '.js-wpv-date-param-' + url_param + '-format' ).val();
262						data += '&action=wpv_format_date';
263						$.post( wpv_pagination_local.front_ajaxurl, data, function( response ) {
264							response = $.parseJSON( response );
265							form.find('.js-wpv-date-param-' + url_param ).html( response['display'] );
266							form.find('.js-wpv-date-front-end-clear-' + url_param ).show();
267							form.find('.js-wpv-date-param-' + url_param + '-value' ).val( response['timestamp'] ).trigger( 'change' );
268						});
269					},
270					dateFormat: 'ddmmyy',
271					minDate: wpv_pagination_local.datepicker_min_date,
272					maxDate: wpv_pagination_local.datepicker_max_date,
273					showOn: "button",
274					buttonImage: wpv_pagination_local.calendar_image,
275					buttonText: wpv_pagination_local.calendar_text,
276					buttonImageOnly: true,
277					changeMonth: true,
278					changeYear: true
279				});
280		});
281	};
282	
283	/**
284	* clone_form
285	*
286	* Clones a form using the fixed clone() method that covers select and textarea elements
287	*
288	* @param object fil
289	* @param array targets
290	*
291	* @since 1.9
292	*/
293	
294	self.clone_form = function( fil, targets ) {
295		var cloned = fil.wpv_clone();
296		targets.each( function() {
297			$( this ).replaceWith( cloned );
298		});
299	};
300	
301	/**
302	* render_frontend_media_shortcodes
303	*
304	* Render the WordPress media players for items inside a container.
305	*
306	* @param object container
307	*
308	* @since 1.9
309	*/
310	
311	self.render_frontend_media_shortcodes = function( container ) {
312		container.find( '.wp-audio-shortcode, .wp-video-shortcode' ).each( function() {
313			var thiz = $( this );
314			thiz.mediaelementplayer();
315		});
316		container.find( '.wp-playlist' ).each( function() {
317			var thiz = $( this );
318			return new WPPlaylistView({ el: this });
319		});
320	};
321	
322	/**
323	* get_form_element_type
324	*
325	* Get a form element type, be it text, radio, checkbox, textarea or select
326	*
327	* @param selector	A jQuery selector object
328	*
329	* @return string	'text'|'radio'|'checkbox'|'textarea'|'select'|empty if selector is empty
330	*
331	* @since 2.2
332	*/
333	
334	self.get_form_element_type = function( selector ) {
335		if ( selector.length > 0 ) {
336			return selector[0].tagName == "INPUT" ? selector[0].type.toLowerCase() : selector[0].tagName.toLowerCase();
337		} else {
338			return '';
339		}
340	}
341	
342	self.get_hidden_item_width = function( item ) {
343		var item_clone = item
344			.clone()
345				.css({
346					'display': 'block',
347					'visibility': 'visible',
348					'position': 'absolute',
349					'z-index': '-99999',
350					'left': '99999999px',
351					'top': '0px',
352					'white-space': 'nowrap'
353				})
354				.appendTo( 'body' ),
355			width = item_clone.outerWidth();
356		item_clone.remove();
357		return width;
358	};
359	
360	// ------------------------------------
361	// Get updated results
362	// ------------------------------------
363	
364	/**
365	* get_updated_query_results
366	*
367	* Shared method for paginating Views and WordPress Archives, and also for parametric search on both.
368	* Returns a promise so you can operate on the response at will.
369	*
370	* Note that it applis the current form regardless it being submitted or not.
371	* @todo we might want to avoid adding that data when the form contains unsubmitted changes.
372	*
373	* @param view_number	The object hash
374	* @param page			The page that we want to get
375	* @param form			The form to track changes against
376	* @param expect			'form'|'full'|'both' Whether to return the full View, just the form, or both
377	*
378	* @since 2.1
379	*/
380	
381	self.get_updated_query_results = function( view_number, page, form, expect ) {
382		var data				= {},
383		sort					= {},
384		environment				= {},
385		search					= {},
386		extra					= {}.
387		attributes				= {},
388		lang					= ( typeof icl_lang == 'undefined' ) ? false : icl_lang,
389		parametric_data			= form.data( 'parametric' );
390		
391		sort = WPViews.view_sorting.get_sort_data( view_number, form );
392		
393		if ( parametric_data['environment'].current_post_id > 0 ) {
394			environment['wpv_aux_current_post_id'] = parametric_data['environment'].current_post_id;
395		}
396		if ( parametric_data['environment'].parent_post_id > 0 ) {
397			environment['wpv_aux_parent_post_id'] = parametric_data['environment'].parent_post_id;
398		}
399		if ( parametric_data['environment'].parent_term_id > 0 ) {
400			environment['wpv_aux_parent_term_id'] = parametric_data['environment'].parent_term_id;
401		}
402		if ( parametric_data['environment'].parent_user_id > 0 ) {
403			environment['wpv_aux_parent_user_id'] = parametric_data['environment'].parent_user_id;
404		}
405		
406		environment['archive'] = parametric_data['environment'].archive;
407		
408		if ( form.find( '.js-wpv-post-relationship-update' ).length ) {
409			search['dps_pr'] = form.find( '.js-wpv-post-relationship-update' ).serializeArray();
410		}
411		if ( 
412			form.hasClass( 'js-wpv-dps-enabled' ) 
413			|| form.hasClass( 'js-wpv-ajax-results-enabled' ) 
414			|| form.hasClass( 'js-wpv-ajax-results-submit-enabled' ) 
415		) {
416			search['dps_general'] = form.find( '.js-wpv-filter-trigger, .js-wpv-filter-trigger-delayed' ).serializeArray();
417		}
418		
419		attributes = parametric_data['attributes'];
420		
421		extra = self.get_extra_url_query_parameters_by_form( form );
422		
423		data = {
424			'view_number':	view_number,
425			page:			page,
426			sort:			sort,
427			attributes:		attributes,
428			environment:	environment,
429			search:			search,
430			extra:			extra,
431			expect:			expect
432		};
433		
434		if ( lang ) {
435			data['lang'] = lang;
436		}
437		
438		switch ( parametric_data.query ) {
439			case 'archive':
440				data['action']	= 'wpv_get_archive_query_results';
441				data['loop']	= parametric_data.loop;
442				break;
443			default:
444				data['action']	= 'wpv_get_view_query_results';
445				data['id']		= parametric_data.id;
446				if ( form.attr( 'data-targetid' ) ) {
447					data['target_id'] = form.data( 'targetid' );
448				} else if ( $( '.js-wpv-form-only.js-wpv-filter-form-' + view_number ).length > 0 ) {
449					data['target_id'] = $( '.js-wpv-form-only.js-wpv-filter-form-' + view_number ).data( 'targetid' );
450				}
451				data['wpv_view_widget_id']	= parametric_data['widget_id'];
452				break;
453		}
454		return $.ajax({
455			type:		"POST",
456			dataType:	"json",
457			url:		wpv_pagination_local.front_ajaxurl,
458			data:		data
459		});
460	};
461
462    /**
463     * Add, update or remove query string argument.
464     *
465     * @param 	key		{string} 	Argument name
466     * @param 	value	{string} 	Argument value. Not supplying a value will remove the parameter, supplying one will
467     *     							add/update the argument.
468     * @param 	url		{string} 	The URL. If no URL is supplied, it will be grabbed from window.location
469     * @return	string				The updated URL.
470	 * @link http://stackoverflow.com/a/11654596/3191395
471     *
472     * @since 2.3
473     */
474    self.updateUrlQuery = function(key, value, url) {
475        if(!url) {
476            url = window.location.href;
477        }
478        var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi");
479        var hash;
480        if (re.test(url)) {
481            if (typeof value !== 'undefined' && value !== null) {
482                return url.replace(re, '$1' + key + "=" + value + '$2$3');
483            } else {
484                hash = url.split('#');
485                url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
486                if(typeof hash[1] !== 'undefined' && hash[1] !== null) {
487                    url += '#' + hash[1];
488                }
489                return url;
490            }
491        } else {
492            if (typeof value !== 'undefined' && value !== null) {
493                var separator = url.indexOf('?') !== -1 ? '&' : '?';
494                hash = url.split('#');
495                url = hash[0] + separator + key + '=' + value;
496                if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
497                    url += '#' + hash[1];
498                }
499                return url;
500            } else {
501                return url;
502            }
503        }
504    };
505
506	// ------------------------------------
507	// Events
508	// ------------------------------------
509	
510	/**
511	* Window resize event
512	*
513	* Make Views layouts responsive
514	*
515	* @since 1.9
516	* @since 1.11 added debounce
517	*/
518	
519	$( window ).on( 'resize', _.debounce(
520		function() {
521			$( '.js-wpv-layout-responsive' ).each( function() {
522				$( this ).css( 'width', '' );
523			})
524			.promise()
525			.done( function() {
526				$( document ).trigger( 'js_event_wpv_layout_responsive_resize_completed' );
527			});
528		},
529		wpv_pagination_local.resize_debounce_tolerance
530	));
531	
532	// ------------------------------------
533	// Init
534	// ------------------------------------
535	
536	self.init = function() {
537		self.render_frontend_datepicker();
538	};
539	
540	self.init();
541
542};
543
544WPViews.ViewSorting = function( $ ) {
545	
546	var self = this;
547	
548	/**
549	 * Get the sort data for a given View.
550	 *
551	 * @note If the current orderby option does not have an orderby_as option and does not match the stored option, 
552	 * we remove (we empty) that value so it gets sorted as a native, string value.
553	 *
554	 * @since 2.3.0
555	 */
556	self.get_sort_data = function( view_number, form ) {
557		var sort			= {},
558		parametric_data		= form.data( 'parametric' );
559		
560		sort['wpv_sort_orderby']	= parametric_data['sort']['orderby'];
561		sort['wpv_sort_order']		= parametric_data['sort']['order'];
562		sort['wpv_sort_orderby_as']	= parametric_data['sort']['orderby_as'];
563		sort['wpv_sort_orderby_second']	= parametric_data['sort']['orderby_second'];
564		sort['wpv_sort_order_second']	= parametric_data['sort']['order_second'];
565		
566		if ( form.find( '.js-wpv-sort-control-orderby' ).length > 0 ) {
567			var orderby_type = WPViews.view_frontend_utils.get_form_element_type( form.find( '.js-wpv-sort-control-orderby' ) );
568			switch ( orderby_type ) {
569				case 'select':
570					sort['wpv_sort_orderby'] = form.find( '.js-wpv-sort-control-orderby' ).val();
571					if ( form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'orderbyas' ) ) {
572						sort['wpv_sort_orderby_as'] = form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'orderbyas' );
573					} else if ( sort['wpv_sort_orderby'] != parametric_data['sort']['orderby'] ) {
574						sort['wpv_sort_orderby_as'] = '';
575					}
576					break;
577				case 'radio':
578					sort['wpv_sort_orderby'] = form.find( '.js-wpv-sort-control-orderby:checked' ).val();
579					if ( form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'orderbyas' ) ) {
580						sort['wpv_sort_orderby_as'] = form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'orderbyas' );
581					} else if ( sort['wpv_sort_orderby'] != parametric_data['sort']['orderby'] ) {
582						sort['wpv_sort_orderby_as'] = '';
583					}
584					break;
585				case 'text':
586				case 'hidden':
587					sort['wpv_sort_orderby'] = form.find( '.js-wpv-sort-control-orderby' ).val();
588					if ( form.find( '.js-wpv-sort-control-orderby' ).data( 'orderbyas' ) ) {
589						sort['wpv_sort_orderby_as'] = form.find( '.js-wpv-sort-control-orderby' ).data( 'orderbyas' );
590					} else if ( sort['wpv_sort_orderby'] != parametric_data['sort']['orderby'] ) {
591						sort['wpv_sort_orderby_as'] = '';
592					}
593					break;
594			}
595		}
596		
597		if ( form.find( '.js-wpv-sort-control-order' ).length > 0 ) {
598			var order_type = WPViews.view_frontend_utils.get_form_element_type( form.find( '.js-wpv-sort-control-order' ) );
599			switch ( order_type ) {
600				case 'select':
601					sort['wpv_sort_order'] = form.find( '.js-wpv-sort-control-order' ).val();
602					break;
603				case 'radio':
604					sort['wpv_sort_order'] = form.find( '.js-wpv-sort-control-order:checked' ).val();
605					break;
606				case 'text':
607				case 'hidden':
608					sort['wpv_sort_order'] =  form.find( '.js-wpv-sort-control-order' ).val();
609					break;
610			}
611		}
612
613        if (
614        	'' === sort['wpv_sort_order']
615			&& form.find( '.js-wpv-sort-control-orderby' ).length > 0
616		) {
617            var order_type = WPViews.view_frontend_utils.get_form_element_type( form.find( '.js-wpv-sort-control-orderby' ) );
618            switch ( order_type ) {
619                case 'select':
620                    sort['wpv_sort_order'] = form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'forceorder' );
621                    break;
622                case 'radio':
623                    sort['wpv_sort_order'] = form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'forceorder' );
624                    break;
625                case 'text':
626                case 'hidden':
627                    sort['wpv_sort_order'] =  form.find( '.js-wpv-sort-control-orderby' ).data( 'forceorder' );
628                    break;
629            }
630        }
631		
632		return sort;
633	}
634	
635	/**
636	 * Sync the sorting controls used inside and outside of the View form.
637	 *
638	 * @since 2.3.0
639	 * @since 2.3.1 Split into set_sort_data_inside_form and set_sort_data_outside_form.
640	 */
641	self.set_sort_data = function( form, sort ) {
642		self.set_sort_data_inside_form( form, sort )
643			.set_sort_data_outside_form( form, sort );
644		return self;
645	};
646
647    /**
648     * Sync the sorting controls used inside and outside of the View form for the case of paginating while the View is
649	 * already sorted.
650     *
651     * @since 2.5.2
652     */
653	self.set_sort_data_for_pagination = function ( form ) {
654        var sort = {},
655        parametric_data	= form.data( 'parametric' );;
656
657        if ( form.find( '.js-wpv-sort-control-orderby' ).length > 0 ) {
658            var orderby_type = WPViews.view_frontend_utils.get_form_element_type( form.find( '.js-wpv-sort-control-orderby' ) );
659            switch ( orderby_type ) {
660                case 'select':
661                    sort['orderby'] = form.find( '.js-wpv-sort-control-orderby' ).val();
662                    if ( form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'orderbyas' ) ) {
663                        sort['orderby_as'] = form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'orderbyas' );
664                    } else if ( sort['orderby'] != parametric_data['sort']['orderby'] ) {
665                        sort['orderby_as'] = '';
666                    }
667
668                    if ( form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'forceorder' ) ) {
669                        sort['order'] = form.find( '.js-wpv-sort-control-orderby option:selected' ).data( 'forceorder' );
670                    }
671                    break;
672                case 'radio':
673                    sort['orderby'] = form.find( '.js-wpv-sort-control-orderby:checked' ).val();
674                    if ( form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'orderbyas' ) ) {
675                        sort['orderby_as'] = form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'orderbyas' );
676                    } else if ( sort['orderby'] != parametric_data['sort']['orderby'] ) {
677                        sort['orderby_as'] = '';
678                    }
679
680                    if ( form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'forceorder' ) ) {
681                        sort['order'] = form.find( '.js-wpv-sort-control-orderby:checked' ).data( 'forceorder' );
682                    }
683                    break;
684                case 'text':
685                case 'hidden':
686                    sort['orderby'] = form.find( '.js-wpv-sort-control-orderby' ).val();
687                    if ( form.find( '.js-wpv-sort-control-orderby' ).data( 'orderbyas' ) ) {
688                        sort['orderby_as'] = form.find( '.js-wpv-sort-control-orderby' ).data( 'orderbyas' );
689                    } else if ( sort['orderby'] != parametric_data['sort']['orderby'] ) {
690                        sort['orderby_as'] = '';
691                    }
692
693                    if ( form.find( '.js-wpv-sort-control-orderby' ).data( 'forceorder' ) ) {
694                        sort['order'] = form.find( '.js-wpv-sort-control-orderby' ).data( 'forceorder' );
695                    }
696                    break;
697            }
698        }
699        self.set_sort_data( form, sort );
700    };
701	
702	/**
703	 * Set the sort data for orderby controls as select dropdowns.
704	 *
705	 * @since 2.3.1
706	 */
707	self.set_sort_data_orderby_select = function( orderby_control, sort ) {
708		if ( orderby_control.find( 'option[value="' + sort['orderby'] + '"]' ).length == 0 ) {
709			orderby_control.append( $('<option>', {
710				value:	sort['orderby'],
711				text:	sort['orderby']
712			}));
713		}
714		orderby_control.val( sort['orderby'] );
715		if ( _.has( sort, 'orderby_as' ) ) {
716			orderby_control.find( 'option:selected' )
717				.data( 'orderbyas', sort['orderby_as'] )
718				.attr( 'data-orderbyas', sort['orderby_as'] );
719		}
720		return self;
721	};
722	
723	/**
724	 * Set the sort data for orderby controls as text or hidden input
724s.
725	 *
726	 * @since 2.3.1
727	 */
728	self.set_sort_data_orderby_text = function( orderby_control, sort ) {
729		orderby_control.val( sort['orderby'] );
730		if ( _.has( sort, 'orderby_as' ) ) {
731			orderby_control
732				.data( 'orderbyas', sort['orderby_as'] )
733				.attr( 'data-orderbyas', sort['orderby_as'] );
734		}
735		return self;
736	};
737	
738	/**
739	 * Set the sort data for orderby controls as radio inputs.
740	 *
741	 * @note Create a radio input if it does not exist one for the right orderby value.
742	 *
743	 * @since 2.3.1
744	 */
745	self.set_sort_data_orderby_radio = function( orderby_control, sort, form ) {
746		if ( orderby_control.filter( '[value="' + sort['orderby'] + '"]' ).length == 0 ) {
747			form.append( $('<input>', {
748				type:		'radio',
749				"class":	'js-wpv-sort-control-orderby',
750				name:		'wpv_sort_orderby',
751				value:		sort['orderby']
752			}));
753		}
754		form.find( '.js-wpv-sort-control-orderby[value="' +  sort['orderby'] + '"]' ).prop( 'checked', true );
755		if ( _.has( sort, 'orderby_as' ) ) {
756			form.find( '.js-wpv-sort-control-orderby:checked' )
757				.data( 'orderbyas', sort['orderby_as'] )
758				.attr( 'data-orderbyas', sort['orderby_as'] );
759		}
760		return self;
761	};
762	
763	/**
764	 * Set the sort data for orderby controls as radio inputs.
765	 *
766	 * @note Uncheck all radio inputs if it does not exist one for the right orderby value.
767	 *
768	 * @since 2.3.1
769	 */
770	self.maybe_set_sort_data_orderby_radio = function( orderby_control, sort ) {
771		if ( orderby_control.filter( '[value="' + sort['orderby'] + '"]' ).length == 0 ) {
772			orderby_control.prop( 'checked', false );
773		} else {
774			orderby_control.filter( '[value="' +  sort['orderby'] + '"]' ).prop( 'checked', true );
775			if ( _.has( sort, 'orderby_as' ) ) {
776				orderby_control.filter( ':checked' )
777					.data( 'orderbyas', sort['orderby_as'] )
778					.attr( 'data-orderbyas', sort['orderby_as'] );
779			}
780		}
781		return self;
782	};
783	
784	/**
785	 * Set the sort data for orderby controls as lists.
786	 *
787	 * @since 2.3.1
788	 */
789	self.set_sort_data_orderby_list = function( orderby_control, sort ) {
790		var orderby_control_to_set = orderby_control.find( '.js-wpv-sort-list-orderby[data-orderby="' + sort['orderby'] + '"]' );
791		if ( orderby_control_to_set.length == 0 ) {
792			
793		} else {
794			if ( ! orderby_control_to_set.closest( '.js-wpv-sort-list-item' ).hasClass( 'wpv-sort-list-current' ) ) {
795				orderby_control
796					.find( 'span.wpv-sort-list-current' )
797						.removeClass( 'wpv-sort-list-current' );
798				orderby_control
799					.find( '.js-wpv-sort-list-item' )
800						.css( {'display':'none'} );
801				orderby_control_to_set
802					.closest( '.js-wpv-sort-list-item' )
803						.addClass( 'wpv-sort-list-current' )
804						.css( {'display': 'block'} );
805				orderby_control
806					.find( '.js-wpv-sort-list' )
807						.prepend( orderby_control_to_set.closest( '.js-wpv-sort-list-item' ) );
808			}
809		}
810		return self;
811	};
812	
813	/**
814	 * Set the sort data for order controls as select dropdowns.
815	 *
816	 * @since 2.3.1
817	 */
818	self.set_sort_data_order_select = function( order_control, sort ) {
819		if ( order_control.find( 'option[value="' + sort['order'] + '"]' ).length == 0 ) {
820			order_control.append( $('<option>', {
821				value:	sort['order'],
822				text:	sort['order']
823			}));
824		}
825		order_control.val( sort['order'] );
826		if ( 
827			_.has( sort, 'orderby' ) 
828			&& typeof order_control.data('labels') !== 'undefined'
829		) {
830			// We are setting the order in a command that also sets the orderby, so we need to modify the order labels
831			var order_labels = order_control.data( 'labels' ),
832				order_labels_to_push = {},
833				orderby_to_check = sort.orderby.toLowerCase();
834			if ( _.has( order_labels, orderby_to_check ) ) {
835				order_labels_to_push = order_labels[ orderby_to_check ];
836			} else if ( _.has( order_labels, 'default' ) ) {
837				order_labels_to_push = order_labels[ 'default' ];
838			}
839			
840			if ( _.has( order_labels_to_push, 'asc' ) ) {
841				order_control.find( 'option[value="asc"]' ).html( order_labels_to_push.asc );
842			}
843			if ( _.has( order_labels_to_push, 'desc' ) ) {
844				order_control.find( 'option[value="desc"]' ).html( order_labels_to_push.desc );
845			}
846		}
847		return self;
848	};
849	
850	/**
851	 * Set the sort data for order controls as text or hidden input
851s.
852	 *
853	 * @since 2.3.1
854	 */
855	self.set_sort_data_order_text = function( order_control, sort ) {
856		order_control.val( sort['order'] );
857		return self;
858	};
859	
860	/**
861	 * Set the sort data for order controls as radio inputs.
862	 *
863	 * @note Create a radio input if it does not exist one for the right order value.
864	 *
865	 * @since 2.3.1
866	 */
867	self.set_sort_data_order_radio = function( order_control, sort, form ) {
868		if ( order_control.filter( '[value="' + sort['order'] + '"]' ).length == 0 ) {
869			form.append( $('<input>', {
870				type:		'radio',
871				"class":	'js-wpv-sort-control-order',
872				name:		'wpv_sort_order',
873				value:		sort['order']
874			}));
875		}
876		form.find( '.js-wpv-sort-control-order[value="' +  sort['order'] + '"]' ).prop( 'checked', true );
877		
878		if ( 
879			_.has( sort, 'orderby' ) 
880			&& typeof order_control.data('labels') !== 'undefined'
881		) {
882			// We are setting the order in a command that also sets the orderby, so we need to modify the order labels
883			var order_labels = order_control.data( 'labels' ),
884				order_labels_to_push = {},
885				orderby_to_check = sort.orderby.toLowerCase(),
886				label_to_update = null,
887				input_to_keep = null;
888			if ( _.has( order_labels, orderby_to_check ) ) {
889				order_labels_to_push = order_labels[ orderby_to_check ];
890			} else if ( _.has( order_labels, 'default' ) ) {
891				order_labels_to_push = order_labels[ 'default' ];
892			}
893			
894			if ( _.has( order_labels_to_push, 'asc' ) ) {
895				label_to_update = order_control.filter( '[value="asc"]' ).closest( 'label' );
896				input_to_keep = order_control.filter( '[value="asc"]' ).detach();
897				
898				label_to_update
899					.html( order_labels_to_push.asc )
900					.prepend( input_to_keep );
901			}
902			if ( _.has( order_labels_to_push, 'desc' ) ) {
903				label_to_update = order_control.filter( '[value="desc"]' ).closest( 'label' );
904				input_to_keep = order_control.filter( '[value="desc"]' ).detach();
905				
906				label_to_update
907					.html( order_labels_to_push.desc )
908					.prepend( input_to_keep );
909			}
910		}
911		return self;
912	};
913	
914	/**
915	 * Set the sort data for order controls as radio inputs.
916	 *
917	 * @note Uncheck all radio inputs if it does not exist one for the right order value.
918	 *
919	 * @since 2.3.1
920	 */
921	self.maybe_set_sort_data_order_radio = function( order_control, sort ) {
922		if ( order_control.filter( '[value="' + sort['order'] + '"]' ).length == 0 ) {
923			order_control.prop( 'checked', true );
924		} else {
925			order_control.filter( '[value="' +  sort['order'] + '"]' ).prop( 'checked', true );
926		}
927		return self;
928	};
929	
930	/**
931	 * Set the sort data for order controls as lists.
932	 *
933	 * @since 2.3.1
934	 */
935	self.set_sort_data_order_list = function( order_control, sort ) {
936		var order_control_to_set = order_control.find( '.js-wpv-sort-list-order[data-order="' + sort['order'] + '"]' );
937		if ( order_control_to_set.length == 0 ) {
938			
939		} else {
940			if ( ! order_control_to_set.closest( '.js-wpv-sort-list-item' ).hasClass( 'wpv-sort-list-current' ) ) {
941				order_control
942					.find( 'span.wpv-sort-list-current' )
943						.removeClass( 'wpv-sort-list-current' );
944				order_control
945					.find( '.js-wpv-sort-list-item' )
946						.css( {'display':'none'} );
947				order_control_to_set
948					.closest( '.js-wpv-sort-list-item' )
949						.addClass( 'wpv-sort-list-current' )
950						.css( {'display': 'block'} );
951				order_control
952					.find( '.js-wpv-sort-list' )
953						.prepend( order_control_to_set.closest( '.js-wpv-sort-list-item' ) );
954			}
955		}
956		if ( 
957			_.has( sort, 'orderby' ) 
958			&& typeof order_control.data('labels') !== 'undefined'
959		) {
960			// We are setting the order in a command that also sets the orderby, so we need to modify the order labels
961			var order_labels = order_control.data( 'labels' ),
962				order_labels_to_push = {},
963				orderby_to_check = sort.orderby.toLowerCase(),
964				width_update_needed = false;
965			if ( _.has( order_labels, orderby_to_check ) ) {
966				order_labels_to_push = order_labels[ orderby_to_check ];
967			} else if ( _.has( order_labels, 'default' ) ) {
968				order_labels_to_push = order_labels[ 'default' ];
969			}
970			
971			if ( _.has( order_labels_to_push, 'asc' ) ) {
972				order_control.find( '.js-wpv-sort-list-order[data-order="asc"] span' ).html( order_labels_to_push.asc );
973				width_update_needed = true;
974			}
975			if ( _.has( order_labels_to_push, 'desc' ) ) {
976				order_control.find( '.js-wpv-sort-list-order[data-order="desc"] span' ).html( order_labels_to_push.desc );
977				width_update_needed = true;
978			}
979			if ( width_update_needed ) {
980				self.adjust_sort_list_width( order_control );
981			}
982		}
983		return self;
984	};
985	
986	/**
987	 * Sync the sorting controls used inside of the View form.
988	 *
989	 * @since 2.3.1
990	 *
991	 * @note Setting "orderby_as" demands that "orderby" is also set.
992	 */
993	self.set_sort_data_inside_form = function( form, sort ) {
994		if ( _.has( sort, 'orderby' ) ) {
995			if ( form.find( '.js-wpv-sort-control-orderby' ).length > 0 ) {
996				var orderby_control = form.find( '.js-wpv-sort-control-orderby' ),
997					orderby_type = WPViews.view_frontend_utils.get_form_element_type( orderby_control );
998				switch ( orderby_type ) {
999					case 'select':
1000						self.set_sort_data_orderby_select( orderby_control, sort );
1001						break;
1002					case 'text':
1003					case 'hidden':
1004						self.set_sort_data_orderby_text( orderby_control, sort );
1005						break;
1006					case 'radio':
1007						self.set_sort_data_orderby_radio( orderby_control, sort, form );
1008						break;
1009				}
1010			} else {
1011				var orderby_attributes = {
1012					type:		'hidden',
1013					"class":	'js-wpv-sort-control-orderby',
1014					name:		'wpv_sort_orderby',
1015					value:		sort['orderby']
1016				};
1017				if ( _.has( sort, 'orderby_as' ) ) {
1018					orderby_attributes['data-orderbyas'] = sort['orderby_as'];
1019				}
1020                if ( _.has( sort, 'forceorder' ) ) {
1021                    orderby_attributes['data-forceorder'] = sort['forceorder'];
1022                }
1023                $( '<input>' )
1024					.attr( orderby_attributes )
1025					.appendTo( form );
1026			}
1027			// We set this as a hidden input for forms that submit with page refresh.
1028			if ( _.has( sort, 'orderby_as' ) ) {
1029				if ( form.find( '.js-wpv-sort-control-orderby-as' ).length > 0 ) {
1030					form.find( '.js-wpv-sort-control-orderby-as' ).remove();
1031				}
1032				$( '<input>' )
1033					.attr({
1034						type:		'hidden',
1035						"class":	'js-wpv-sort-control-orderby-as',
1036						name:		'wpv_sort_orderby_as',
1037						value:		sort['orderby_as']
1038					})
1039					.appendTo( form );
1040			}
1041			if ( form.find( '.js-wpv-sort-list-orderby-dropdown' ).length > 0 ) {
1042				var orderby_list_control = form.find( '.js-wpv-sort-list-orderby-dropdown' );
1043				self.set_sort_data_orderby_list( orderby_list_control, sort );
1044			}
1045		}
1046		if ( _.has( sort, 'order' ) ) {
1047			if ( form.find( '.js-wpv-sort-control-order' ).length > 0 ) {
1048				var order_control = form.find( '.js-wpv-sort-control-order' ),
1049					order_type = WPViews.view_frontend_utils.get_form_element_type( order_control );
1050				switch ( order_type ) {
1051					case 'select':
1052						self.set_sort_data_order_select( order_control, sort );
1053						break;
1054					case 'text':
1055					case 'hidden':
1056						self.set_sort_data_order_text( order_control, sort );
1057						break;
1058					case 'radio':
1059						self.set_sort_data_order_radio( order_control, sort, form );
1060						break;
1061				}
1062			} else {
1063				$( '<input>' )
1064					.attr({
1065						type:		'hidden',
1066						"class":	'js-wpv-sort-control-order',
1067						name:		'wpv_sort_order',
1068						value:		sort['order']
1069					})
1070					.appendTo( form );
1071			}
1072			if ( form.find( '.js-wpv-sort-list-order-dropdown' ).length > 0 ) {
1073				var order_list_control = form.find( '.js-wpv-sort-list-order-dropdown' );
1074				self.set_sort_data_order_list( order_list_control, sort );
1075			}
1076		}
1077		return self;
1078	}
1079	
1080	/**
1081	 * Sync the sorting controls used outside of the View form.
1082	 *
1083	 * @since 2.3.1
1084	 *
1085	 * @note Setting "orderby_as" demands that "orderby" is also set.
1086	 */
1087	self.set_sort_data_outside_form = function( form, sort ) {
1088		
1089		var view_number = form.data( 'viewnumber' );
1090		
1091		if ( _.has( sort, 'orderby' ) ) {
1092			var extra_orderby = $( '.js-wpv-sort-control-orderby[data-viewnumber="' + view_number + '"]:not(.js-wpv-filter-form .js-wpv-sort-control-orderby)' ),
1093				extra_orderby_list = $( '.js-wpv-sort-list-orderby-dropdown[data-viewnumber="' + view_number + '"]:not(.js-wpv-filter-form .js-wpv-sort-list-orderby-dropdown)' );
1094			if ( extra_orderby.length > 0 ) {
1095				var orderby_type = WPViews.view_frontend_utils.get_form_element_type( extra_orderby );
1096				switch ( orderby_type ) {
1097					case 'select':
1098						self.set_sort_data_orderby_select( extra_orderby, sort );
1099						break;
1100					case 'text':
1101					case 'hidden':
1102						self.set_sort_data_orderby_text( extra_orderby, sort );
1103						break;
1104					case 'radio':
1105						self.maybe_set_sort_data_orderby_radio( extra_orderby, sort );
1106						break;
1107				}
1108			}
1109			if ( extra_orderby_list.length > 0 ) {
1110				self.set_sort_data_orderby_list( extra_orderby_list, sort );
1111			}
1112		}
1113		
1114		if ( _.has( sort, 'order' ) ) {
1115			var extra_order = $( '.js-wpv-sort-control-order[data-viewnumber="' + view_number + '"]:not(.js-wpv-filter-form .js-wpv-sort-control-order)' ),
1116				extra_order_list = $( '.js-wpv-sort-list-order-dropdown[data-viewnumber="' + view_number + '"]:not(.js-wpv-filter-form .js-wpv-sort-list-order-dropdown)' );
1117			if ( extra_order.length > 0 ) {
1118				var order_type = WPViews.view_frontend_utils.get_form_element_type( extra_order );
1119				switch ( order_type ) {
1120					case 'select':
1121						self.set_sort_data_order_select( extra_order, sort );
1122						break;
1123					case 'text':
1124					case 'hidden':
1125						self.set_sort_data_order_text( extra_order, sort );
1126						break;
1127					case 'radio':
1128						self.maybe_set_sort_data_order_radio( extra_order, sort );
1129						break;
1130				}
1131			}
1132			if ( extra_order_list.length > 0 ) {
1133				self.set_sort_data_order_list( extra_order_list, sort );
1134			}
1135		}
1136		
1137		return self;
1138		
1139	};
1140	
1141	// ------------------------------------
1142	// Sorting links - not implemented yet
1143	// ------------------------------------
1144	
1145	$( document ).on( 'click', '.js-wpv-sort-trigger', function( e ) {
1146		e.preventDefault();
1147		var thiz		= $( this ),
1148		view_number		= thiz.data( 'viewnumber' ),
1149		form			= $( '.js-wpv-filter-form-' + view_number ),
1150		sort			= {
1151							'orderby':		( typeof thiz.data( 'orderby' ) != 'undefined' ) ? thiz.data( 'orderby' ) : '',
1152							'order':		( typeof thiz.data( 'order' ) != 'undefined' ) ? thiz.data( 'order' ) : '',
1153							'orderby_as':	( typeof thiz.data( 'orderbyas' ) != 'undefined' ) ? thiz.data( 'orderbyas' ) : '',
1154		},
1155		form_each;
1156		form.each( function() {
1157			form_each = $( this );
1158			self.set_sort_data( form_each, sort );
1159			WPViews.view_frontend_utils.set_extra_url_query_parameters_by_form( form_each );
1160		});
1161		if ( 
1162			thiz.hasClass( 'js-wpv-column-header-click' ) 
1163			|| (
1164				! form.hasClass( 'js-wpv-ajax-results-enabled' ) 
1165				&& ! form.hasClass( 'js-wpv-ajax-results-submit-enabled' )
1166			)
1167		) {
1168			// Backwards compatibility: table sorting does reload the page for sorting
1169			// Also, submit the form for a page reload when the form is not set to load results using AJAX
1170			form.submit();
1171		} else {
1172			// Elsewhere, trigger a parametric search change, and make sure AJAX is used where due
1173			var data_for_events = {
1174				view_unique_id:			view_number,
1175				form:					form,
1176				force_results_update:	form.hasClass( 'js-wpv-ajax-results-submit-enabled' )
1177			};
1178			
1179			data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1180			
1181			$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1182		}
1183	});
1184	
1185	// ------------------------------------
1186	// Sorting controls
1187	// ------------------------------------
1188	
1189	$( document ).on( 'change', 'select.js-wpv-sort-control-orderby', function() {
1190		
1191		var thiz		= $( this ),
1192		thiz_selected	= thiz.find( ':selected' ),
1193		sort			= {},
1194		view_number		= thiz.data( 'viewnumber' ),
1195		form			= $( '.js-wpv-filter-form-' + view_number ),
1196		data_for_events = {
1197			view_unique_id:	view_number,
1198			form:			form
1199		};
1200		
1201		sort[ 'orderby' ] = thiz.val();
1202		if ( thiz_selected.data( 'orderbyas' ) !== undefined ) {
1203			sort[ 'orderby_as' ] = thiz_selected.data( 'orderbyas' );
1204		}
1205		if ( 
1206			thiz_selected.data( 'forceorder' ) !== undefined 
1207			&& thiz_selected.data( 'forceorder' ) !== ''
1208		) {
1209			sort[ 'order' ] = thiz_selected.data( 'forceorder' );
1210		}
1211		
1212		self.set_sort_data( form, sort );
1213		
1214		wpv_stop_rollover[ view_number ] = true;
1215		
1216		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1217		
1218		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1219		
1220	});
1221	
1222	$( document ).on( 'change', 'input.js-wpv-sort-control-orderby', function() {
1223		
1224		var thiz		= $( this ),
1225		sort			= {},
1226		view_number		= thiz.data( 'viewnumber' ),
1227		sort_control	= $( '.js-wpv-sort-control-orderby[data-viewnumber="' + view_number + '"]:checked' ),
1228		form			= $( '.js-wpv-filter-form-' + view_number ),
1229		data_for_events = {
1230			view_unique_id:	view_number,
1231			form:			form
1232		};
1233		
1234		sort[ 'orderby' ] = sort_control.val();
1235		if ( sort_control.data( 'orderbyas' ) !== undefined ) {
1236			sort[ 'orderby_as' ] = sort_control.data( 'orderbyas' );
1237		}
1238		if ( 
1239			sort_control.data( 'forceorder' ) !== undefined 
1240			&& sort_control.data( 'forceorder' ) !== '' 
1241		) {
1242			sort[ 'order' ] = sort_control.data( 'forceorder' );
1243		}
1244		
1245		self.set_sort_data( form, sort );
1246		
1247		wpv_stop_rollover[ view_number ] = true;
1248		
1249		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1250		
1251		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1252		
1253	});
1254	
1255	$( document ).on( 'click', '.js-wpv-sort-list-orderby', function( e ) {
1256		e.preventDefault();
1257		var orderby_link = $( this ),
1258			orderby = orderby_link.data( 'orderby' ),
1259			orderby_as = orderby_link.data( 'orderbyas' ),
1260			orderby_order = orderby_link.data( 'forceorder' ),
1261			orderby_list = orderby_link.closest( '.wpv-sort-list' ),
1262			orderby_list_item = orderby_link.closest( 'span.js-wpv-sort-list-item' ),
1263			view_number = orderby_link.data( 'viewnumber' ),
1264			form = $( '.js-wpv-filter-form-' + view_number ),
1265			sort = {
1266				'orderby':		orderby,
1267				'orderby_as':	orderby_as
1268			},
1269			data_for_events = {
1270				view_unique_id:	view_number,
1271				form:			form
1272			};
1273		
1274		
1275		if ( orderby_list_item.hasClass( 'wpv-sort-list-current' ) ) {
1276			return;
1277		}
1278		
1279		orderby_list
1280			.find( 'span.wpv-sort-list-current' )
1281				.removeClass( 'wpv-sort-list-current' );
1282		orderby_list
1283			.find( '.js-wpv-sort-list-item' )
1284				.css( {'display':'none'} );
1285		orderby_list_item
1286			.addClass( 'wpv-sort-list-current' )
1287			.css( {'display': 'block'} );
1288		orderby_list.prepend( orderby_list_item );
1289		
1290		if ( orderby_order !== '' ) {
1291			sort[ 'order' ] = orderby_order;
1292		}
1293		
1294		self.set_sort_data( form, sort );
1295		
1296		wpv_stop_rollover[ view_number ] = true;
1297		
1298		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1299		
1300		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1301		
1302	});
1303	
1304	$( document ).on( 'change', 'select.js-wpv-sort-control-order', function() {
1305		
1306		var thiz		= $( this ),
1307		sort			= {},
1308		view_number		= thiz.data( 'viewnumber' ),
1309		form			= $( '.js-wpv-filter-form-' + view_number ),
1310		data_for_events = {
1311			view_unique_id:	view_number,
1312			form:			form
1313		};
1314		
1315		sort[ 'order' ] = thiz.val();
1316		
1317		self.set_sort_data( form, sort );
1318		
1319		wpv_stop_rollover[ view_number ] = true;
1320		
1321		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1322		
1323		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1324		
1325	});
1326	
1327	$( document ).on( 'change', 'input.js-wpv-sort-control-order', function() {
1328		
1329		var thiz		= $( this ),
1330		sort			= {},
1331		view_number		= thiz.data( 'viewnumber' ),
1332		sort_control	= $( '.js-wpv-sort-control-order[data-viewnumber="' + view_number + '"]:checked' ),
1333		form			= $( '.js-wpv-filter-form-' + view_number ),
1334		data_for_events = {
1335			view_unique_id:	view_number,
1336			form:			form
1337		};
1338		
1339		sort[ 'order' ] = sort_control.val();
1340		
1341		self.set_sort_data( form, sort );
1342		
1343		wpv_stop_rollover[ view_number ] = true;
1344		
1345		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1346		
1347		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1348		
1349	});
1350	
1351	$( document ).on( 'click', '.js-wpv-sort-list-order', function( e ) {
1352		e.preventDefault();
1353		var order_link = $( this ),
1354			order = order_link.data( 'order' ),
1355			order_list = order_link.closest( '.wpv-sort-list' ),
1356			order_list_item = order_link.closest( 'span.js-wpv-sort-list-item' ),
1357			view_number = order_link.data( 'viewnumber' ),
1358			form = $( '.js-wpv-filter-form-' + view_number ),
1359			sort = {
1360				'order': order
1361			},
1362			data_for_events = {
1363				view_unique_id:	view_number,
1364				form:			form
1365			};
1366		
1367		
1368		if ( order_list_item.hasClass( 'wpv-sort-list-current' ) ) {
1369			return;
1370		}
1371		
1372		order_list
1373			.find( 'span.wpv-sort-list-current' )
1374				.removeClass( 'wpv-sort-list-current' );
1375		order_list
1376			.find( '.js-wpv-sort-list-item' )
1377				.css( {'display':'none'} );
1378		order_list_item
1379			.addClass( 'wpv-sort-list-current' )
1380			.css( {'display': 'block'} );
1381		order_list.prepend( order_list_item );
1382		
1383		self.set_sort_data( form, sort );
1384		
1385		wpv_stop_rollover[ view_number ] = true;
1386		
1387		data_for_events = WPViews.view_parametric_search.extend_wpv_parametric_search_triggered_data( data_for_events );
1388		
1389		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
1390		
1391	});
1392	
1393	$( document ).on( 'mouseenter', '.js-wpv-sort-list-dropdown', function() {
1394		var orderby_list = $( this );
1395		orderby_list
1396			.find( '.js-wpv-sort-list-item' )
1397				.css( {'display': 'block'} );
1398	});
1399	
1400	$( document ).on( 'mouseleave', '.js-wpv-sort-list-dropdown', function() {
1401		var orderby_list = $( this );
1402		orderby_list
1403			.find( '.js-wpv-sort-list-item:not(.wpv-sort-list-current)' )
1404				.css( {'display': 'none'} );
1405	});
1406	
1407	// @todo calculate inital width and height of the container and also maybe re-calculate height on selection
1408	
1409	self.init_sort_list_width = function( selector ) {
1410		/*
1411		selector
1412			.find( '.js-wpv-sort-list-dropdown' )
1413				.each( function() {
1414					var sort_list = $( this ),
1415						sort_list_width = 0,
1416						sort_list_items = sort_list.find( '.js-wpv-sort-list-item' ),
1417						sort_list_anchors = sort_list.find( '.wpv-sort-list-anchor' );
1418						sort_list_anchors.each( function() {
1419							var item_width = WPViews.view_frontend_utils.get_hidden_item_width( $( this ) );
1420							if ( item_width > sort_list_width ) {
1421								sort_list_width = item_width;
1422							}
1423						});
1424						sort_list.css( { 'width': sort_list_width + 'em' } );
1425						sort_list_items.css( { 'width': sort_list_width + 'em' } );
1426				});
1427		*/
1428	};
1429	
1430	/**
1431	 * Adjust the sort list width to span at least its length in "em" units.
1432	 *
1433	 * @note When the length is less than 10 units, add an extra one for the toggle icon.
1434	 *
1435	 * @since 2.3.1
1436	 */
1437	self.adjust_sort_list_width = function( selector ) {
1438		var sort_list = selector,
1439			sort_list_width = 0,
1440			sort_list_items = sort_list.find( '.js-wpv-sort-list-item' ),
1441			sort_list_anchors = sort_list.find( '.wpv-sort-list-anchor span' );
1442		
1443		sort_list_anchors.each( function() {
1444			var item_width = $( this ).text().length;
1445			if ( item_width > sort_list_width ) {
1446				sort_list_width = item_width;
1447			}
1448		});
1449		sort_list_width = ( sort_list_width < 10 ) ? sort_list_width + 1 : sort_list_width;
1450		sort_list.css( { 'width': sort_list_width + 'em' } );
1451		sort_list_items.css( { 'width': sort_list_width + 'em' } );
1452	};
1453	
1454	/**
1455	 * Initialize sorting data for special cass:
1456	 * - When the sorting controls are of type 'list'.
1457	 * - When the sorting controls are of type 'dropdown' or 'radio', but are located outside of their related form.
1458	 * In those cases, there are no real sorting control elements inside the form, so we need to manually add them.
1459	 *
1460	 * @param selector The DOM object where this should be run, helps to narrow down on AJAX related operations.
1461	 *
1462	 * @since 2.3.0
1463	 *
1464	 * @todo Check whether we need to initialize the order coming from "forceorder" attributes in orderby controlos.
1465	 */
1466	self.maybe_init_sort_data = function( selector ) {
1467		
1468		// Init sort data for sort list controls, as they do not add proper form input elements
1469		selector.find( '.js-wpv-sort-list-dropdown' ).each( function() {
1470			var sorting_list = $( this ),
1471				sorting_list_type = sorting_list.hasClass( 'wpv-sort-list-orderby-dropdown' ) ? 'orderby' : 'order';
1472			
1473			switch ( sorting_list_type ) {
1474				case 'orderby':
1475					var sorting_current = sorting_list.find( '.wpv-sort-list-current .js-wpv-sort-list-orderby' ),
1476						sorting_viewnumber = sorting_current.data( 'viewnumber' ),
1477						sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1478						sorting_data = {
1479							orderby: sorting_current.data( 'orderby' ),
1480                            orderby_as: sorting_current.data( 'orderbyas' ),
1481                            forceorder: sorting_current.data( 'forceorder' )
1482                        };
1483						
1484						self.set_sort_data( sorting_form, sorting_data );
1485					break;
1486				case 'order':
1487					var sorting_current = sorting_list.find( '.wpv-sort-list-current .js-wpv-sort-list-order' ),
1488						sorting_viewnumber = sorting_current.data( 'viewnumber' ),
1489						sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1490						sorting_data = {
1491							order: sorting_current.data( 'order' ),
1492						};
1493						
1494						self.set_sort_data( sorting_form, sorting_data );
1495					break;
1496			}
1497		});
1498		
1499		// Init sort data for dropdowns or radios that are rendered outside their proper form
1500		selector.find( 'select.js-wpv-sort-control-orderby' ).each( function() {
1501			var sorting_control = $( this );
1502			if ( sorting_control.closest( '.js-wpv-filter-form' ).length == 0 ) {
1503				var sorting_viewnumber = sorting_control.data( 'viewnumber' ),
1504					sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1505					sorting_data = {
1506						orderby: sorting_control.val()
1507					};
1508				
1509				if ( sorting_control.find( ':selected' ).data( 'orderbyas' ) !== undefined ) {
1510					sorting_data[ 'orderby_as' ] = sorting_control.find( ':selected' ).data( 'orderbyas' );
1511				}
1512				
1513				self.set_sort_data( sorting_form, sorting_data );
1514			}
1515		});
1516		selector.find( 'select.js-wpv-sort-control-order' ).each( function() {
1517			var sorting_control = $( this );
1518			if ( sorting_control.closest( '.js-wpv-filter-form' ).length == 0 ) {
1519				var sorting_viewnumber = sorting_control.data( 'viewnumber' ),
1520					sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1521					sorting_data = {
1522						order: sorting_control.val()
1523					};
1524				
1525				self.set_sort_data( sorting_form, sorting_data );
1526			}
1527		});
1528		selector.find( 'input.js-wpv-sort-control-orderby:checked' ).each( function() {
1529			var sorting_control = $( this );
1530			if ( sorting_control.closest( '.js-wpv-filter-form' ).length == 0 ) {
1531				var sorting_viewnumber = sorting_control.data( 'viewnumber' ),
1532					sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1533					sorting_data = {
1534						orderby: sorting_control.val()
1535					};
1536				
1537				if ( sorting_control.data( 'orderbyas' ) !== undefined ) {
1538					sorting_data[ 'orderby_as' ] = sorting_control.data( 'orderbyas' );
1539				}
1540				
1541				self.set_sort_data( sorting_form, sorting_data );
1542			}
1543		});
1544		selector.find( 'input.js-wpv-sort-control-order:checked' ).each( function() {
1545			var sorting_control = $( this );
1546			if ( sorting_control.closest( '.js-wpv-filter-form' ).length == 0 ) {
1547				var sorting_viewnumber = sorting_control.data( 'viewnumber' ),
1548					sorting_form = $( '.js-wpv-filter-form-' + sorting_viewnumber ),
1549					sorting_data = {
1550						order: sorting_control.val()
1551					};
1552				
1553				self.set_sort_data( sorting_form, sorting_data );
1554			}
1555		});
1556		
1557	};
1558	
1559	$( document ).on( 'js_event_wpv_pagination_completed', function( event, data ) {
1560		//self.init_sort_list_width( data.layout );
1561		self.maybe_init_sort_data( data.layout );
1562		if ( data.filter ) {
1563            self.maybe_init_sort_data( data.filter );
1564		}
1565	});
1566	
1567	$( document ).on( 'js_event_wpv_parametric_search_form_updated', function( event, data ) {
1568		//self.init_sort_list_width( data.view_changed_form );
1569		self.maybe_init_sort_data( data.view_changed_form );
1570	});
1571	
1572	$( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
1573		//self.init_sort_list_width( data.layout );
1574		self.maybe_init_sort_data( data.layout );
1575	});
1576	
1577	// ------------------------------------
1578	// Init
1579	// ------------------------------------
1580	
1581	self.init = function() {
1582		//self.init_sort_list_width( $( 'body' ) );
1583		self.maybe_init_sort_data( $( 'body' ) );
1584	};
1585	
1586	self.init();
1587	
1588};
1589
1590WPViews.ViewPagination = function( $ ) {
1591	
1592	// ------------------------------------
1593	// Constants and variables
1594	// ------------------------------------
1595	
1596	var self = this;
1597	
1598	self.rollover_running = [];
1599	self.rollover_stopped = [];
1600    self.rollover_paused = [];
1601	
1602	self.init_rollover_timing_fired = false;
1603	
1604	self.pagination_queue = {};
1605	
1606	self.pagination_effects				= {};
1607	self.pagination_effects_conditions	= {};
1608	self.pagination_effects_spinner		= {};
1609	self.paged_views					= {};
1610	self.paged_views_initial_page		= {};
1611	
1612	self.last_paginated_view				= [];
1613	self.paginated_history_reach			= 0;
1614	self.add_paginated_history				= true;
1615	self.pagination_effect_state_push		= [ 'fade', 'slidev', 'slideh' ];
1616	self.pagination_effect_state_replace	= [];
1617	self.pagination_effect_state_keep		= [ 'infinite' ];
1618	
1619	self.init_scrolling_event_fired = false;
1620		
1621	self.slide_data_defaults = { 
1622		view_number:		'',
1623		page:				0,
1624		max_pages:			0,
1625		speed:				500,
1626		next:				true,
1627		effect:				'fade',
1628		response:			null,
1629		wpvPaginatorFilter: null,
1630		wpvPaginatorLayout: null,
1631		responseFilter:		null,
1632		responseView:		null,
1633		callback_next_func:	WPViews.view_frontend_utils.just_return
1634	};
1635	
1636	self.pagination_doing_ajax = [];
1637	
1638	// ------------------------------------
1639	// Methods
1640	// ------------------------------------
1641	
1642	/**
1643	* add_view_parameters
1644	*
1645	* Add several information to the data used to get pagination pages.
1646	* For example, add column sorting data, parametric search data and parent View data.
1647	*
1648	* @since 1.9
1649	* @since 2.1	Deprecated
1650	*/
1651	
1652	self.add_view_parameters = function( data, page, view_number ) {
1653		var this_form			= $( 'form.js-wpv-filter-form-' + view_number ),
1654		this_prelements			= this_form.find( '.js-wpv-post-relationship-update' ),
1655		this_form_environment	= this_form.data( 'environment' );
1656		
1657		data['action']				= 'wpv_get_page';
1658		data['page']				= page;
1659		data['view_number']			= view_number;
1660		data['wpv_sort_orderby']	= ( typeof this_form.data( 'orderby' ) != 'undefined' ) ? this_form.data( 'orderby' ) : '';
1661		data['wpv_sort_order']		= ( typeof this_form.data( 'order' ) != 'undefined' ) ? this_form.data( 'order' ) : '';
1662		data['wpv_sort_orderby_as']	= ( typeof this_form.data( 'orderbyas' ) != 'undefined' ) ? this_form.data( 'orderbyas' ) : '';
1663		data['wpv_sort_orderby_second']	= ( typeof this_form.data( 'orderbysecond' ) != 'undefined' ) ? this_form.data( 'orderbysecond' ) : '';
1664		data['wpv_sort_order_second']	= ( typeof this_form.data( 'ordersecond' ) != 'undefined' ) ? this_form.data( 'ordersecond' ) : '';
1665		data['wpv_view_widget_id']	= this_form.data( 'viewwidgetid' );
1666		data['view_hash']			= this_form.data( 'viewhash' );
1667		data['dps_pr']				= {};
1668		data['dps_general']			= {};
1669		
1670		if ( this_form_environment.current_post_id > 0 ) {
1671			data['wpv_aux_current_post_id'] = this_form_environment.current_post_id;
1672		}
1673		if ( this_form_environment.parent_post_id > 0 ) {
1674			data['wpv_aux_parent_post_id'] = this_form_environment.parent_post_id;
1675		}
1676		if ( this_form_environment.parent_term_id > 0 ) {
1677			data['wpv_aux_parent_term_id'] = this_form_environment.parent_term_id;
1678		}
1679		if ( this_form_environment.parent_user_id > 0 ) {
1680			data['wpv_aux_parent_user_id'] = this_form_environment.parent_user_id;
1681		}
1682		
1683		if ( this_prelements.length ) {
1684			data['dps_pr'] = this_prelements.serializeArray();
1685		}
1686		if ( this_form.hasClass( 'js-wpv-dps-enabled' ) || this_form.hasClass( 'js-wpv-ajax-results-enabled' ) ) {
1687			data['dps_general'] = this_form.find( '.js-wpv-filter-trigger, .js-wpv-filter-trigger-delayed' ).serializeArray();
1688		}
1689		
1690		return data;
1691	};
1692	
1693	/**
1694	* pagination_preload_pages
1695	*
1696	* Preload pages to a reach.
1697	*
1698	* @param object preload_data
1699	*
1700	* @since 1.9
1701	*/
1702	
1703	self.pagination_preload_pages = function( preload_data ) {
1704		var page = parseInt( preload_data.page, 10 ),
1705		max_pages = parseInt( preload_data.max_pages, 10 ),
1706		max_reach = parseInt( preload_data.max_reach, 10 );
1707		
1708		if ( max_reach > max_pages ) {
1709			max_reach = max_pages;
1710		}
1711		
1712		if ( preload_data.preload_pages == 'enabled' ) {
1713			var reach = 1;
1714			while ( reach < max_reach ) {
1715				self.pagination_preload_next_page( preload_data.view_number, page, max_pages, reach );
1716				self.pagination_preload_previous_page( preload_data.view_number, page, max_pages, reach );
1717				reach++;
1718			}
1719		}
1720		if ( preload_data.cache_pages == 'enabled' ) {
1721			self.pagination_cache_current_page( preload_data.view_number, page );
1722		}
1723	};
1724	
1725	/**
1726	* pagination_cache_current_page
1727	*
1728	* Cache current page.
1729	*
1730	* @param string	view_number
1731	* @param int	page
1732	*
1733	* @since 1.9
1734	*/
1735	
1736	self.pagination_cache_current_page = function( view_number, page ) {
1737		window.wpvCachedPages[ view_number ] = window.wpvCachedPages[ view_number ] || [];
1738		var current_page_permalink,
1739		content;
1740		icl_lang = ( typeof icl_lang == 'undefined' ) ? false : icl_lang;
1741		if ( ! window.wpvCachedPages[view_number].hasOwnProperty( page ) ) {
1742			WPViews.view_frontend_utils.get_updated_query_results( view_number, page, $( 'form.js-wpv-filter-form-' + view_number ), 'full' )
1743				.done( function( response ) {
1744					if ( response.success ) {
1745						window.wpvCachedPages[view_number][page] = response.data.full;
1746						content = $( response.data.full ).find( 'img' );
1747						content.each( function() {
1748							window.wpvCachedImages.push( this.src );
1749						});
1750					}
1751				});
1752		}
1753	};
1754	
1755	/**
1756	* pagination_preload_next_page
1757	*
1758	* Load the next page, or the next one counting "reach" pages.
1759	*
1760	* @param string	view_number
1761	* @param int	page
1762	* @param int	max_pages
1763	* @param int	reach
1764	*
1765	* @since 1.9
1766	*/
1767	
1768	self.pagination_preload_next_page = function( view_number, page, max_pages, reach ) {
1769		window.wpvCachedPages[ view_number ] = window.wpvCachedPages[ view_number ] || [];
1770		var next_page = page + reach,
1771		content,
1772		current_page_permalink;
1773		icl_lang = ( typeof icl_lang == 'undefined' ) ? false : icl_lang;
1774		if ( ! window.wpvCachedPages[view_number].hasOwnProperty( next_page ) ) {
1775			if ( ( next_page - 1 ) < max_pages ) {
1776				WPViews.view_frontend_utils.get_updated_query_results( view_number, next_page, $( 'form.js-wpv-filter-form-' + view_number ), 'full' )
1777					.done( function( response ) {
1778						if ( response.success ) {
1779							window.wpvCachedPages[view_number][next_page] = response.data.full;
1780							content = $( response.data.full ).find( 'img' );
1781							content.each( function() {
1782								window.wpvCachedImages.push( this.src );
1783							});
1784						}
1785					});
1786			}
1787		}
1788	};
1789	
1790	/**
1791	* pagination_preload_previous_page
1792	*
1793	* Load the previous page, or the previous one counting "reach" pages.
1794	*
1795	* @param string	view_number
1796	* @param int	page
1797	* @param int	max_pages
1798	* @param int	reach
1799	*
1800	* @since 1.9
1801	*/
1802	
1803	self.pagination_preload_previous_page = function(view_number, page, max_pages, reach) {
1804		window.wpvCachedPages[ view_number ] = window.wpvCachedPages[ view_number ] || [];
1805		var previous_page = page - reach,
1806		current_page_permalink,
1807		content;
1808		icl_lang = ( typeof icl_lang == 'undefined' ) ? false : icl_lang;
1809		if ( ! window.wpvCachedPages[view_number].hasOwnProperty( previous_page ) ) {
1810			// LOAD PREVIOUS
1811			if ( ( previous_page + 1 ) > 1 ) {
1812				WPViews.view_frontend_utils.get_updated_query_results( view_number, previous_page, $( 'form.js-wpv-filter-form-' + view_number ), 'full' )
1813					.done( function( response ) {
1814						if ( response.success ) {
1815							window.wpvCachedPages[view_number][previous_page] = response.data.full;
1816							content = $( response.data.full ).find( 'img' );
1817							content.each( function() {
1818								window.wpvCachedImages.push( this.src );
1819							});
1820						}
1821					});
1822			} else if ( (previous_page + 1 ) === 1 ) { // LOAD LAST PAGE IF ON FIRST PAGE
1823				WPViews.view_frontend_utils.get_updated_query_results( view_number, max_pages, $( 'form.js-wpv-filter-form-' + view_number ), 'full' )
1824					.done( function( response ) {
1825						if ( response.success ) {
1826							window.wpvCachedPages[view_number][max_pages] = response.data.full;
1827							window.wpvCachedPages[view_number][0] = response.data.full;
1828							content = $( response.data.full ).find( 'img' );
1829							content.each( function() {
1830								window.wpvCachedImages.push( this.src );
1831							});
1832						}
1833					});
1834			}
1835		}
1836	};
1837	
1838	/**
1839	* trigger_pagination
1840	*
1841	* Manage the View pagination after a control has been inited
1842	*
1843	* @param string	view_number
1844	* @param int	page
1845	*
1846	* @since 1.9
1847	*/
1848	
1849	self.trigger_pagination = function( view_number, page ) {
1850		if ( ! window.wpvPaginationAnimationFinished.hasOwnProperty( view_number ) ) {
1851			window.wpvPaginationAnimationFinished[ view_number ] = false;
1852		} else if ( window.wpvPaginationAnimationFinished[ view_number ] !== true ) {
1853			if ( ! window.wpvPaginationQueue.hasOwnProperty( view_number ) ) {
1854				window.wpvPaginationQueue[view_number] = [];
1855			}
1856			window.wpvPaginationQueue[ view_number ].push( arguments );
1857			return;
1858		}
1859		
1860		window.wpvPaginationAnimationFinished[ view_number ] = false;
1861		
1862		var data = {},
1863		wpvPaginatorLayout = $( '#wpv-view-layout-' + view_number ),
1864		wpvPaginatorFilter = $( 'form[name="wpv-filter-' + view_number + '"]' ),
1865		speed = 500,
1866		next = true,
1867		paged_view_data = self.get_paged_view( view_number ),
1868		max_reach = parseInt( paged_view_data.preload_reach ) + 1,
1869		callback_next_func = WPViews.view_frontend_utils.just_return,
1870		data_for_get_page,
1871		img;
1872		
1873		// Not using AJAX pagination
1874		// For WPAs we just need to adjust the form target and we are done :-)
1875		if ( 
1876			paged_view_data.type == 'disabled' 
1877			|| paged_view_data.type == 'paged' 
1878		) {
1879
1880			switch ( paged_view_data.query ) {
1881				case 'archive':
1882					current_page_permalink = paged_view_data[ 'base_permalink' ].replace( 'WPV_PAGE_NUM', page );
1883					window.location.replace( current_page_permalink );
1884					break;
1885				default:
1886					WPViews.view_frontend_utils.set_extra_url_query_parameters_by_form( wpvPaginatorFilter );
1887					// Adjust the wpv_paged hidden input to the page that we want to show
1888					if ( $( 'input[name="wpv_paged"]' ).length > 0 ) {
1889						$( 'input[name="wpv_paged"]' ).attr( 'value', page );
1890					} else {
1891						$( '<input>')
1892							.attr({
1893								type: 'hidden',
1894								name: 'wpv_paged',
1895								value: page
1896							})
1897							.appendTo( wpvPaginatorFilter );
1898					}
1899					wpvPaginatorFilter[0].submit();
1900					break;
1901			}
1902			return;
1903		}
1904		
1905		// Using AJAX pagination
1906		
1907		if ( paged_view_data.effect in self.pagination_effects_conditions ) {
1908			if ( ! self.pagination_effects_conditions[ paged_view_data.effect ]( paged_view_data, page ) ) {
1909				window.wpvPaginationAnimationFinished[ view_number ] = true;
1910				return;
1911			}
1912		}
1913		
1914		window.wpvPaginationAjaxLoaded[view_number] = false;
1915		window.wpvCachedPages[ view_number ] = window.wpvCachedPages[view_number] || [];
1916		
1917		if ( this.historyP.hasOwnProperty( view_number ) ) {
1918			next = ( this.historyP[ view_number ] < page ) ? true : false;
1919		}
1920		
1921		if ( paged_view_data.callback_next !== '' ) {
1922			callback_next_func = window[ paged_view_data.callback_next ];
1923			if ( typeof callback_next_func !== "function" ) {
1924				callback_next_func = WPViews.view_frontend_utils.just_return;
1925			}
1926		}
1927		
1928		data_for_get_page = { 
1929			view_number:		view_number,
1930			page:				page,
1931			max_pages:			parseInt( paged_view_data.max_pages, 10 ),
1932			speed:				parseFloat( paged_view_data.duration ),
1933			next:				next,
1934			effect:				paged_view_data.effect,
1935			wpvPaginatorFilter: wpvPaginatorFilter,
1936			wpvPaginatorLayout: wpvPaginatorLayout,
1937			responseView:		null,
1938			callback_next_func:	callback_next_func
1939		};
1940		
1941		if ( 
1942			window.wpvCachedPages[ view_number ].hasOwnProperty( page ) 
1943		) {
1944			data_for_get_page.response = window.wpvCachedPages[ view_number ][ page ];
1945			self.prepare_slide( data_for_get_page );
1946		} else {
1947			// Set loading class
1948			if ( paged_view_data.spinner !== 'disabled' ) {
1949				if ( paged_view_data.effect in self.pagination_effects_spinner ) {
1950					self.pagination_effects_spinner[ paged_view_data.effect ]( view_number, wpvPaginatorLayout );
1951				} else {
1952					self.pagination_effects_spinner[ 'fade' ]( view_number, wpvPaginatorLayout );
1953				}
1954			}
1955			WPViews.view_frontend_utils.get_updated_query_results( view_number, page, $( 'form.js-wpv-filter-form-' + view_number ), 'full' )
1956				.done( function( response ) {
1957					if ( response.success ) {
1958						data_for_get_page.response = response.data.full;
1959						self.prepare_slide( data_for_get_page );
1960					}
1961				});
1962		}
1963		self.pagination_preload_pages({
1964			view_number:	view_number, 
1965			cache_pages:	paged_view_data.cache_pages, 
1966			preload_pages:	paged_view_data.preload_pages, 
1967			page:			page, 
1968			max_reach:		max_reach, 
1969			max_pages:		paged_view_data.max_pages 
1970		});
1971		this.historyP[ view_number ] = page;
1972		return;
1973	};
1974	
1975	/**
1976	* prepare_slide
1977	*
1978	* Wrap the old layout into a div.wpv_slide_remove and change its ID to ~-response
1979	* Preload images on the new page if needed
1980	* Fire self.pagination_slide
1981	*
1982	* @param object data
1983	*
1984	* @since 1.9
1985	*/
1986	
1987	self.prepare_slide = function( data ) {
1988		var slide_data = $.extend( {}, self.slide_data_defaults, data ),
1989		width = slide_data.wpvPaginatorLayout.width(),
1990		outer_width = slide_data.wpvPaginatorLayout.outerWidth(),
1991		height = slide_data.wpvPaginatorLayout.height(),
1992		outer_height = slide_data.wpvPaginatorLayout.outerHeight(),
1993		responseObj = $( '<div></div>' ).append( slide_data.response ),
1994		preloadedImages,
1995		images;
1996		
1997		slide_data.responseView = responseObj.find( '.js-wpv-view-layout-' + slide_data.view_number );
1998        slide_data.responseFilterSelector = responseObj.find( 'form.js-wpv-filter-form-' + slide_data.view_number );
1999		slide_data.responseFilter = responseObj.find( 'form.js-wpv-filter-form-' + slide_data.view_number ).html();
2000		slide_data.pagination_page_permalink = slide_data.responseView.data( 'permalink' );
2001		
2002		// Wrap old layout in a div.wpv_slide_remove nd change its ID to ~-response
2003		slide_data.wpvPaginatorLayout
2004			.attr( 'id', 'wpv-view-layout-' + slide_data.view_number + '-response' )
2005			.wrap( '<div class="wpv_slide_remove" style="width:' + outer_width + 'px;height:' + outer_height + 'px;overflow:hidden;" />' )
2006			.css( 'width', width );
2007		// Add an ID attribute to the upcoming new layout, and hide it
2008		slide_data.responseView
2009			.attr( 'id', 'wpv-view-layout-' + slide_data.view_number )
2010			.css( {
2011				'visibility': 'hidden',
2012				'width': width
2013			} );
2014		
2015		// Preload images if needed
2016		if ( slide_data.wpvPaginatorLayout.hasClass( 'js-wpv-layout-preload-images' ) ) {
2017			preloadedImages = [];
2018			images = slide_data.responseView.find( 'img' );
2019			if ( images.length < 1 ) {
2020				self.pagination_slide( slide_data );
2021			} else {
2022				images.one( 'load', function() {
2023					preloadedImages.push( $( this ).attr( 'src' ) );
2024					if ( preloadedImages.length === images.length ) {
2025						self.pagination_slide( slide_data );
2026					}
2027				}).each( function() {
2028					$( this ).load();
2029				});
2030			}
2031			// Fix inner nested Views with AJAX pagination: the inner View, when preloading images, was rendered with visibility:hidden by default
2032			slide_data.responseView
2033				.find( '.js-wpv-layout-preload-images' )
2034					.css( 'visibility', 'visible' );
2035		} else {
2036			self.pagination_slide( slide_data );
2037		}
2038	};
2039	
2040	/**
2041	* pagination_slide
2042	*
2043	* Routes to the right pagination effect callback
2044	*
2045	* @param object data
2046	*
2047	* @since 1.9
2048	*/
2049	
2050	self.pagination_slide = function( data ) {
2051		var slide_data = $.extend( {}, self.slide_data_defaults, data );
2052		
2053		switch ( slide_data.effect ) {
2054			case 'slideleft':
2055				slide_data.next = true;
2056				slide_data.effect = 'slideh';
2057				break;
2058			case 'slideright':
2059			case 'sliderightforward':
2060				slide_data.next = false;
2061				slide_data.effect = 'slideh';
2062				break;
2063			case 'slidedown':
2064			case 'slidedownforward':
2065				slide_data.next = false;
2066				slide_data.effect = 'slidev';
2067				break;
2068			case 'slideup':
2069				slide_data.next = true;
2070				slide_data.effect = 'slidev';
2071				break;
2072		}
2073		
2074		if ( ! slide_data.effect in self.pagination_effects ) {
2075			slide_data.effect = 'fade';
2076		}
2077		
2078		self.pagination_effects[ slide_data.effect ]( slide_data );
2079	};
2080	
2081	/**
2082	* pagination_queue_trigger
2083	*
2084	* Manage multiple and fast pagination requests.
2085	*
2086	* @param int		view_number
2087	* @param boolean	next
2088	* @param object		wpvPaginatorFilter
2089	*
2090	* @todo why do we pass next and wpvPaginatorFilter here?
2091	*
2092	* @since 1.9
2093	*/
2094	
2095	self.pagination_queue_trigger = function( view_number, next, wpvPaginatorFilter ) {
2096		var args,
2097		page,
2098		max_pages;
2099		if ( window.wpvPaginationQueue.hasOwnProperty( view_number ) && window.wpvPaginationQueue[view_number].length > 0 ) {
2100		// when double clicking,we have set window.wpvPaginationQueue[view_number][1] and maybe we could tweak it to change the page number. Maybe checkin historyP
2101			window.wpvPaginationQueue[view_number].sort();
2102			args = window.wpvPaginationQueue[view_number][0];
2103			window.wpvPaginationQueue[view_number].splice(0, 1);
2104			page = args[1];
2105			max_pages = args[4];
2106			if ( page > max_pages ) {
2107				page = 1;
2108			} else if ( page < 1 ) {
2109				page = max_pages;
2110			}
2111			self.trigger_pagination( view_number, page );
2112		}
2113	};
2114	
2115	// ------------------------------------
2116	// Events for Views pagination
2117	// ------------------------------------
2118	
2119	/**
2120	* Manage pagination triggered from prev/next or first/last links
2121	*
2122	* @since 1.9
2123	* @since 2.4.1 Added support for first/last pagination links
2124	*/
2125	
2126	$( document ).on( 'click', '.js-wpv-pagination-next-link, .js-wpv-pagination-previous-link, .js-wpv-pagination-first-link, .js-wpv-pagination-last-link', function( e ) {
2127		e.preventDefault();
2128		var thiz = $( this ),
2129		view_number = thiz.data( 'viewnumber' ),
2130        page = thiz.data( 'page' ),
2131        form = $( '.js-wpv-filter-form-' + view_number );
2132
2133        WPViews.view_sorting.set_sort_data_for_pagination( form );
2134
2135        wpv_stop_rollover[ view_number ] = true;
2136		self.trigger_pagination( view_number, page );
2137	});
2138	
2139	/**
2140	* Manage pagination triggered by a change in the page selector dropdown
2141	*
2142	* @since 1.9
2143	*/
2144	
2145	$( document ).on( 'change', '.js-wpv-page-selector', function( e ) {
2146		e.preventDefault();
2147		var thiz = $( this ),
2148		view_number = thiz.data( 'viewnumber' ),
2149		page = thiz.val();
2150		wpv_stop_rollover[ view_number ] = true
2151		self.trigger_pagination( view_number, page );
2152	});
2153	
2154	/**
2155	* Manage pagination triggered by a click on a pagination link.
2156	*
2157	* @since 1.9
2158	*
2159	* @note Safari on iOS might need to also listen to the touchstart event. Investigate this!
2160	*/
2161	
2162	$( document ).on( 'click', '.js-wpv-pagination-link', function( e ) {
2163		e.preventDefault();
2164		var thiz = $( this ),
2165		data_collected = {};
2166		data_collected.view_number = thiz.data( 'viewnumber');
2167		data_collected.page = thiz.data( 'page' );
2168		var i;
2169		// TODO this can be improved: we should not need a loop here at all
2170		// @todo review this, data_collected.max_pages is UNDEFINED
2171		for ( i = 1; i <= data_collected.max_pages; i++ ) {
2172			if ( i === data_collected.page ) {
2173				$( '.js-wpv-page-link-' + data_collected.view_number + '-' + i ).addClass( 'wpv_page_current' );
2174			} else {
2175				$( '.js-wpv-page-link-' + data_collected.view_number + '-' + i ).removeClass( 'wpv_page_current' );
2176			}
2177			
2178		}
2179		wpv_stop_rollover[ data_collected.view_number ] = true
2180		self.trigger_pagination( data_collected.view_number, data_collected.page );
2181	});
2182	
2183	/*
2184	$( document ).on( 'click', '.js-wpv-pagination-pause-rollover', function( e ) {
2185		e.preventDefault();
2186		var view_num = $( this ).data( 'viewnumber' );
2187		wpv_stop_rollover[view_num] = true;
2188	});
2189	
2190	$( document ).on( 'click', '.js-wpv-pagination-resume-rollover', function( e ) {
2191		e.preventDefault();
2192		var view_num = $( this ).data( 'viewnumber' );
2193		delete wpv_stop_rollover[view_num];
2194	});
2195	*/
2196	
2197	// ------------------------------------
2198	// Events for WordPress Archives pagination
2199	// ------------------------------------
2200	
2201	/**
2202	* Manage pagination triggered from prev/next and first/last links, and numeric links, including their own prev/next ones
2203	*
2204	* @since 2.1
2205	* @since 2.4.1 Added support for first/last links.
2206	*/
2207	
2208	$( document ).on( 'click', '.js-wpv-archive-pagination-link, .js-wpv-archive-pagination-next-link, .js-wpv-archive-pagination-prev-link, .js-wpv-archive-pagination-links-next-link, .js-wpv-archive-pagination-links-prev-link, .js-wpv-archive-pagination-links-first-link, .js-wpv-archive-pagination-links-last-link', function( e ) {
2209		e.preventDefault();
2210		var thiz = $( this ),
2211		view_number = thiz.data( 'viewnumber' ),
2212		page = thiz.data( 'page' );
2213		wpv_stop_rollover[ view_number ] = true;
2214		self.trigger_pagination( view_number, page );
2215	});
2216	
2217	// ------------------------------------
2218	// Custom events
2219	// ------------------------------------
2220	
2221	/**
2222	* js_event_wpv_pagination_completed
2223	*
2224	* Event fired after a pagination transition has been completed
2225	*
2226	* @param data
2227	* 	- view_unique_id
2228	* 	- effect
2229	* 	- speed
2230	* 	- layout
2231	*
2232	* @since 1.9
2233	*/
2234	
2235	$( document ).on( 'js_event_wpv_pagination_completed', function( event, data ) {
2236		WPViews.view_frontend_utils.render_frontend_media_shortcodes( data.layout );
2237		WPViews.view_frontend_utils.render_frontend_datepicker();
2238		// Init pagination for any inner View that might be included inside the new page
2239		self.init_paged_views( data.layout );
2240		self.init_preload_images( data.layout );
2241		self.init_preload_pages( data.layout );
2242        self.init_pagination_button_state();
2243	});
2244	
2245	$( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
2246		// Init the pagination settings for this View results being updated
2247		self.init_paged_view( data.view_unique_id );
2248		// Init pagination for any inner View that might be included inside the new page
2249		self.init_paged_views( data.layout );
2250		self.init_preload_images( data.layout );
2251		self.init_preload_pages( data.layout );
2252	});
2253	
2254	// ------------------------------------
2255	// Init
2256	// ------------------------------------
2257	
2258	/**
2259	* init_effects
2260	*
2261	* Define the default pagination effects, can be extended by third parties.
2262	* Each callback gets the following parameters:
2263	* @param object slide_data
2264	*
2265	* @since 1.11
2266	*/
2267	
2268	self.init_effects = function() {
2269		self.pagination_effects = {
2270			infinite: function( slide_data ) {
2271				
2272				if ( slide_data.page != ( self.get_paged_view( slide_data.view_number ).page + 1 ) ) {
2273					// This should never happen! See self.pagination_effects_conditions
2274					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function() {
2275						$( this ).remove();
2276					});
2277					slide_data.wpvPaginatorLayout
2278						.animate( { opacity: 1 }, 300 )
2279						.unwrap()// If it got here, it has a -response suffix in the ID and is wrapped in an auxiliar div
2280						.attr( 'id', 'wpv-view-layout-' + slide_data.view_number  );
2281					window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2282					window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2283					
2284				} else {
2285				
2286					// content.match(/<!-- HOOK OPEN -->(W?)\<!-- HOOK CLOSE -->/);
2287					var data_for_events = {},
2288					data_for_history = {};
2289					
2290					data_for_events.view_unique_id	= slide_data.view_number;
2291					data_for_events.effect			= 'infinite';
2292					data_for_events.speed			= slide_data.speed;
2293					
2294					data_for_history.view_number				= slide_data.view_number;
2295					data_for_history.page						= slide_data.page;
2296					data_for_history.effect						= 'infinite';
2297					data_for_history.pagination_page_permalink	= slide_data.pagination_page_permalink;
2298					
2299					if (
2300						slide_data.wpvPaginatorLayout.find( '.js-wpv-loop' ).length > 0 
2301						&& slide_data.responseView.find( '.js-wpv-loop' ).length > 0 
2302					) {
2303						slide_data.responseView
2304							.find( '.js-wpv-loop' )
2305							.children()
2306								.addClass( 'wpv-loop-item-blink' )
2307								.css( { 'opacity': '0.3' } );
2308						slide_data.responseView
2309							.find( '.js-wpv-loop' )
2310							.prepend( 
2311								slide_data.wpvPaginatorLayout
2312									.find( '.js-wpv-loop' )
2313									.html() 
2314							);
2315						slide_data.wpvPaginatorLayout.html( slide_data.responseView.html() );
2316						slide_data.wpvPaginatorLayout
2317							.find( '.wpv-loop-item-blink' )
2318								.removeClass( 'wpv-loop-item-blink' )
2319								.animate( { opacity: 1 }, slide_data.speed );
2320								
2321					} else {
2322						var oldHTML = slide_data.wpvPaginatorLayout.html(),
2323						oldArray = oldHTML.split( '<!-- WPV_Infinite_Scroll -->', 3 ),
2324						oldReplace = ( oldArray.length > 2 ) ? oldArray[1] : '';
2325						slide_data.wpvPaginatorLayout.html(
2326							slide_data.responseView.html().replace( 
2327								'<!-- WPV_Infinite_Scroll_Insert -->',
2328								oldReplace
2329							)
2330						);
2331					}
2332					data_for_events.layout = slide_data.wpvPaginatorLayout;
2333					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function() {
2334						$( this ).remove();
2335					});
2336					slide_data.wpvPaginatorLayout
2337						.unwrap()
2338						.attr( 'id', 'wpv-view-layout-' + slide_data.view_number  )
2339						.animate( { opacity: 1 }, 300, function() {
2340							slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2341
2342							self.get_paged_view( slide_data.view_number ).page = slide_data.page;
2343
2344							window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2345							window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2346							slide_data.callback_next_func();
2347							self.manage_browser_history( data_for_history );
2348							$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2349							self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2350						});
2351				}
2352			},
2353			slideh: function( slide_data ) {
2354				var height = slide_data.wpvPaginatorLayout.height(),
2355				old_height = slide_data.wpvPaginatorLayout.outerHeight(),
2356				new_height,
2357				data_for_events = {},
2358				data_for_history = {};
2359				
2360				data_for_events.view_unique_id	= slide_data.view_number;
2361				data_for_events.effect			= 'slideh';
2362				data_for_events.speed			= slide_data.speed;
2363				data_for_events.layout			= slide_data.responseView;
2364                data_for_events.filter			= slide_data.responseFilterSelector;
2365				
2366				data_for_history.view_number				= slide_data.view_number;
2367				data_for_history.page						= slide_data.page;
2368				data_for_history.effect						= 'slideh';
2369				data_for_history.pagination_page_permalink	= slide_data.pagination_page_permalink;
2370				
2371				if ( slide_data.next === true ) {
2372					slide_data.wpvPaginatorLayout.css( 'float', 'left' );
2373					slide_data.responseView.css( {"float": "left", "visibility": "visible"} );
2374					slide_data.wpvPaginatorLayout
2375						.after( slide_data.responseView )
2376						.parent()
2377							.children()
2378								.wrapAll( '<div style="width:5000px;" />' );
2379					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut(function() {
2380						$( this ).remove();
2381					});
2382					new_height = slide_data.responseView.outerHeight();
2383					if ( old_height === new_height ) {
2384						slide_data.wpvPaginatorLayout
2385							.parent()
2386								.animate( {marginLeft: '-' + slide_data.wpvPaginatorLayout.outerWidth()+'px'}, slide_data.speed+500, function() {
2387									slide_data.responseView.css( {'position': 'static', 'float': 'none'} );
2388									slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2389									
2390									slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2391									
2392									window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2393									window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2394									slide_data.callback_next_func();
2395									self.manage_browser_history( data_for_history );
2396									$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2397									self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2398								});
2399					} else if ( old_height > new_height ) {
2400						slide_data.wpvPaginatorLayout
2401							.parent()
2402								.animate( {marginLeft: '-' + slide_data.wpvPaginatorLayout.outerWidth()+'px'}, slide_data.speed+500, function() {
2403									slide_data.wpvPaginatorLayout
2404										.parent().parent()
2405											.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2406												slide_data.responseView.css( {'position': 'static', 'float': 'none'} );
2407												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2408												
2409												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2410												
2411												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2412												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2413												slide_data.callback_next_func();
2414												self.manage_browser_history( data_for_history );
2415												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2416												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2417											});
2418								});
2419					} else {
2420						slide_data.wpvPaginatorLayout
2421							.parent().parent()
2422								.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2423									slide_data.wpvPaginatorLayout
2424										.parent()
2425											.animate( {marginLeft: '-' + slide_data.wpvPaginatorLayout.outerWidth()+'px'}, slide_data.speed+500, function() {
2426												slide_data.responseView.css( {'position': 'static', 'float': 'none'} );
2427												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2428												
2429												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2430												
2431												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2432												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2433												slide_data.callback_next_func();
2434												self.manage_browser_history( data_for_history );
2435												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2436												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2437											});
2438								});
2439					}
2440				} else {
2441					slide_data.wpvPaginatorLayout.css( 'float', 'right' );
2442					slide_data.responseView.css( {'float': 'right', 'visibility': 'visible'} );
2443					slide_data.wpvPaginatorLayout
2444						.after( slide_data.responseView )
2445						.parent()
2446							.children()
2447								.wrapAll( '<div style="height:' + height +  ';width:' + ( slide_data.responseView.outerWidth() + slide_data.wpvPaginatorLayout.outerWidth() ) + 'px; margin-left:-' + ( slide_data.wpvPaginatorLayout.outerWidth() ) + 'px;" />' );
2448					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function() {
2449						$( this ).remove();
2450					});
2451					new_height = slide_data.responseView.outerHeight();
2452					if ( old_height === new_height ) {
2453						slide_data.wpvPaginatorLayout
2454							.parent()
2455								.animate( {marginLeft: '0px'}, slide_data.speed+500, function() {
2456									slide_data.responseView.css( {'position': 'static', 'margin': '0px', 'float': 'none'} );
2457									slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2458									
2459									slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2460									
2461									window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2462									window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2463									slide_data.callback_next_func();
2464									self.manage_browser_history( data_for_history );
2465									$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2466									self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2467								});
2468					} else if ( old_height > new_height ) {
2469						slide_data.wpvPaginatorLayout
2470							.parent()
2471								.animate( {marginLeft: '0px'}, slide_data.speed+500, function() {
2472									slide_data.wpvPaginatorLayout
2473										.parent().parent()
2474											.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2475												slide_data.responseView.css( {'position': 'static', 'margin': '0px', 'float': 'none'} );
2476												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2477												
2478												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2479												
2480												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2481												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2482												slide_data.callback_next_func();
2483												self.manage_browser_history( data_for_history );
2484												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2485												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2486											});
2487								});
2488					} else {
2489						slide_data.wpvPaginatorLayout
2490							.parent().parent()
2491								.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2492									slide_data.wpvPaginatorLayout
2493										.parent()
2494											.animate( {marginLeft: '0px'}, slide_data.speed+500, function() {
2495												slide_data.responseView.css( {'position': 'static', 'margin': '0px', 'float': 'none'} );
2496												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2497												
2498												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2499												
2500												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2501												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2502												slide_data.callback_next_func();
2503												self.manage_browser_history( data_for_history );
2504												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2505												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2506											});
2507								});
2508					}
2509				}
2510			},
2511			slidev: function( slide_data ) {
2512				var old_height = slide_data.wpvPaginatorLayout.outerHeight(),
2513				new_height,
2514				data_for_events = {},
2515				data_for_history = {};
2516				
2517				data_for_events.view_unique_id	= slide_data.view_number;
2518				data_for_events.effect			= 'slidev';
2519				data_for_events.speed			= slide_data.speed;
2520				data_for_events.layout			= slide_data.responseView;
2521                data_for_events.filter			= slide_data.responseFilterSelector;
2522				
2523				data_for_history.view_number				= slide_data.view_number;
2524				data_for_history.page						= slide_data.page;
2525				data_for_history.effect						= 'slidev';
2526				data_for_history.pagination_page_permalink	= slide_data.pagination_page_permalink;
2527				
2528				if ( slide_data.next === true ) {
2529					slide_data.responseView.css( 'visibility', 'visible' );
2530					slide_data.wpvPaginatorLayout
2531						.after( slide_data.responseView )
2532						.parent()
2533							.children()
2534								.wrapAll( '<div />' );
2535					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function(){
2536						$( this ).remove();
2537					});
2538					new_height = slide_data.responseView.outerHeight();
2539					if ( old_height === new_height ) {
2540						slide_data.wpvPaginatorLayout
2541							.parent()
2542								.animate( {marginTop: '-' + slide_data.responseView.outerHeight()+'px'}, slide_data.speed+500, function() {
2543									slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2544									slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2545									
2546									slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2547									
2548									window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2549									window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2550									slide_data.callback_next_func();
2551									self.manage_browser_history( data_for_history );
2552									$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2553									self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2554								});
2555					} else if ( old_height > new_height ) {
2556						slide_data.wpvPaginatorLayout
2557							.parent()
2558								.animate( {marginTop: '-'+old_height+'px'}, slide_data.speed+500, function() {
2559									slide_data.wpvPaginatorLayout
2560										.parent().parent()
2561											.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2562												slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2563	
2563											slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2564												
2565												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2566												
2567												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2568												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2569												slide_data.callback_next_func();
2570												self.manage_browser_history( data_for_history );
2571												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2572												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2573											});
2574								});
2575					} else {
2576						slide_data.wpvPaginatorLayout
2577							.parent().parent()
2578								.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2579									slide_data.wpvPaginatorLayout
2580										.parent()
2581											.animate( {marginTop: '-'+old_height+'px'}, slide_data.speed+500, function() {
2582												slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2583												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2584												
2585												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2586												
2587												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2588												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2589												slide_data.callback_next_func();
2590												self.manage_browser_history( data_for_history );
2591												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2592												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2593											});
2594								});
2595					}
2596				} else {
2597					slide_data.responseView.css( 'visibility', 'visible' );
2598					slide_data.wpvPaginatorLayout
2599						.before( slide_data.responseView )
2600						.parent()
2601							.children()
2602								.wrapAll( '<div />' );
2603					$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function() {
2604						$( this ).remove();
2605					});
2606					new_height = slide_data.responseView.outerHeight();
2607					slide_data.wpvPaginatorLayout.parent().css( {'position': 'relative', 'margin-top': '-' + slide_data.responseView.outerHeight() + 'px'} );
2608					if ( old_height === new_height ) {
2609						slide_data.wpvPaginatorLayout
2610							.parent()
2611								.animate( {marginTop: '0px'}, slide_data.speed+500, function() {
2612									slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2613									slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2614									
2615									slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2616									
2617									window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2618									window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2619									slide_data.callback_next_func();
2620									self.manage_browser_history( data_for_history );
2621									$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2622									self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2623								});
2624					} else if ( old_height > new_height ) {
2625						slide_data.wpvPaginatorLayout
2626							.parent()
2627								.animate( {marginTop: '0px'}, slide_data.speed+500, function() {
2628									slide_data.wpvPaginatorLayout
2629										.parent().parent()
2630											.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2631												slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2632												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2633												
2634												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2635												
2636												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2637												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2638												slide_data.callback_next_func();
2639												self.manage_browser_history( data_for_history );
2640												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2641												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2642											});
2643						});
2644					} else {
2645						slide_data.wpvPaginatorLayout
2646							.parent().parent()
2647								.animate( {height: slide_data.responseView.outerHeight()+'px'}, slide_data.speed/2, function() {
2648									slide_data.wpvPaginatorLayout
2649										.parent()
2650											.animate( {marginTop: '0px'}, slide_data.speed+500, function() {
2651												slide_data.responseView.css( {'position': 'static', 'margin': '0px'} );
2652												slide_data.wpvPaginatorLayout.unwrap().unwrap().remove();
2653												
2654												slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2655												
2656												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2657												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2658												slide_data.callback_next_func();
2659												self.manage_browser_history( data_for_history );
2660												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2661												self.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2662											});
2663								});
2664					}
2665				}
2666			},
2667			fade: function( slide_data ) {
2668				var old_height = slide_data.wpvPaginatorLayout.outerHeight(),
2669				new_height,
2670				data_for_events = {},
2671				data_for_history = {};
2672
2673				data_for_events.view_unique_id	= slide_data.view_number;
2674				data_for_events.effect			= 'fade';
2675				data_for_events.speed			= slide_data.speed;
2676				data_for_events.layout			= slide_data.responseView;
2677                data_for_events.filter			= slide_data.responseFilterSelector;
2678				
2679				data_for_history.view_number				= slide_data.view_number;
2680				data_for_history.page						= slide_data.page;
2681				data_for_history.effect						= 'fade';
2682				data_for_history.pagination_page_permalink	= slide_data.pagination_page_permalink;
2683				
2684				$( '.js-wpv_slide_loading_img_' + slide_data.view_number ).fadeOut( function() {
2685					$( this ).remove();
2686				});
2687
2688				slide_data.wpvPaginatorLayout
2689					.css( {'position': 'absolute', 'z-index': '5'} )
2690					.after( slide_data.responseView )
2691						.next()
2692						.css( 'position', 'static' );
2693				// We need to set a zero timeout here since the above modifications introduce a race condition that produces a wrong new_height 
2694				setTimeout( function() {
2695					new_height = slide_data.responseView.outerHeight();
2696					if ( old_height === new_height ) {
2697						slide_data.wpvPaginatorLayout.fadeOut( slide_data.speed, function() {
2698							slide_data.wpvPaginatorLayout.unwrap().remove();
2699
2700							slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2701						});
2702						// In the case when the old height is equal to the new height, we need to perform the fade-out of the old container and the
2703						// fade in of the new container in parallel, at the same time. Even though, UX-wise, this is not 100% correct, this choice
2704						// was made because of some clients complaints. This is due to backwards compatibility
2705						slide_data.responseView
2706							.hide()
2707							.css( 'visibility', 'visible' )
2708							.fadeIn( slide_data.speed, function() {
2709								window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2710								window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2711								slide_data.callback_next_func();
2712								self.manage_browser_history( data_for_history );
2713								$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2714								WPViews.view_pagination.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2715							});
2716					} else {
2717						slide_data.wpvPaginatorLayout.fadeOut( slide_data.speed, function() {
2718							slide_data.wpvPaginatorLayout
2719								.parent()
2720									.animate( {height: new_height+'px'}, slide_data.speed, function() {
2721										slide_data.wpvPaginatorLayout.unwrap().remove();
2722										
2723										slide_data.wpvPaginatorFilter.html( slide_data.responseFilter );
2724
2725										slide_data.responseView
2726											.hide()
2727											.css( 'visibility', 'visible' )
2728											.fadeIn( slide_data.speed, function() {
2729												window.wpvPaginationAjaxLoaded[slide_data.view_number] = true;
2730												window.wpvPaginationAnimationFinished[slide_data.view_number] = true;
2731												slide_data.callback_next_func();
2732												self.manage_browser_history( data_for_history );
2733												$( document ).trigger( 'js_event_wpv_pagination_completed', [ data_for_events ] );
2734												WPViews.view_pagination.pagination_queue_trigger( slide_data.view_number, slide_data.next, slide_data.wpvPaginatorFilter );
2735											});
2736									});
2737						});
2738					}
2739				}, 0 );
2740			}
2741		};
2742	
2743	};
2744	
2745	/**
2746	* manage_browser_history
2747	*
2748	* Makes the history in the browser work with AJAX pagination, except infinite scrolling and sliders
2749	*
2750	* @param object data
2751	*
2752	* @since 1.11
2753	*/
2754	
2755	self.manage_browser_history = function( data ) {
2756		if ( 
2757			self.get_paged_view( data.view_number ).type != 'rollover'
2758		) {
2759			if ( self.get_paged_view( data.view_number ).manage_history == 'enabled' ) {
2760				if ( self.add_paginated_history == true ) {
2761					if ( ! _.contains( self.pagination_effect_state_keep, data.effect ) ) {
2762						if ( _.contains( self.pagination_effect_state_replace, data.effect ) ) {
2763							history.replaceState( null, '', data.pagination_page_permalink );
2764						} else {
2765							self.last_paginated_view.push( data.view_number );
2766							state_obj = { 
2767								view_number: data.view_number, 
2768								page: data.page
2769							};
2770							history.pushState( state_obj, '', data.pagination_page_permalink );
2771							// http://scrollsample.appspot.com/items
2772							// http://html5.gingerhost.com/
2773							self.paginated_history_reach = self.paginated_history_reach + 1;
2774						}
2775					}
2776				} else {
2777					self.add_paginated_history = true;
2778				}
2779			}
2780		}
2781	};
2782	
2783	/**
2784	* window.onpopstate
2785	*
2786	* Manages the browser back button click based on daya added by Views pagination
2787	*
2788	* @since 1.11
2789	*/
2790	
2791	window.onpopstate = function( event ) {
2792		if ( event.state == null ) {
2793			var last_paginated_view_number = self.last_paginated_view.pop();
2794			if ( last_paginated_view_number != undefined ) {
2795				self.add_paginated_history = false;
2796				self.paged_views_initial_page[ last_paginated_view_number ] = self.paged_views_initial_page[ last_paginated_view_number ] || 1;
2797				self.trigger_pagination( last_paginated_view_number, self.paged_views_initial_page[ last_paginated_view_number ] );
2798			}
2799		} else {
2800			if (
2801				_.has( event.state, 'view_number' )
2802				&& _.has( event.state, 'page' )
2803			) {
2804				self.add_paginated_history = false;
2805				self.trigger_pagination( event.state.view_number, event.state.page );
2806			}
2807		}
2808	};
2809	
2810	/**
2811	* When the parametric search with automatic results has been completed, reset the pagination history and add a state with the current URL
2812	*
2813	* @since 1.11
2814	*/
2815	
2816	$( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
2817		window.wpvCachedPages[ data.view_unique_id ] = [];
2818		self.last_paginated_view = [];
2819		if ( self.paginated_history_reach > 0 ) {
2820			window.history.go( -Math.abs( self.paginated_history_reach ) );
2821			self.paginated_history_reach = 0;
2822		}
2823		// HACK! HACK! HACK!
2824		// Chrome and Safari execute history.replaceState before history.go so we end up with a mess
2825		// That is why we need to set a timeout here
2826		// See https://code.google.com/p/chromium/issues/detail?id=529810
2827		setTimeout( function() {
2828			history.replaceState( null, '', data.permalink );
2829		}, 100 );
2830	});
2831	
2832	/**
2833	* init_effects_conditions
2834	*
2835	* Lets you define a condition that an effect must meet to be applied, doing nothing otherwise.
2836	* Each callback gets the following parameters:
2837	* @param object	view_pagination_data
2838	* @param int	page
2839	*
2840	* @since 1.11
2841	*/
2842	
2843	self.init_effects_conditions = function() {
2844		self.pagination_effects_conditions = {
2845			infinite: function( view_pagination_data, page ) {
2846				if ( page != ( view_pagination_data.page + 1 ) ) {
2847					return false;
2848				}
2849				return true;				
2850			}
2851		};
2852	};
2853	
2854	/**
2855	* init_effects_conditions
2856	*
2857	* Lets you define a condition that an effect must meet to be applied, doing nothing otherwise.
2858	* Each callback gets the following parameters:
2859	* @param string	view_number
2860	* @param object	wpvPaginatorLayout
2861	*
2862	* @since 1.11
2863	*/
2864	
2865	self.init_effects_spinner = function() {
2866		self.pagination_effects_spinner['fade']			= 
2867		self.pagination_effects_spinner['slideleft']	= 
2868		self.pagination_effects_spinner['slideright']	= 
2869		self.pagination_effects_spinner['sliderightforward']	= 
2870		self.pagination_effects_spinner['slideh']		= 
2871		self.pagination_effects_spinner['slideup']		=
2872		self.pagination_effects_spinner['slidedown']	= 
2873		self.pagination_effects_spinner['slidedownforward']	= 
2874		self.pagination_effects_spinner['slidev']		= function( view_number, wpvPaginatorLayout ) {
2875			var img = new Image();
2876			img.src = self.get_paged_view( view_number ).spinner_image;
2877			img.onload = function() {
2878				var wpvPaginatorLayoutOffset = wpvPaginatorLayout.position(),
2879				wpvPaginatorSpinner = '<div style="'
2880					+ 'width:' + img.width + 'px;'
2881					+ 'height:' + img.height + 'px;'
2882					+ 'border:none;'
2883					+ 'background:transparent 50% 50% no-repeat url(' + self.get_paged_view( view_number ).spinner_image + ');'
2884					+ 'position:absolute;'
2885					+ 'z-index:99;'
2886					+ 'top:' + ( Math.round( wpvPaginatorLayoutOffset.top ) + ( Math.round( wpvPaginatorLayout.height()/2 ) ) - ( Math.round( img.height/2 ) ) ) + 'px;'
2887					+ 'left:' + ( Math.round( wpvPaginatorLayoutOffset.left ) + ( Math.round( wpvPaginatorLayout.width()/2 ) ) - ( Math.round( img.width/2 ) ) ) + 'px;'
2888					+ '" '
2889					+ 'class="wpv_slide_loading_img js-wpv_slide_loading_img_' + view_number + '"'
2890					+ '>'
2891					+ '</div>';
2892				wpvPaginatorLayout
2893					.before( wpvPaginatorSpinner )
2894						.animate( { opacity: 0.5 }, 300 );
2895			};
2896		};
2897		self.pagination_effects_spinner['infinite'] = function( view_number, wpvPaginatorLayout ) {
2898			var img = new Image();
2899			img.src = self.get_paged_view( view_number ).spinner_image;
2900			img.onload = function() {
2901				var wpvPaginatorLayoutOffset = wpvPaginatorLayout.position(),
2902				wpvPaginatorSpinner = '<div style="'
2903					+ 'width:' + img.width + 'px;'
2904					+ 'height:' + img.height + 'px;'
2905					+ 'border:none;'
2906					+ 'background:transparent 50% 50% no-repeat url(' + self.get_paged_view( view_number ).spinner_image + ');'
2907					+ 'position:absolute;'
2908					+ 'z-index:99;'
2909					+ 'top:' + ( Math.round( wpvPaginatorLayoutOffset.top ) + ( wpvPaginatorLayout.height() ) - ( Math.round( img.height/2 ) ) ) + 'px;'
2910					+ 'left:' + ( Math.round( wpvPaginatorLayoutOffset.left ) + ( Math.round( wpvPaginatorLayout.width()/2 ) ) - ( Math.round( img.width/2 ) ) ) + 'px;'
2911					+ '" '
2912					+ 'class="wpv_slide_loading_img js-wpv_slide_loading_img_' + view_number + '"'
2913					+ '>'
2914					+ '</div>';
2915				wpvPaginatorLayout
2916					.before( wpvPaginatorSpinner )
2917						.animate( { opacity: 0.5 }, 300 );
2918			};
2919		};
2920	};
2921	
2922	/**
2923	* init_paged_views
2924	*
2925	* Gather the data for paginating each of the Views rendered in a page
2926	*
2927	* @since 1.11
2928	*/
2929	
2930	self.init_paged_views = function( container ) {
2931		var init_scrolling_event = false,
2932		init_rollover_timing = false;
2933		this.historyP = this.historyP || [];
2934		window.wpvCachedPages = window.wpvCachedPages || [];
2935		window.wpvCachedImages = window.wpvCachedImages || [];
2936		$( '.js-wpv-view-layout', container ).each( function() {
2937			var thiz = $( this ),
2938			view_number = thiz.data( 'viewnumber' );
2939			self.init_paged_view( view_number );
2940			if (
2941				self.paged_views[ view_number ].effect == 'infinite' 
2942				&& self.paged_views[ view_number ].page == 1
2943			) {
2944				init_scrolling_event = true;
2945			}
2946			if ( 
2947				self.paged_views[ view_number ].type == 'rollover' 
2948				&& ! wpv_stop_rollover.hasOwnProperty( view_number ) 
2949			) {
2950				init_rollover_timing	= true;
2951				rollover_has_index		= _.findIndex( self.rollover_running, function( item ) { 
2952					return item.view_number == view_number; 
2953				});
2954				if ( rollover_has_index < 0 ) {
2955					// This rollover was not there, so trigger it
2956					var thiz_rollover_data = { 
2957						view_number:	view_number, 
2958						page:			1,
2959						force_reset:	false
2960					};
2961					self.rollover_running.push( thiz_rollover_data );
2962					if ( self.init_rollover_timing_fired ) {
2963						self.trigger_rollover( thiz_rollover_data );
2964					}
2965				} else {
2966					self.rollover_running[ rollover_has_index ] = {
2967						view_number:	view_number,
2968						page:			1,
2969						force_reset:	true
2970					};
2971				}
2972			}
2973		});
2974		if ( 
2975			! self.init_scrolling_event_fired 
2976			&& init_scrolling_event 
2977		) {
2978			self.init_scrolling_event_callback();
2979		}
2980		
2981		if ( 
2982			! self.init_rollover_timing_fired
2983			&& init_rollover_timing
2984		) {
2985			self.init_rollover_timing_callback();
2986		}
2987		return self;
2988	};
2989	
2990	/**
2991	* init_paged_view
2992	*
2993	* Gather pagination info for a specific View rendered in a page.
2994	* Note that this is also used to init the View pagination data after a parametric search change.
2995	*
2996	* @todo check the existence of $( '#wpv-view-layout-' + view_number ) and set defauls otherwise. 
2997	*
2998	* @since 1.11
2999	*/
3000	
3001	self.init_paged_view = function( view_number ) {
3002		this.historyP = this.historyP || [];
3003		self.paged_views[ view_number ] = $( '#wpv-view-layout-' + view_number ).data( 'pagination' );
3004		self.paged_views_initial_page[ view_number ] = self.paged_views[ view_number ].page;
3005		this.historyP[ view_number ] = self.paged_views[ view_number ].page;
3006		window.wpvCachedPages[ view_number ] = [];
3007		if ( 
3008			self.paged_views[ view_number ].type != 'disabled' 
3009			&& self.paged_views[ view_number ].type != 'paged' 
3010			&& self.paged_views[ view_number ].page > 1 
3011		) {
3012			// Infinite scrolling only can be triggered from the first page - individual URLs can not have that effect
3013			$( '#wpv-view-layout-' + view_number ).removeClass( 'js-wpv-layout-infinite-scrolling' );
3014		}
3015		if ( $( '#wpv-view-layout-' + view_number ).parents( '.js-wpv-view-layout' ).length > 0 ) {
3016			// Disable history management in inner Views in nested structures
3017			self.paged_views[ view_number ].manage_history = 'disabled';
3018		}
3019	};
3020	
3021	/**
3022	 * Generate the View pagintion data, on demand.
3023	 *
3024	 * This method will ensure that we can generate the pagination data for a View JIT 
3025	 * when it is needed for a View which was dynamically added to the page, by a 
3026	 * third party provider.
3027	 *
3028	 * @param view_number string The View unique hash.
3029	 *
3030	 * @since 2.3.1
3031	 */
3032	
3033	self.get_paged_view = function( view_number ) {
3034		if ( ! _.has( self.paged_views, view_number ) ) {
3035			self.init_paged_view( view_number );
3036		}
3037		return self.paged_views[ view_number ];
3038	}
3039	
3040	/**
3041	* is_infinite_triggable
3042	*
3043	* Auxiliar method to check whether the scroll got to a point where a pagination event should be triggered
3044	*
3045	* @param object	view_layout
3046	*
3047	* @since 1.11
3048	* @since 2.0	Add a tolerance setting
3049	* @since 2.0	Trigger the pagination when scrolling to the bottom of the page
3050	*/
3051	
3052	self.is_infinite_triggable = function( view_layout ) {
3053		var flag_element = view_layout,
3054		view_number = view_layout.data( 'viewnumber' );
3055		infinite_tolerance = self.get_paged_view( view_number ).infinite_tolerance;
3056		infinite_tolerance = ( isNaN( infinite_tolerance ) ) ? 0 : + infinite_tolerance;
3057		if ( view_layout.find( '.js-wpv-loop' ).length > 0 ) {
3058			flag_element = view_layout.find( '.js-wpv-loop' );
3059		}
3060		return (
3061			( flag_element.offset().top + flag_element.outerHeight() ) <= ( $( window ).scrollTop() + $( window ).height() + infinite_tolerance )
3062			|| ( $( window ).scrollTop() + $(window).height() ) == $( document ).height()
3063		);
3064	};
3065	
3066	/**
3067	* init_scrolling_event_callback
3068	*
3069	* Init the scrolling event callback, only when there is a View with infinite scrolling in a page
3070	*
3071	* @since 1.11
3072	*/
3073	
3074	self.init_scrolling_event_callback = function() {
3075		$( window ).on( 'scroll', _.debounce( 
3076			_.throttle( 
3077				function() {
3078					$( '.js-wpv-layout-infinite-scrolling' ).each( function() {
3079						var thiz = $( this ),
3080						thiz_view_number = thiz.data( 'viewnumber' ),
3081						thiz_paged_view_data = self.get_paged_view( thiz_view_number );
3082						if ( 
3083							thiz_paged_view_data.page < thiz_paged_view_data.max_pages 
3084							&& self.is_infinite_triggable( thiz )
3085						) {
3086							self.trigger_pagination( thiz_view_number, thiz_paged_view_data.page + 1 );
3087						}
3088					});
3089				},
3090				1000
3091			),
3092			1000
3093		));
3094		self.init_scrolling_event_fired = true;
3095	};
3096
3097	/**
3098	* trigger_rollover
3099	*
3100	* Trigger the rollover on a given View, using timeout
3101	*
3102	* @since 2.2
3103	*/
3104	
3105	self.trigger_rollover = function( view_data ) {
3106		var rollover_data	= $.extend( {}, { view_number: '', page: 1, force_reset: false }, view_data ),
3107		view_number			= rollover_data.view_number,
3108		paged_view_data		= self.get_paged_view( view_number );
3109		
3110		if ( 
3111			paged_view_data.max_pages > 1
3112			&& $("#wpv-view-layout-" + view_number ).length > 0 
3113		) {
3114			setTimeout( function() {
3115				var rollover_index = _.findIndex( self.rollover_paused, function ( item ) {
3116                    return item.view_number == view_number;
3117                } );
3118                if ( self.rollover_paused[ rollover_index ]
3119                	&& self.rollover_paused[ rollover_index ].view_number
3120					&& self.rollover_paused[ rollover_index ].view_number == view_number
3121				) {
3122                    setTimeout( function() { self.trigger_rollover( view_data ) }, 100 );
3123                } else {
3124                    if (
3125                        ! wpv_stop_rollover.hasOwnProperty( view_number ) &&
3126						$( "#wpv-view-layout-" + view_number ).length > 0
3127                    ) {
3128                        // Get native current page and index on the rollovers array
3129                        var view_page = rollover_data.page,
3130                            rollover_index = _.findIndex( self.rollover_running, function ( item ) {
3131                                return item.view_number == view_number;
3132                            } );
3133                        // If reset is force, set the current page to 1 and stop the force
3134                        if ( self.rollover_running[ rollover_index ].force_reset ) {
3135                            self.rollover_running[ rollover_index ].force_reset = false;
3136                            view_page = 1;
3137                        }
3138                        // Calculate the page to rollover to
3139                        if (
3140                            paged_view_data.effect === 'slideright'
3141                            || paged_view_data.effect === 'slidedown'
3142                        ) {
3143                            // Note that this was deprecated in 2.2, keep for backwards compatibility
3144                            if ( view_page <= 1 ) {
3145                                view_page = paged_view_data.max_pages;
3146                            } else {
3147                                view_page = view_page - 1;
3148                            }
3149                        } else {
3150                            if ( view_page === paged_view_data.max_pages ) {
3151                                view_page = 1;
3152                            } else {
3153                                view_page = view_page + 1;
3154                            }
3155                        }
3156                        // Set the new current page
3157                        self.rollover_running[ rollover_index ].page = view_page;
3158                        WPViews.view_pagination.trigger_pagination( view_number, view_page );
3159                    } else {
3160                        var rollover_index = _.findIndex( self.rollover_running, function ( item ) {
3161                            return item.view_number == view_number;
3162                        });
3163                        self.rollover_running.splice( rollover_index, 1 );
3164                    }
3165                }
3166			}, paged_view_data.speed * 1000 );
3167		} else {
3168			var rollover_index	= _.findIndex( self.rollover_running, function( item ) { 
3169				return item.view_number == view_number; 
3170			});
3171			self.rollover_running.splice( rollover_index, 1 );
3172		}
3173	};
3174	
3175	/**
3176	* init_rollover_timing_callback
3177	*
3178	* Init the rollover event callback, only when there is a View with rollover in a page
3179	*
3180	* @since 2.2
3181	* @since 2.3 Switched from iterating self.rollover_running to iterating a clone of it
3182	*			in order to avoid modification of the iterated array.
3183	*/
3184	
3185	self.init_rollover_timing_callback = function() {
3186		// We are cloning the self.rollover_running array and iterating the clone as we want to avoid modifying
3187		// the array that is been iterated. Remember that self.trigger_rollover removes views from the self.rollover_running
3188		// array, that don't need to be initiated as a rollover, for example when the view has only one page of results.
3189		var rollover_running = self.rollover_running.slice(0);
3190		_.each( rollover_running, function( view_data, index, list ) {
3191			self.trigger_rollover( view_data );
3192		});
3193		self.init_rollover_timing_fired = true;
3194	};
3195	
3196	$( document ).on( 'js_event_wpv_pagination_completed', function( event, data ) {
3197		if ( 
3198			self.get_paged_view( data.view_unique_id ).type == 'rollover' 
3199			&& ! wpv_stop_rollover.hasOwnProperty( data.view_unique_id ) 
3200		) {
3201			var rollover_index = _.findIndex( self.rollover_running, function( item ) { 
3202				return item.view_number == data.view_unique_id; 
3203			});
3204			self.trigger_rollover( self.rollover_running[ rollover_index ] );
3205		}
3206	});
3207	
3208	$( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
3209		if ( 
3210			self.get_paged_view( data.view_unique_id ).type == 'rollover' 
3211			&& ! wpv_stop_rollover.hasOwnProperty( data.view_unique_id ) 
3212		) {
3213			var rollover_index = _.findIndex( self.rollover_running, function( item ) { 
3214				return item.view_number == data.view_unique_id; 
3215			});
3216			self.trigger_rollover( self.rollover_running[ rollover_index ] );
3217		}
3218	});
3219
3220    $( document ).on( 'mouseenter', '.js-wpv-view-layout', function() {
3221        var view_number = $( this ).data( 'viewnumber' );
3222        if ( self.get_paged_view( view_number ).pause_on_hover == 'enabled' ) {
3223            var thiz_rollover_data = {
3224                view_number:	view_number,
3225            };
3226            self.rollover_paused.push( thiz_rollover_data );
3227        }
3228
3229    });
3230
3231    $( document ).on( 'mouseleave', '.js-wpv-view-layout', function() {
3232        var view_number = $( this ).data( 'viewnumber' );
3233        var rollover_index = _.findIndex( self.rollover_paused, function ( item ) {
3234            return item.view_number == view_number;
3235        });
3236        self.rollover_paused.splice( rollover_index, 1 );
3237    });
3238	
3239	/**
3240	* pagination_init_preload_images
3241	*
3242	* Init-preload images.
3243	*
3244	* @since 1.9
3245	*/
3246	
3247	self.init_preload_images = function( container ) {
3248		$( '.js-wpv-layout-preload-images', container ).css( 'visibility', 'hidden' ); // TODO move it to the CSS file and test
3249		$( '.js-wpv-layout-preload-images', container ).each( function() {
3250			var preloadedImages = [],
3251			element = $( this ),
3252			images = element.find( 'img' );
3253			if ( images.length < 1 ) {
3254				element.css( 'visibility', 'visible' );
3255			} else {
3256				images.one( 'load', function() {
3257					preloadedImages.push( $( this ).attr( 'src' ) );
3258					if ( preloadedImages.length === images.length ) {
3259						element.css( 'visibility', 'visible' );
3260					}
3261				}).each( function() {
3262					if( this.complete ) {
3263						$( this ).load();
3264					}
3265				});
3266				setTimeout( function() {
3267					element.css( 'visibility', 'visible' );
3268				}, 3000 );
3269			}
3270		});
3271	};
3272	
3273	self.init_preload_pages = function( container ) {
3274		$( '.js-wpv-layout-preload-pages', container ).each( function() {
3275			var thiz = $( this ),
3276			view_number = thiz.data( 'viewnumber' ),
3277			paged_view_data = self.get_paged_view( view_number ),
3278			max_pages = parseInt( paged_view_data.max_pages, 10 ),
3279			max_reach = parseInt( paged_view_data.preload_reach, 10 ) + 1;
3280			
3281			self.pagination_preload_pages({
3282				view_number:	view_number, 
3283				cache_pages:	'disabled', 
3284				preload_pages:	'enabled', 
3285				page:			1, 
3286				max_reach:		max_reach,
3287				max_pages:		max_pages 
3288			});
3289		});
3290	};
3291
3292    /**
3293     * init_pagination_button_state
3294	 *
3295	 * Initiate the pagination's button state in the case of a Bootstrap pager (only "Previous" and "Next" links)
3296     *
3297     * @since 2.4.0
3298     */
3299    self.init_pagination_button_state = function() {
3300        $( '.pagination li:not(.disabled,.active)' ).has('span').addClass('disabled');
3301        $( '.pagination li.page-item:empty' ).remove();
3302	};
3303	
3304	self.init = function() {
3305		self.init_effects();
3306		self.init_effects_conditions();
3307		self.init_effects_spinner();
3308		// Init Views inside the html
3309		var init_html = $( 'html' );
3310		self.init_paged_views( init_html );
3311		self.init_preload_images( init_html );
3312		self.init_preload_pages( init_html );
3313		self.init_pagination_button_state();
3314	}
3315	
3316	self.init();
3317
3318};
3319
3320WPViews.ViewParametricSearch = function( $ ) {
3321	
3322	// ------------------------------------
3323	// Constants and variables
3324	// ------------------------------------
3325	
3326	var self = this;
3327	
3328	// ------------------------------------
3329	// Methods
3330	// ------------------------------------
3331	
3332	self.manage_update_results = function( data ) {
3333		if ( data.ajax_before !== '' ) {
3334			var ajax_before_func = window[data.ajax_before];
3335			if ( typeof ajax_before_func === "function" ) {
3336				ajax_before_func( data.view_num );
3337			}
3338		}
3339		var data_for_events = {};
3340		data_for_events.view_unique_id	= data.view_num;
3341		data_for_events.permalink	= data.permalink;
3342		data.layout.fadeOut( 200, function() {
3343			data.layout.html( data.new_layout.html() )
3344				.attr( 'data-pagination', data.new_layout.attr( 'data-pagination' ) )
3345				.data( 'pagination', data.new_layout.data( 'pagination' ) )
3346				.fadeIn( 'fast', function() {
3347					var ajax_after_func = window[data.ajax_after];
3348					if ( typeof ajax_after_func === "function" ) {
3349						ajax_after_func( data.view_num );
3350					}
3351					data_for_events.layout = data.layout;
3352					$( document ).trigger( 'js_event_wpv_parametric_search_results_updated', [ data_for_events ] );
3353				});		
3354		});
3355	};
3356	
3357	/**
3358	* manage_changed_form
3359	*
3360	* @param settings	object
3361	* 	{
3362	*		view_unique_id:			string			View unique ID
3363	*		form:					collection		Filter jQuery object
3364	* 		force_form_update:		boolean			
3365	* 		update_form				boolean			Whether the form will be updated, either because forced or native
3366	* 		force_results_update:	boolean			
3367	* 		update_results			boolean			Whether the results wil be updated, either because forced or native
3368	*	};
3369	*
3370	* @todo Switch .js-wpv-filter-data-for-this-form into a form data attribute that we can init on document.ready and refresh when neeeded
3371	*
3372	* @since 1.9
3373	* @since 2.1	Merge a group of parameters into an object
3374	*/
3375	
3376	self.manage_changed_form = function( settings ) {
3377		
3378		var fil				= settings.form,
3379		view_num			= settings.view_unique_id,
3380		lay					= $( '#wpv-view-layout-' + view_num ),
3381		full_data			= fil.find( '.js-wpv-filter-data-for-this-form' ),
3382		ajax_pre_before		= full_data.data( 'ajaxprebefore' ),
3383		view_type			= 'full',
3384		additional_forms	= $( '.js-wpv-filter-form-' + view_num ).not( fil ),
3385		additional_forms_only,
3386		additional_forms_full,
3387		ajax_get			= 'both',
3388		new_content_form,
3389		new_content_form_filter,
3390		new_content_full,
3391		new_content_full_filter,
3392		new_content_full_layout,
3393		spinnerContainer	= fil.find( '.js-wpv-dps-spinner' ).add( additional_forms.find( '.js-wpv-dps-spinner' ) ),
3394		spinnerItems		= spinnerContainer.length
3395		data_for_events		= {},
3396		data_for_manage_updated_results	= {};
3397		
3398		data_for_events.view_unique_id	= view_num;
3399		
3400		data_for_manage_updated_results.view_num		= view_num;
3401		data_for_manage_updated_results.ajax_before		= full_data.data( 'ajaxbefore' );
3402		data_for_manage_updated_results.ajax_after		= full_data.data( 'ajaxafter' );
3403		
3404		if ( fil.hasClass( 'js-wpv-form-only' ) ) {
3405			view_type = 'form';
3406		}
3407		if ( settings.update_form ) {
3408			if ( additional_forms.length > 0 ) {
3409				additional_forms_only = additional_forms.not( '.js-wpv-form-full' );
3410				additional_forms_full = additional_forms.not( '.js-wpv-form-only' );
3411				if ( view_type == 'form' ) {
3412					if ( additional_forms_full.length > 0 || settings.update_results ) {
3413						ajax_get = 'both';					
3414					} else {
3415						ajax_get = 'form';
3416					}
3417					if ( settings.update_results ) {
3418						if ( ajax_pre_before !== '' ) {
3419							var ajax_pre_before_func = window[ajax_pre_before];
3420							if ( typeof ajax_pre_before_func === "function" ) {
3421								ajax_pre_before_func( view_num );
3422							}
3423						}
3424						$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3425					}
3426					if ( spinnerItems ) {// TODO maybe only when updating results
3427						$( spinnerContainer ).fadeIn( 'fast' );
3428					}
3429					
3430					wpv_stop_rollover[ view_num ] = true;
3431					
3432					WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, ajax_get )
3433						.done( function( response ) {
3434							if ( response.success ) {
3435								new_content_form = $( '<div></div>' ).append( response.data.form );
3436								new_content_full = $( '<div></div>' ).append( response.data.full );
3437								new_content_form_filter = new_content_form.find( '.js-wpv-filter-form-' + view_num );
3438								new_content_full_filter = new_content_full.find( '.js-wpv-filter-form-' + view_num );
3439								new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3440								
3441								fil.html( new_content_form_filter.html() );
3442								WPViews.view_frontend_utils.destroy_frontend_datepicker();
3443								WPViews.view_frontend_utils.clone_form( fil, additional_forms_only );
3444								additional_forms_full.each( function() {
3445									$( this ).html( new_content_full_filter.html() );
3446								});
3447								data_for_events.view_changed_form						= fil;
3448								data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3449								data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3450								$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3451								if ( settings.update_results ) {
3452									data_for_manage_updated_results.layout			= lay;
3453									data_for_manage_updated_results.new_layout		= new_content_full_layout;
3454									data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3455									self.manage_update_results( data_for_manage_updated_results );
3456								}
3457								spinnerContainer.hide();
3458							}
3459						});
3460				} else {
3461					if ( additional_forms_only.length > 0 ) {
3462						ajax_get = 'both';
3463					} else {
3464						ajax_get = 'full';
3465					}
3466					if ( settings.update_results ) {
3467						if ( ajax_pre_before !== '' ) {
3468							var ajax_pre_before_func = window[ajax_pre_before];
3469							if ( typeof ajax_pre_before_func === "function" ) {
3470								ajax_pre_before_func( view_num );
3471							}
3472						}
3473						$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3474					}
3475					if ( spinnerItems ) {// TODO maybe only when updating results
3476						$( spinnerContainer ).fadeIn( 'fast' );
3477					}
3478					
3479					wpv_stop_rollover[ view_num ] = true;
3480					
3481					WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, ajax_get )
3482						.done( function( response ) {
3483							if ( response.success ) {
3484								new_content_form = $( '<div></div>' ).append( response.data.form );
3485								new_content_full = $( '<div></div>' ).append( response.data.full );
3486								new_content_form_filter = new_content_form.find( '.js-wpv-filter-form-' + view_num );
3487								new_content_full_filter = new_content_full.find( '.js-wpv-filter-form-' + view_num );
3488								new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3489								
3490								fil.html( new_content_full_filter.html() );
3491								WPViews.view_frontend_utils.destroy_frontend_datepicker();
3492								WPViews.view_frontend_utils.clone_form( fil, additional_forms_full );
3493								additional_forms_only.each( function() {
3494									$( this ).html( new_content_form_filter.html() );
3495								});
3496								data_for_events.view_changed_form						= fil;
3497								data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3498								data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3499								$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3500								if ( settings.update_results ) {
3501									data_for_manage_updated_results.layout			= lay;
3502									data_for_manage_updated_results.new_layout		= new_content_full_layout;
3503									data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3504									self.manage_update_results( data_for_manage_updated_results );
3505								}
3506								spinnerContainer.hide();
3507							}
3508						});
3509				}
3510			} else {
3511				if ( view_type == 'form' ) {
3512					if ( settings.update_results ) {
3513						ajax_get = 'both';
3514						// NOTE this should never happen:
3515						// If change is done on an only-form and there is no extra form, there is no full form thus there is no layout
3516						// WARNING this can be executed on an only-form form from a View with automatic results
3517						// I might want to avoid this branch completely
3518						// NOTE-2 might be a good idea to keep-on-clear// As we might be displaying the layout in non-standard ways
3519						// So keeping the check for lay.length should suffice
3520						
3521					} else {
3522						ajax_get = 'form';
3523					}
3524					
3525					if ( settings.update_results ) {
3526						if ( ajax_pre_before !== '' ) {
3527							var ajax_pre_before_func = window[ajax_pre_before];
3528							if ( typeof ajax_pre_before_func === "function" ) {
3529								ajax_pre_before_func( view_num );
3530							}
3531						}
3532						$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3533					}
3534					if ( spinnerItems ) {// TODO maybe only when updating results
3535						$( spinnerContainer ).fadeIn( 'fast' );
3536					}
3537					
3538					wpv_stop_rollover[ view_num ] = true;
3539					
3540					WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, ajax_get )
3541						.done( function( response ) {
3542							if ( response.success ) {
3543								new_content_form = $( '<div></div>' ).append( response.data.form );
3544								new_content_full = $( '<div></div>' ).append( response.data.full );
3545								new_content_form_filter = new_content_form.find( '.js-wpv-filter-form-' + view_num );
3546								//new_content_full_filter = new_content_full.find( '.js-wpv-filter-form' ).html();
3547								new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3548								fil.html( new_content_form_filter.html() );
3549								data_for_events.view_changed_form						= fil;
3550								data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3551								data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3552								$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3553								if ( settings.update_results ) {
3554									data_for_manage_updated_results.layout			= lay;
3555									data_for_manage_updated_results.new_layout		= new_content_full_layout;
3556									data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3557									self.manage_update_results( data_for_manage_updated_results );
3558								}
3559								spinnerContainer.hide();
3560							}
3561						});
3562				} else {
3563					if ( settings.update_results ) {
3564						if ( ajax_pre_before !== '' ) {
3565							var ajax_pre_before_func = window[ajax_pre_before];
3566							if ( typeof ajax_pre_before_func === "function" ) {
3567								ajax_pre_before_func( view_num );
3568							}
3569						}
3570						$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3571					}
3572					if ( spinnerItems ) {// TODO maybe only when updating results
3573						$( spinnerContainer ).fadeIn( 'fast' );
3574					}
3575					
3576					wpv_stop_rollover[ view_num ] = true;
3577					
3578					WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, 'full' )
3579						.done( function( response ) {
3580							if ( response.success ) {
3581								//new_content_form = $( '<div></div>' ).append( ajax_result.form );
3582								new_content_full = $( '<div></div>' ).append( response.data.full );
3583								//new_content_form_filter = new_content_form.find( '.js-wpv-filter-form' ).html();
3584								new_content_full_filter = new_content_full.find( '.js-wpv-filter-form-' + view_num );
3585								new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3586								fil.html( new_content_full_filter.html() );
3587								data_for_events.view_changed_form						= fil;
3588								data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3589								data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3590								$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3591								if ( settings.update_results ) {
3592									data_for_manage_updated_results.layout			= lay;
3593									data_for_manage_updated_results.new_layout		= new_content_full_layout;
3594									data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3595									self.manage_update_results( data_for_manage_updated_results );
3596								}
3597								spinnerContainer.hide();
3598							}
3599						});
3600				}
3601			}
3602		} else {
3603			if ( additional_forms.length > 0 ) {
3604				additional_forms_only = additional_forms.not( '.js-wpv-form-full' );
3605				additional_forms_full = additional_forms.not( '.js-wpv-form-only' );
3606				if ( view_type == 'form' ) {
3607					WPViews.view_frontend_utils.destroy_frontend_datepicker();
3608					WPViews.view_frontend_utils.clone_form( fil, additional_forms_only );
3609					if ( additional_forms_full.length > 0 || settings.update_results ) {
3610						if ( settings.update_results ) {
3611							if ( ajax_pre_before !== '' ) {
3612								var ajax_pre_before_func = window[ajax_pre_before];
3613								if ( typeof ajax_pre_before_func === "function" ) {
3614									ajax_pre_before_func( view_num );
3615								}
3616							}
3617							$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3618						}
3619						if ( spinnerItems ) {// TODO maybe only when updating results
3620							$( spinnerContainer ).fadeIn( 'fast' );
3621						}
3622						
3623						wpv_stop_rollover[ view_num ] = true;
3624						
3625						WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, 'full' )
3626							.done( function( response ) {
3627								if ( response.success ) {
3628									//new_content_form = $( '<div></div>' ).append( response.data.form );
3629									new_content_full = $( '<div></div>' ).append( response.data.full );
3630									//new_content_form_filter = new_content_form.find( '.js-wpv-filter-form' ).html();
3631									new_content_full_filter = new_content_full.find( '.js-wpv-filter-form-' + view_num );
3632									new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3633									
3634									additional_forms_full.each( function() {
3635										$( this ).html( new_content_full_filter.html() );
3636									});
3637									data_for_events.view_changed_form						= fil;
3638									data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3639									data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3640									$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3641									if ( settings.update_results ) {
3642										data_for_manage_u
3642pdated_results.layout			= lay;
3643										data_for_manage_updated_results.new_layout		= new_content_full_layout;
3644										data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3645										self.manage_update_results( data_for_manage_updated_results );
3646									}
3647									spinnerContainer.hide();
3648								}
3649							});
3650					} else {
3651						data_for_events.view_changed_form						= fil;
3652						data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3653						data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3654						$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3655					}
3656				} else {
3657					WPViews.view_frontend_utils.destroy_frontend_datepicker();
3658					WPViews.view_frontend_utils.clone_form( fil, additional_forms_full );
3659					WPViews.view_frontend_utils.render_frontend_datepicker();
3660					if ( additional_forms_only.length > 0 || settings.update_results ) {
3661						if ( additional_forms_only.length > 0 ) {
3662							ajax_get = 'both';
3663						} else {
3664							ajax_get = 'full';
3665						}
3666						
3667						if ( settings.update_results ) {
3668							if ( ajax_pre_before !== '' ) {
3669								var ajax_pre_before_func = window[ajax_pre_before];
3670								if ( typeof ajax_pre_before_func === "function" ) {
3671									ajax_pre_before_func( view_num );
3672								}
3673							}
3674							$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3675						}
3676						if ( spinnerItems ) {// TODO maybe only when updating results
3677							$( spinnerContainer ).fadeIn( 'fast' );
3678						}
3679						
3680						wpv_stop_rollover[ view_num ] = true;
3681						
3682						WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, ajax_get )
3683							.done( function( response ) {
3684								if ( response.success ) {
3685									new_content_form = $( '<div></div>' ).append( response.data.form );
3686									new_content_full = $( '<div></div>' ).append( response.data.full );
3687									new_content_form_filter = new_content_form.find( '.js-wpv-filter-form-' + view_num );
3688									//new_content_full_filter = new_content_full.find( '.js-wpv-filter-form' ).html();
3689									new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3690									additional_forms_only.each( function() {
3691										$( this ).html( new_content_form_filter.html() );
3692									});
3693									data_for_events.view_changed_form						= fil;
3694									data_for_events.view_changed_form_additional_forms_only	= additional_forms_only;
3695									data_for_events.view_changed_form_additional_forms_full	= additional_forms_full;
3696									$( document ).trigger( 'js_event_wpv_parametric_search_form_updated', [ data_for_events ] );
3697									if ( settings.update_results ) {
3698										data_for_manage_updated_results.layout			= lay;
3699										data_for_manage_updated_results.new_layout		= new_content_full_layout;
3700										data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3701										self.manage_update_results( data_for_manage_updated_results );
3702									}
3703									spinnerContainer.hide();
3704								}
3705							});
3706					}
3707				}
3708			} else {
3709				if ( settings.update_results ) {
3710					if ( ajax_pre_before !== '' ) {
3711						var ajax_pre_before_func = window[ajax_pre_before];
3712						if ( typeof ajax_pre_before_func === "function" ) {
3713							ajax_pre_before_func( view_num );
3714						}
3715					}
3716					$( document ).trigger( 'js_event_wpv_parametric_search_started', [ data_for_events ] );
3717					if ( spinnerItems ) {// TODO maybe only when updating results
3718						$( spinnerContainer ).fadeIn( 'fast' );
3719					}
3720					
3721					wpv_stop_rollover[ view_num ] = true;
3722					
3723					WPViews.view_frontend_utils.get_updated_query_results( view_num, 1, fil, 'full' )
3724						.done( function( response ) {
3725							if ( response.success ) {
3726								//new_content_form = $( '<div></div>' ).append( response.data.form );
3727								new_content_full = $( '<div></div>' ).append( response.data.full );
3728								//new_content_form_filter = new_content_form.find( '.js-wpv-filter-form' ).html();
3729								//new_content_full_filter = new_content_full.find( '.js-wpv-filter-form' ).html();
3730								new_content_full_layout = new_content_full.find( '.js-wpv-view-layout-' + view_num );
3731								data_for_manage_updated_results.layout			= lay;
3732								data_for_manage_updated_results.new_layout		= new_content_full_layout;
3733								data_for_manage_updated_results.permalink		= response.data['parametric_permalink'];
3734								self.manage_update_results( data_for_manage_updated_results );
3735								spinnerContainer.hide();
3736							}
3737						});
3738				}
3739			}
3740		}
3741	};
3742	
3743	/**
3744	* Normalize the data passed to the js_event_wpv_parametric_search_triggered event.
3745	*
3746	* @para data	Object
3747	* 	{
3748	*		view_unique_id:			string			View unique ID
3749	*		form:					collection		Filter jQuery object
3750	* 		force_form_update:		boolean			Optional
3751	* 		force_results_update:	boolean			Optional
3752	*	};
3753	*
3754	* @return settings	Object
3755	* 	{
3756	*		view_unique_id:			string			View unique ID
3757	*		form:					collection		Filter jQuery object
3758	* 		force_form_update:		boolean			
3759	* 		update_form				boolean			Whether the form will be updated, either because forced or native
3760	* 		force_results_update:	boolean			
3761	* 		update_results			boolean			Whether the results wil be updated, either because forced or native
3762	*	};
3763	*
3764	* @since 2.1
3765	*/
3766	
3767	self.extend_wpv_parametric_search_triggered_data = function( data ) {
3768		var defaults	= { 
3769			force_form_update:		false, 
3770			force_results_update:	false
3771		},
3772		settings		= $.extend( {}, defaults, data ),
3773		view_loop		= $( '#wpv-view-layout-' + settings.view_unique_id );
3774		
3775		if (
3776			settings.force_form_update == false 
3777			&& (
3778				// The form contains pagination settings and the results are set to be updated
3779				(
3780					settings.force_results_update == true 
3781					|| settings.form.hasClass( 'js-wpv-ajax-results-enabled' ) 
3782				) 
3783				&& _.has( WPViews.view_pagination.paged_views, settings.view_unique_id ) 
3784				&& _.has( WPViews.view_pagination.paged_views[ settings.view_unique_id ], 'has_controls_in_form' )
3785				&& WPViews.view_pagination.paged_views[ settings.view_unique_id ].has_controls_in_form == 'enabled'
3786			)
3787		) {
3788			settings.force_form_update = true;
3789		}
3790		
3791		settings.update_form	= ( settings.force_form_update || settings.form.hasClass( 'js-wpv-dps-enabled' ) );
3792		settings.update_results	= ( view_loop.length > 0 && ( settings.force_results_update || settings.form.hasClass( 'js-wpv-ajax-results-enabled' ) ) );
3793		
3794		return settings;
3795	};
3796	
3797	// ------------------------------------
3798	// Events
3799	// ------------------------------------
3800	
3801	// Show datepicker on date string click
3802	$( document ).on( 'click', '.js-wpv-date-display', function() {
3803		var url_param = $( this ).data( 'param' );
3804		$( '.js-wpv-date-front-end-' + url_param ).datepicker( 'show' );
3805	});
3806
3807	// Remove current selected date
3808	$( document ).on( 'click', '.js-wpv-date-front-end-clear', function(e) {
3809		e.preventDefault();
3810		var thiz = $( this ),
3811		url_param = thiz.data( 'param' ),
3812		form = thiz.closest( 'form' );
3813		form.find( '.js-wpv-date-param-' + url_param ).html( '' );
3814		form.find( '.js-wpv-date-front-end-' + url_param ).val( '' );
3815		thiz.hide();
3816		form.find('.js-wpv-date-param-' + url_param + '-value' )
3817			.val( '' )
3818			.trigger( 'change' );
3819	});
3820	
3821	$( document ).on( 'change', '.js-wpv-post-relationship-update', function() {
3822		var thiz = $( this ),
3823		fil = thiz.closest( 'form' ),
3824		view_number = fil.data( 'viewnumber' ),
3825		additional_forms = $( '.js-wpv-filter-form-' + view_number ).not( fil ),
3826		currentposttype = thiz.data( 'currentposttype' ),
3827		watchers = fil.find( '.js-wpv-' + currentposttype + '-watch' ).add( additional_forms.find( '.js-wpv-' + currentposttype + '-watch' ) ),
3828		watcherslength = watchers.length,
3829		i;
3830		if ( watcherslength ) {
3831			for( i = 0; i < watcherslength; i++ ) {
3832				$( watchers[i] )
3833					.attr( 'disabled', true )
3834					.removeAttr( 'checked' )
3835					.removeAttr( 'selected' )
3836					.not( ':button, :submit, :reset, :hidden, :radio, :checkbox' )
3837					.val( '0' );
3838			}
3839		}
3840		
3841		var data_for_events = {
3842			view_unique_id:		view_number,
3843			form:				fil,
3844			force_form_update:	true
3845		};
3846		
3847		data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3848		
3849		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3850	});
3851
3852	$( document ).on( 'change', '.js-wpv-filter-trigger', function() {
3853		var thiz = $( this ),
3854		fil = thiz.closest( 'form' ),
3855		view_number = fil.data( 'viewnumber' );
3856		
3857		var data_for_events = {
3858			view_unique_id:	view_number,
3859			form:			fil
3860		};
3861		
3862		data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3863		
3864		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3865	});
3866
3867	$( document ).on( 'click', '.js-wpv-ajax-results-enabled .js-wpv-submit-trigger, .js-wpv-ajax-results-submit-enabled .js-wpv-submit-trigger', function( e ) {
3868		e.preventDefault();
3869		var thiz = $( this ),
3870		fil = thiz.closest( 'form' ),
3871		view_number = fil.data( 'viewnumber' );
3872		
3873		var data_for_events = {
3874			view_unique_id:			view_number,
3875			form:					fil,
3876			force_form_update:		false,
3877			force_results_update:	true
3878		};
3879		
3880		data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3881		
3882		$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3883	});
3884
3885	$( document).on( 'keypress', '.js-wpv-ajax-results-enabled .js-wpv-filter-trigger-delayed, .js-wpv-ajax-results-submit-enabled .js-wpv-filter-trigger-delayed', function( e ) {
3886		// Enter pressed?
3887		if ( e.which == 13 ) {
3888			e.preventDefault();
3889			var thiz = $( this ),
3890			fil = thiz.closest( 'form' ),
3891			view_number = fil.data( 'viewnumber' );
3892			
3893			var data_for_events = {
3894				view_unique_id:			view_number,
3895				form:					fil,
3896				force_results_update:	true
3897			};
3898			
3899			data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3900			
3901			$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3902		}
3903	});
3904
3905	$( document ).on( 'click', '.js-wpv-reset-trigger', function( e ) {
3906		e.preventDefault();
3907		var thiz = $( this ),
3908		fil = thiz.closest( 'form' ),
3909		view_number = fil.data( 'viewnumber' ),
3910		additional_forms = $( '.js-wpv-filter-form-' + view_number ).not( fil ),
3911		watchers,
3912		watcherslength,
3913		i,
3914		target = fil.attr( 'action' ),
3915		form_only_force_update = false,
3916		form_only_results_force_update = false;
3917		
3918		if ( fil.hasClass( 'js-wpv-form-only' ) ) {
3919			watchers = fil.find( 'input, select' ).add( additional_forms.find( 'input, select' ) );
3920			watcherslength = watchers.length;
3921			form_only_force_update = ( fil.hasClass( 'js-wpv-dps-enabled' ) || ( fil.find( '.js-wpv-post-relationship-update' ).length > 0 ) );
3922			if (
3923				fil.hasClass( 'js-wpv-ajax-results-enabled' ) 
3924				|| fil.hasClass( 'js-wpv-ajax-results-submit-enabled' )
3925			) {
3926				form_only_results_force_update = true;
3927			}
3928			
3929			if ( watcherslength ) {
3930				for ( i = 0; i < watcherslength; i++ ) {
3931					if ( ! $( watchers[i] ).hasClass( 'js-wpv-keep-on-clear' ) ) {
3932						$( watchers[i] )
3933							.attr( 'disabled', form_only_force_update )
3934							.removeAttr( 'checked' )
3935							.removeAttr( 'selected' )
3936							.not( ':button, :submit, :reset, :hidden, :radio, :checkbox' )
3937							.val( '' );
3938					}
3939				}
3940			}
3941			
3942			var data_for_events = {
3943				view_unique_id:			view_number,
3944				form:					fil,
3945				force_form_update:		form_only_force_update,
3946				force_results_update:	form_only_results_force_update
3947			};
3948			
3949			data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3950			
3951			if( ! form_only_results_force_update && $( '#wpv-view-layout-' + fil.data( 'viewnumber' ) ).length > 0 ) {
3952                window.location.href = target;
3953			}
3954			else {
3955                $( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3956			}
3957
3958		} else if ( fil.hasClass( 'js-wpv-ajax-results-enabled' ) || fil.hasClass( 'js-wpv-ajax-results-submit-enabled' ) ) {
3959			watchers = fil.find( 'input, select' ).add( additional_forms.find( 'input, select' ) );
3960			watcherslength = watchers.length;
3961			if ( watcherslength ) {
3962				for ( i = 0; i < watcherslength; i++ ) {
3963					if ( ! $( watchers[i] ).hasClass( 'js-wpv-keep-on-clear' ) ) {
3964						$( watchers[i] )
3965							.attr( 'disabled', true )
3966							.removeAttr( 'checked' )
3967							.removeAttr( 'selected' )
3968							.not( ':button, :submit, :reset, :hidden, :radio, :checkbox' )
3969							.val( '' );
3970					}
3971				}
3972			}
3973			
3974			var data_for_events = {
3975				view_unique_id:			view_number,
3976				form:					fil,
3977				force_form_update:		true,
3978				force_results_update:	true
3979			};
3980			
3981			data_for_events = self.extend_wpv_parametric_search_triggered_data( data_for_events );
3982			
3983			$( document ).trigger( 'js_event_wpv_parametric_search_triggered', [ data_for_events ] );
3984		} else {
3985            window.location.href = WPViews.view_frontend_utils.updateUrlQuery( 'wpv_view_count', null, target );
3986		}
3987	});
3988	
3989	$( document ).on( 'js_event_wpv_parametric_search_triggered', function( event, settings ) {
3990		self.manage_changed_form( settings );
3991	});
3992
3993	// Also, stop the rollover if we do any modification on the parametric search form
3994
3995	$( document ).on( 'change', '.js-wpv-filter-trigger, .js-wpv-filter-trigger-delayed', function() {
3996		var thiz = $( this ),
3997		fil = thiz.closest( 'form' ),
3998		view_num = fil.data( 'viewnumber' );
3999		wpv_stop_rollover[view_num] = true;
4000	});
4001	
4002	// ------------------------------------
4003	// Custom events
4004	// ------------------------------------
4005	
4006	/**
4007	* js_event_wpv_parametric_search_started
4008	*
4009	* Event fired before updating the parametric search forms and results.
4010	*
4011	* @param data
4012	* 	- view_unique_id
4013	*
4014	* @since 1.9
4015	*/
4016	
4017	$( document ).on( 'js_event_wpv_parametric_search_started', function( event, data ) {
4018		
4019	});
4020	
4021	
4022	/**
4023	* js_event_wpv_parametric_search_form_updated
4024	*
4025	* Event fired after updating the parametric search forms.
4026	*
4027	* @param data
4028	* 	- view_unique_id
4029	* 	- view_changed_form
4030	* 	- view_changed_form_additional_forms_only
4031	* 	- view_changed_form_additional_forms_full
4032	*
4033	* @since 1.9
4034	*/
4035	
4036	$( document ).on( 'js_event_wpv_parametric_search_form_updated', function( event, data ) {
4037		WPViews.view_frontend_utils.render_frontend_datepicker();
4038	});
4039	
4040	/**
4041	* js_event_wpv_parametric_search_results_updated
4042	*
4043	* Event fired after updating the parametric search results.
4044	*
4045	* @param data
4046	* 	- view_unique_id
4047	* 	- layout
4048	*
4049	* @since 1.9
4050	*/
4051	
4052	$( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
4053		WPViews.view_frontend_utils.render_frontend_media_shortcodes( data.layout );
4054	});
4055	
4056	// ------------------------------------
4057	// Init
4058	// ------------------------------------
4059	
4060	self.init = function() {
4061		
4062	}
4063	
4064	self.init();
4065
4066};
4067
4068jQuery( document ).ready( function( $ ) {
4069	WPViews.view_frontend_utils = new WPViews.ViewFrontendUtils( $ );
4070	WPViews.view_sorting = new WPViews.ViewSorting( $ );
4071	WPViews.view_pagination = new WPViews.ViewPagination( $ );
4072    WPViews.view_parametric_search = new WPViews.ViewParametricSearch( $ );
4073});

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.