PageSourceSearch

https://fundacja2act.org/wp-content/themes/chaplin/assets/js/construct.js?ver=2.6.7

js fundacja2act.org collected 2026-10-02 01:06:41 UTC 36,823 bytes, 1,371 lines download raw bytes

1/*	-----------------------------------------------------------------------------------------------
2	Namespace
3--------------------------------------------------------------------------------------------------- */
4
5var chaplin = chaplin || {},
6    $ = jQuery;
7
8
9/*	-----------------------------------------------------------------------------------------------
10	Global variables
11--------------------------------------------------------------------------------------------------- */
12
13var $doc = $( document ),
14    $win = $( window ),
15    winHeight = $win.height(),
16    winWidth = $win.width();
17
18var viewport = {};
19	viewport.top = $win.scrollTop();
20	viewport.bottom = viewport.top + $win.height();
21
22
23/*	-----------------------------------------------------------------------------------------------
24	Helper functions
25--------------------------------------------------------------------------------------------------- */
26
27/* Output AJAX errors ------------------------ */
28
29function chaplinAJAXErrors( jqXHR, exception ) {
30	var message = '';
31	if ( jqXHR.status === 0 ) {
32		message = 'Not connect.n Verify Network.';
33	} else if ( jqXHR.status == 404 ) {
34		message = 'Requested page not found. [404]';
35	} else if ( jqXHR.status == 500 ) {
36		message = 'Internal Server Error [500].';
37	} else if ( exception === 'parsererror' ) {
38		message = 'Requested JSON parse failed.';
39	} else if ( exception === 'timeout' ) {
40		message = 'Time out error.';
41	} else if ( exception === 'abort' ) {
42		message = 'Ajax request aborted.';
43	} else {
44		message = 'Uncaught Error.n' + jqXHR.responseText;
45	}
46	console.log( 'AJAX ERROR:' + message );
47}
48
49/* Toggle an attribute ----------------------- */
50
51function chaplinToggleAttribute( $element, attribute, trueVal, falseVal ) {
52
53	if ( typeof trueVal === 'undefined' ) { trueVal = true; }
54	if ( typeof falseVal === 'undefined' ) { falseVal = false; }
55
56	if ( $element.attr( attribute ) !== trueVal ) {
57		$element.attr( attribute, trueVal );
58	} else {
59		$element.attr( attribute, falseVal );
60	}
61}
62
63
64/*	-----------------------------------------------------------------------------------------------
65	Interval Scroll
66--------------------------------------------------------------------------------------------------- */
67
68chaplin.intervalScroll = {
69
70	init: function() {
71
72		didScroll = false;
73
74		// Check for the scroll event
75		$win.on( 'scroll load', function() {
76			didScroll = true;
77		} );
78
79		// Once every 250ms, check if we have scrolled, and if we have, do the intensive stuff
80		setInterval( function() {
81			if ( didScroll ) {
82				didScroll = false;
83
84				// When this triggers, we know that we have scrolled
85				$win.triggerHandler( 'did-interval-scroll' );
86
87			}
88
89		}, 250 );
90
91	},
92
93} // chaplin.intervalScroll
94
95
96/*	-----------------------------------------------------------------------------------------------
97	Resize End Event
98--------------------------------------------------------------------------------------------------- */
99
100chaplin.resizeEnd = {
101
102	init: function() {
103
104		var resizeTimer;
105
106		$win.on( 'resize', function(e) {
107
108			clearTimeout( resizeTimer );
109			
110			resizeTimer = setTimeout( function() {
111
112				// Trigger this at the end of screen resizing
113				$win.triggerHandler( 'resize-end' );
114						
115			}, 250 );
116
117		} );
118
119	},
120
121} // chaplin.resizeEnd
122
123
124/*	-----------------------------------------------------------------------------------------------
125	Toggles
126--------------------------------------------------------------------------------------------------- */
127
128chaplin.toggles = {
129
130	init: function() {
131
132		// Do the toggle
133		chaplin.toggles.toggle();
134
135		// Check for toggle/untoggle on resize
136		chaplin.toggles.resizeCheck();
137
138		// Check for untoggle on escape key press
139		chaplin.toggles.untoggleOnEscapeKeyPress();
140
141	},
142
143	// Do the toggle
144	toggle: function() {
145
146		$( '*[data-toggle-target]' ).on( 'click', function( e ) {
147
148			// Get our targets
149			var $toggle = $( this ),
150				targetString = $( this ).data( 'toggle-target' );
151
152			if ( targetString == 'next' ) {
153				var $target = $toggle.next();
154			} else {
155				var $target = $( targetString );
156			}
157
158			// Trigger events on the toggle targets before they are toggled
159			if ( $target.is( '.active' ) ) {
160				$target.trigger( 'toggle-target-before-active' );
161			} else {
162				$target.trigger( 'toggle-target-before-inactive' );
163			}
164
165			// Get the class to toggle, if specified
166			var classToToggle = $toggle.data( 'class-to-toggle' ) ? $toggle.data( 'class-to-toggle' ) : 'active';
167
168			// For cover modals, set a short timeout duration so the class animations have time to play out
169			var timeOutTime = 0;
170
171			if ( $target.hasClass( 'cover-modal' ) ) {
172				var timeOutTime = 10;
173			}
174
175			setTimeout( function() {
176
177				// Toggle the target of the clicked toggle
178				if ( $toggle.data( 'toggle-type' ) == 'slidetoggle' ) {
179					var duration = $toggle.data( 'toggle-duration' ) ? $toggle.data( 'toggle-duration' ) : 250;
180					$target.slideToggle( duration );
181				} else {
182					$target.toggleClass( classToToggle );
183				}
184
185				// If the toggle target is 'next', only give the clicked toggle the active class
186				if ( targetString == 'next' ) {
187					$toggle.toggleClass( 'active' )
188
189				// If not, toggle all toggles with this toggle target
190				} else {
191					$( '*[data-toggle-target="' + targetString + '"]' ).toggleClass( 'active' );
192				}
193
194				// Toggle aria-expanded on the target
195				chaplinToggleAttribute( $target, 'aria-expanded', 'true', 'false' );
196
197				// Toggle aria-pressed on the toggle
198				chaplinToggleAttribute( $toggle, 'aria-pressed', 'true', 'false' );
199
200				// Toggle body class
201				if ( $toggle.data( 'toggle-body-class' ) ) {
202					$( 'body' ).toggleClass( $toggle.data( 'toggle-body-class' ) );
203				}
204
205				// Check whether to lock the screen
206				if ( $toggle.data( 'lock-screen' ) ) {
207					chaplin.scrollLock.setTo( true );
208				} else if ( $toggle.data( 'unlock-screen' ) ) {
209					chaplin.scrollLock.setTo( false );
210				} else if ( $toggle.data( 'toggle-screen-lock' ) ) {
211					chaplin.scrollLock.setTo();
212				}
213
214				// Check whether to set focus
215				if ( $toggle.data( 'set-focus' ) ) {
216					var $focusElement = $( $toggle.data( 'set-focus' ) );
217					if ( $focusElement.length ) {
218						if ( $toggle.is( '.active' ) ) {
219							$focusElement.focus();
220						} else {
221							$focusElement.blur();
222						}
223					}
224				}
225
226				// Trigger the toggled event on the toggle target
227				$target.triggerHandler( 'toggled' );
228
229				// Trigger events on the toggle targets after they are toggled
230				if ( $target.is( '.active' ) ) {
231					$target.trigger( 'toggle-target-after-active' );
232				} else {
233					$target.trigger( 'toggle-target-after-inactive' );
234				}
235
236			}, timeOutTime );
237
238			return false;
239
240		} );
241	},
242
243	// Check for toggle/untoggle on screen resize
244	resizeCheck: function() {
245
246		if ( $( '*[data-untoggle-above], *[data-untoggle-below], *[data-toggle-above], *[data-toggle-below]' ).length ) {
247
248			$win.on( 'resize', function() {
249
250				var winWidth = $win.width(),
251					$toggles = $( '.toggle' );
252
253				$toggles.each( function() {
254
255					$toggle = $( this );
256
257					var unToggleAbove = $toggle.data( 'untoggle-above' ),
258						unToggleBelow = $toggle.data( 'untoggle-below' ),
259						toggleAbove = $toggle.data( 'toggle-above' ),
260						toggleBelow = $toggle.data( 'toggle-below' );
261
262					// If no width comparison is set, continue
263					if ( ! unToggleAbove && ! unToggleBelow && ! toggleAbove && ! toggleBelow ) {
264						return;
265					}
266
267					// If the toggle width comparison is true, toggle the toggle
268					if ( 
269						( ( ( unToggleAbove && winWidth > unToggleAbove ) ||
270						( unToggleBelow && winWidth < unToggleBelow ) ) &&
271						$toggle.hasClass( 'active' ) )
272						||
273						( ( ( toggleAbove && winWidth > toggleAbove ) ||
274						( toggleBelow && winWidth < toggleBelow ) ) &&
275						! $toggle.hasClass( 'active' ) )
276					) {
277						$toggle.trigger( 'click' );
278					}
279
280				} );
281
282			} );
283
284		}
285
286	},
287
288	// Close toggle on escape key press
289	untoggleOnEscapeKeyPress: function() {
290
291		$doc.keyup( function( e ) {
292			if ( e.key === "Escape" ) {
293
294				$( '*[data-untoggle-on-escape].active' ).each( function() {
295					if ( $( this ).hasClass( 'active' ) ) {
296						$( this ).trigger( 'click' );
297					}
298				} );
299					
300			}
301		} );
302
303	},
304
305} // chaplin.toggles
306
307
308/*	-----------------------------------------------------------------------------------------------
309	Cover Modals
310--------------------------------------------------------------------------------------------------- */
311
312chaplin.coverModals = {
313
314	init: function () {
315
316		if ( $( '.cover-modal' ).length ) {
317
318			// Handle cover modals when they're toggled
319			chaplin.coverModals.onToggle();
320
321			// When toggled, untoggle if visitor clicks on the wrapping element of the modal
322			chaplin.coverModals.outsideUntoggle();
323
324			// Close on escape key press
325			chaplin.coverModals.closeOnEscape();
326
327			// Show a cover modal on load, if the query string says so
328			chaplin.coverModals.showOnLoadandClick();
329
330			// Hide and show modals before and after their animations have played out
331			chaplin.coverModals.hideAndShowModals();
332
333		}
334
335	},
336
337	// Handle cover modals when they're toggled
338	onToggle: function() {
339
340		$( '.cover-modal' ).on( 'toggled', function() {
341
342			var $modal = $( this ),
343				$body = $( 'body' );
344
345			if ( $modal.hasClass( 'active' ) ) {
346				$body.addClass( 'showing-modal' );
347			} else {
348				$body.removeClass( 'showing-modal' ).addClass( 'hiding-modal' );
349
350				// Remove the hiding class after a delay, when animations have been run
351				setTimeout ( function() {
352					$body.removeClass( 'hiding-modal' );
353				}, 500 );
354			}
355		} );
356
357	},
358
359	// Close modal on outside click
360	outsideUntoggle: function() {
361
362		$doc.on( 'click', function( e ) {
363
364			var $target = $( e.target ),
365				modal = '.cover-modal.active';
366
367			if ( $target.is( modal ) ) {
368
369				chaplin.coverModals.untoggleModal( $target );
370
371			}
372
373		} );
374
375	},
376
377	// Close modal on escape key press
378	closeOnEscape: function() {
379
380		$doc.keyup( function( e ) {
381			if ( e.key === "Escape" ) {
382				$( '.cover-modal.active' ).each( function() {
383					chaplin.coverModals.untoggleModal( $( this ) );
384				} );
385			}
386		} );
387
388	},
389
390	// Show modals on load
391	showOnLoadandClick: function() {
392
393		var key = 'modal';
394
395		// Load based on query string
396		if ( window.location.search.indexOf( key ) !== -1 ) {
397				
398			var modalTargetString = getQueryStringValue( key ),
399				$modalTarget = $( '#' + modalTargetString + '-modal' );
400
401			if ( modalTargetString && $modalTarget.length ) {
402				setTimeout( function() {
403					$modalTarget.addClass( 'active' ).triggerHandler( 'toggled' );
404					chaplin.scrollLock.setTo( true );
405				}, 250 );
406			}
407		}
408
409		// Check for modal matching querystring when clicking a link
410		// Format: www.url.com?modal=modal-id
411		$( 'a' ).on( 'click', function() {
412
413			// Load based on query string
414			if ( $( this ).attr( 'href' ) && $( this ).attr( 'href' ).indexOf( key ) !== -1 ) {
415					
416				var modalTargetString = getQueryStringValue( key, $( this ).attr( 'href' ) ),
417					$modalTarget = $( '#' + modalTargetString );
418
419				if ( modalTargetString && $modalTarget.length ) {
420					
421					$modalTarget.addClass( 'active' ).triggerHandler( 'toggled' );
422					chaplin.scrollLock.setTo( true );
423
424					return false;
425
426				}
427			}
428
429		} );
430
431	},
432
433	// Hide and show modals before and after their animations have played out
434	hideAndShowModals: function() {
435
436		var $modals = $( '.cover-modal' );
437
438		// Show the modal
439		$modals.on( 'toggle-target-before-inactive', function( e ) {
440			if ( e.target != this ) return;
441			
442			$( this ).addClass( 'show-modal' );
443		} );
444
445		// Hide the modal after a delay, so animations have time to play out
446		$modals.on( 'toggle-target-after-inactive', function( e ) {
447			if ( e.target != this ) return;
448
449			var $modal = $( this );
450			setTimeout( function() {
451				$modal.removeClass( 'show-modal' );
452			}, 500 );
453		} );
454
455	},
456
457	// Untoggle a modal
458	untoggleModal: function( $modal ) {
459
460		$modalToggle = false;
461
462		// If the modal has specified the string (ID or class) used by toggles to target it, untoggle the toggles with that target string
463		// The modal-target-string must match the string toggles use to target the modal
464		if ( $modal.data( 'modal-target-string' ) ) {
465			var modalTargetClass = $modal.data( 'modal-target-string' ),
466				$modalToggle = $( '*[data-toggle-target="' + modalTargetClass + '"]' ).first();
467		}
468
469		// If a modal toggle exists, trigger it so all of the toggle options are included
470		if ( $modalToggle && $modalToggle.length ) {
471			$modalToggle.trigger( 'click' );
472
473		// If one doesn't exist, just hide the modal
474		} else {
475			$modal.removeClass( 'active' );
476		}
477
478	}
479
480} // chaplin.coverModals
481
482
483/*	-----------------------------------------------------------------------------------------------
484	Element In View
485--------------------------------------------------------------------------------------------------- */
486
487chaplin.elementInView = {
488
489	init: function() {
490
491		$targets = $( '.do-spot' );
492		chaplin.elementInView.run( $targets );
493
494		// Rerun on AJAX content loaded
495		$win.on( 'ajax-content-loaded', function() {
496			$targets = $( '.do-spot' );
497			chaplin.elementInView.run( $targets );
498		} );
499
500	},
501
502	run: function( $targets ) {
503
504		if ( $targets.length ) {
505
506			// Add class indicating the elements will be spotted
507			$targets.each( function() {
508				$( this ).addClass( 'will-be-spotted' );
509			} );
510
511			chaplin.elementInView.handleFocus( $targets );
512		}
513
514	},
515
516	handleFocus: function( $targets ) {
517
518		// Get dimensions of window outside of scroll for performance
519		$win.on( 'load resize orientationchange', function() {
520			winHeight = $win.height();
521		} );
522
523		$win.on( 'resize orientationchange did-interval-scroll', function() {
524
525			var winTop 		= $win.scrollTop();
526				winBottom 	= winTop + winHeight;
527
528			// Check for our targets
529			$targets.each( function() {
530
531				var $this = $( this );
532
533				if ( chaplin.elementInView.isVisible( $this, checkAbove = true ) ) {
534					$this.addClass( 'spotted' ).triggerHandler( 'spotted' );
535				}
536
537			} );
538
539		} );
540
541	},
542
543	// Determine whether the element is in view
544	isVisible: function( $elem, checkAbove ) {
545
546		if ( typeof checkAbove === 'undefined' ) {
547			checkAbove = false;
548		}
549
550		var winHeight 				= $win.height();
551
552		var docViewTop 				= $win.scrollTop(),
553			docViewBottom			= docViewTop + winHeight,
554			docViewLimit 			= docViewBottom - 50;
555
556		var elemTop 				= $elem.offset().top,
557			elemBottom 				= $elem.offset().top + $elem.outerHeight();
558
559		// If checkAbove is set to true, which is default, return true if the browser has already scrolled past the element
560		if ( checkAbove && ( elemBottom <= docViewBottom ) ) {
561			return true;
562		}
563
564		// If not, check whether the scroll limit exceeds the element top
565		return ( docViewLimit >= elemTop );
566
567	}
568
569} // chaplin.elementInView
570
571
572/*	-----------------------------------------------------------------------------------------------
573	Fade Blocks
574--------------------------------------------------------------------------------------------------- */
575
576chaplin.fadeBlocks = {
577
578	init: function() {
579
580		var scroll = window.requestAnimationFrame ||
581					window.webkitRequestAnimationFrame ||
582					window.mozRequestAnimationFrame ||
583					window.msRequestAnimationFrame ||
584					window.oRequestAnimationFrame ||
585					// IE Fallback, you can even fallback to onscroll
586					function( callback ) { window.setTimeout( callback, 1000/60 ) };
587				 
588		function loop() {
589		
590			var windowOffset = window.pageYOffset;
591			
592			if ( windowOffset < $win.outerHeight() ) {
593				$( '.fade-block' ).css({ 
594					'opacity': 1 - ( windowOffset * 0.002 )
595				} );
596			}
597		
598			scroll( loop )
599		
600		}
601		loop();
602
603	},
604
605} // chaplin.fadeBlocks
606
607
608/*	-----------------------------------------------------------------------------------------------
609	Smooth Scroll
610--------------------------------------------------------------------------------------------------- */
611
612chaplin.smoothScroll = {
613
614	init: function() {
615
616		// Scroll to on-page elements by hash
617		$( 'body:not(.disable-smooth-scroll) a[href*="#"]' ).not( '[href="#"]' ).not( '[href="#0"]' ).not( '.do-not-smooth-scroll' ).on( 'click', function( e ) {
618			if ( location.pathname.replace(/^\//, '' ) == this.pathname.replace(/^\//, '' ) && location.hostname == this.hostname ) {
619				var $target = $( this.hash ).length ? $( this.hash ) : $( '[name=' + this.hash.slice(1) + ']' );
620				chaplin.smoothScroll.scrollToTarget( $target, $( this ) );
621				e.preventDefault();
622			}
623		} );
624
625		// Scroll to elements specified with a data attribute
626		$( 'body:not(.disable-smooth-scroll) *[data-scroll-to]' ).on( 'click', function( e ) {
627			var $target = $( $( this ).data( 'scroll-to' ) );
628			chaplin.smoothScroll.scrollToTarget( $target, $( this ) );
629			e.preventDefault();
630		} );
631
632	},
633
634	// Scroll to target
635	scrollToTarget: function( $target, $clickElem ) {
636
637		if ( $target.length ) {
638
639			var additionalOffset 	= 0,
640				scrollSpeed			= 500;
641
642			// Get options
643			if ( $clickElem && $clickElem.length ) {
644				additionalOffset 	= $clickElem.data( 'additional-offset' ) ? $clickElem.data( 'additional-offset' ) : additionalOffset,
645				scrollSpeed 		= $clickElem.data( 'scroll-speed' ) ? $clickElem.data( 'scroll-speed' ) : scrollSpeed;
646			}
647
648			// Determine offset
649			var originalOffset = $target.offset().top;
650
651			// Special handling of scroll offset when scroll locked
652			if ( $( 'html' ).attr( 'scroll-lock-top' ) ) {
653				var originalOffset = parseInt( $( 'html' ).attr( 'scroll-lock-top' ) ) + $target.offset().top;
654			}
655
656			// If the header is sticky, subtract its height from the offset
657			if ( $( '.header-inner.stick-me' ).length ) {
658				var originalOffset = originalOffset - $( '.header-inner.stick-me' ).outerHeight();
659			}
660
661			// Close any parent modal before scrolling
662			if ( $clickElem.closest( '.cover-modal' ).length ) {
663				chaplin.coverModals.untoggleModal( $clickElem.closest( '.cover-modal' ) );
664			}
665
666			// Add the additional offset
667			var scrollOffset = originalOffset + additionalOffset;
668
669			chaplin.smoothScroll.scrollToPosition( scrollOffset, scrollSpeed );
670
671		}
672
673	},
674
675	scrollToPosition: function( position, speed ) {
676
677		$( 'html, body' ).animate( {
678			scrollTop: position,
679		}, speed, function() {
680			$win.trigger( 'did-interval-scroll' );
681		} );
682
683	}
684
685} // chaplin.smoothScroll
686
687
688/*	-----------------------------------------------------------------------------------------------
689	Stick Me
690--------------------------------------------------------------------------------------------------- */
691chaplin.stickMe = {
692
693	init: function() {
694
695		var $stickyElement = $( '.stick-me' );
696
697		if ( $stickyElement.length ) {
698
699			var stickyClass = 'is-sticky',
700				stickyOffset = $stickyElement.scrollTop();
701
702			// Our stand-in element for stickyElement while stickyElement is off on a scroll
703			if ( ! $( '.sticky-adjuster' ).length ) {
704				$stickyElement.before( '<div class="sticky-adjuster"></div>' );
705			}
706
707			// Stick it on resize, scroll and load
708			$win.on( 'resize scroll load', function(){
709				var stickyOffset = $( '.sticky-adjuster' ).offset().top;
710				chaplin.stickMe.stickIt( $stickyElement, stickyClass, stickyOffset );
711			} );
712
713			chaplin.stickMe.stickIt( $stickyElement, stickyClass, stickyOffset );
714
715		}
716
717	},
718
719	// Check whether to stick the element
720	stickIt: function ( $stickyElement, stickyClass, stickyOffset ) {
721
722		var winScroll = $win.scrollTop();
723
724		if ( $stickyElement.css( 'display' ) != 'none' && winScroll > stickyOffset ) {
725
726			// If a sticky edge element exists and we've scrolled past it, stick it
727			if ( ! $stickyElement.hasClass( stickyClass ) ) {
728				$stickyElement.addClass( stickyClass );
729				$( '.sticky-adjuster' ).height( $stickyElement.outerHeight() ).css( 'margin-bottom', parseInt( $stickyElement.css( 'marginBottom' ) ) );
730				if ( $stickyElement.is( '.header-inner' ) ) {
731					$( 'body' ).addClass( 'header-is-sticky' );
732				}
733			}
734
735		// If not, remove class and sticky-adjuster properties
736		} else {
737			chaplin.stickMe.unstickIt( $stickyElement, stickyClass );
738		}
739
740	},
741
742	unstickIt: function( $stickyElement, stickyClass ) {
743
744		$stickyElement.removeClass( stickyClass );
745		$( '.sticky-adjuster' ).height( 0 ).css( 'margin-bottom', '0' );
746
747		if ( $stickyElement.is( '.header-inner' ) ) {
748			$( 'body' ).removeClass( 'header-is-sticky' );
749		}
750
751	}
752
753} // Stick Me
754
755
756/*	-----------------------------------------------------------------------------------------------
757	Intrinsic Ratio Embeds
758--------------------------------------------------------------------------------------------------- */
759
760chaplin.instrinsicRatioVideos = {
761
762	init: function() {
763
764		chaplin.instrinsicRatioVideos.makeFit();
765
766		$win.on( 'resize fit-videos', function() {
767
768			chaplin.instrinsicRatioVideos.makeFit();
769
770		} );
771
772	},
773
774	makeFit: function() {
775
776		var vidSelector = "iframe, object, video";
777
778		$( vidSelector ).each( function() {
779
780			var $video = $( this ),
781				$container = $video.parent(),
782				iTargetWidth = $container.width();
783
784			// Skip videos we want to ignore
785			if ( $video.hasClass( 'intrinsic-ignore' ) || $video.parent().hasClass( 'intrinsic-ignore' ) ) {
786				return true;
787			}
788
789			if ( ! $video.attr( 'data-origwidth' ) ) {
790
791				// Get the video element proportions
792				$video.attr( 'data-origwidth', $video.attr( 'width' ) );
793				$video.attr( 'data-origheight', $video.attr( 'height' ) );
794
795			}
796
797			// Get ratio from proportions
798			var ratio = iTargetWidth / $video.attr( 'data-origwidth' );
799
800			// Scale based on ratio, thus retaining proportions
801			$video.css( 'width', iTargetWidth + 'px' );
802			$video.css( 'height', ( $video.attr( 'data-origheight' ) * ratio ) + 'px' );
803
804		} );
805
806	}
807
808} // chaplin.instrinsicRatioVideos
809
810
811/*	-----------------------------------------------------------------------------------------------
812	Scroll Lock
813--------------------------------------------------------------------------------------------------- */
814
815chaplin.scrollLock = {
816
817	init: function() {
818
819		// Init variables
820		window.scrollLocked = false,
821		window.prevScroll = {
822			scrollLeft : $win.scrollLeft(),
823			scrollTop  : $win.scrollTop()
824		},
825		window.prevLockStyles = {},
826		window.lockStyles = {
827			'overflow-y' : 'scroll',
828			'position'   : 'fixed',
829			'width'      : '100%'
830		};
831
832		// Instantiate cache in case someone tries to unlock before locking
833		chaplin.scrollLock.saveStyles();
834
835	},
836
837	// Save context's inline styles in cache
838	saveStyles: function() {
839
840		var styleAttr = $( 'html' ).attr( 'style' ),
841			styleStrs = [],
842			styleHash = {};
843
844		if ( ! styleAttr ) {
845			return;
846		}
847
848		styleStrs = styleAttr.split( /;\s/ );
849
850		$.each( styleStrs, function serializeStyleProp( styleString ) {
851			if ( ! styleString ) {
852				return;
853			}
854
855			var keyValue = styleString.split( /\s:\s/ );
856
857			if ( keyValue.length < 2 ) {
858				return;
859			}
860
861			styleHash[ keyValue[ 0 ] ] = keyValue[ 1 ];
862		} );
863
864		$.extend( prevLockStyles, styleHash );
865	},
866
867	// Lock the scroll (do not call this directly)
868	lock: function() {
869
870		var appliedLock = {};
871
872		if ( scrollLocked ) {
873			return;
874		}
875
876		// Save scroll state and styles
877		prevScroll = {
878			scrollLeft : $win.scrollLeft(),
879			scrollTop  : $win.scrollTop()
880		};
881
882		chaplin.scrollLock.saveStyles();
883
884		// Compose our applied CSS, with scroll state as styles
885		$.extend( appliedLock, lockStyles, {
886			'left' : - prevScroll.scrollLeft + 'px',
887			'top'  : - prevScroll.scrollTop + 'px'
888		} );
889
890		// Then lock styles and state
891		$( 'html' ).css( appliedLock );
892		$( 'html' ).addClass( 'scroll-locked' );
893		$( 'html' ).attr( 'scroll-lock-top', prevScroll.scrollTop );
894		$win.scrollLeft( 0 ).scrollTop( 0 );
895
896		window.scrollLocked = true;
897	},
898
899	// Unlock the scroll (do not call this directly)
900	unlock: function() {
901
902		if ( ! window.scrollLocked ) {
903			return;
904		}
905
906		// Revert styles and state
907		$( 'html' ).attr( 'style', $( '<x>' ).css( prevLockStyles ).attr( 'style' ) || '' );
908		$( 'html' ).removeClass( 'scroll-locked' );
909		$( 'html' ).attr( 'scroll-lock-top', '' );
910		$win.scrollLeft( prevScroll.scrollLeft ).scrollTop( prevScroll.scrollTop );
911
912		window.scrollLocked = false;
913	},
914
915	// Call this to lock or unlock the scroll
916	setTo: function( on ) {
917
918		// If an argument is passed, lock or unlock accordingly
919		if ( arguments.length ) {
920			if ( on ) {
921				chaplin.scrollLock.lock();
922			} else {
923				chaplin.scrollLock.unlock();
924			}
925			// If not, toggle to the inverse state
926		} else {
927			if ( window.scrollLocked ) {
928				chaplin.scrollLock.unlock();
929			} else {
930				chaplin.scrollLock.lock();
931			}
932		}
933
934	},
935
936} // chaplin.scrollLock
937
938
939/*	-----------------------------------------------------------------------------------------------
940	Dynamic Screen Height
941--------------------------------------------------------------------------------------------------- */
942
943chaplin.dynamicScreenHeight = {
944
945	init: function() {
946
947		var $screenHeight = $( '.screen-height' );
948
949		$screenHeight.css( 'min-height', $win.innerHeight() );
950
951		setTimeout( function() {
952			$screenHeight.css( 'min-height', $win.innerHeight() );
953		}, 500 );
954
955		$win.on( 'resize', function() {
956			$screenHeight.css( 'min-height', $win.innerHeight() );
957		} );
958
959	},
960
961} // chaplin.dynamicScreenHeight
962
963
964/*	-----------------------------------------------------------------------------------------------
965	Focus Management
966--------------------------------------------------------------------------------------------------- */
967
968chaplin.focusManagement = {
969
970	init: function() {
971
972		// Add and remove a class from dropdown menu items on focus
973		chaplin.focusManagement.dropdownFocus();
974
975		// If the visitor tabs out of the main menu, return focus to the navigation toggle
976		// Also, if the visitor tabs into a hidden element, move the focus to the element after the hidden element
977		chaplin.focusManagement.focusLoop();
978
979	},
980
981	focusLoop: function() {
982		$( 'input, a, button' ).on( 'focus', function() {
983			if ( $( '.menu-modal' ).is( '.active' ) ) {
984				if ( ! $( this ).parents( '.menu-modal' ).length ) {
985					$( '.nav-untoggle' ).focus();
986				}
987			} else if ( $( '.search-modal' ).is( '.active' ) ) {
988				if ( ! $( this ).parents( '.search-modal' ).length ) {
989					$( '.search-modal .search-field' ).focus();
990				}
991			}
992		} );
993	},
994
995	dropdownFocus: function() {
996		$( '.dropdown-menu a' ).on( 'blur focus', function( e ) {
997			$( this ).parents( 'li.menu-item-has-children' ).toggleClass( 'focus' );
998			if ( e.type == 'focus' ) $( this ).trigger( 'focus-applied' );
999		} );
1000	}
1001
1002} // chaplin.focusManagement
1003
1004
1005/*	-----------------------------------------------------------------------------------------------
1006	Main Menu
1007--------------------------------------------------------------------------------------------------- */
1008
1009chaplin.mainMenu = {
1010
1011	init: function() {
1012
1013		// If the current menu item is in a sub level, expand all the levels higher up on load
1014		chaplin.mainMenu.expandLevel();
1015
1016		// Determine the direction of sub menus in the alt menu
1017		chaplin.mainMenu.directionCheck();
1018
1019	},
1020
1021	// If the current menu item is in a sub level, expand all the levels higher up on load
1022	expandLevel: function() {
1023		var $activeMenuItem = $( '.main-menu .current-menu-item' );
1024
1025		if ( $activeMenuItem.length !== false ) {
1026			$activeMenuItem.parents( 'li' ).each( function() {
1027				$subMenuToggle = $( this ).find( '.sub-menu-toggle' ).first();
1028				if ( $subMenuToggle.length ) {
1029					$subMenuToggle.trigger( 'click' );
1030				}
1031			} )
1032		}
1033	},
1034
1035	// Determine the direction of sub menus in the alt menu
1036	directionCheck: function() {
1037
1038		// Note: the focus-applied event is triggered 
1039		// by chaplin.focusManagement.dropdownFocus when
1040		// the sub has been given the .focus class.
1041
1042		$( '.main-menu-alt ul a' ).on( 'mouseover focus-applied', function() {
1043			var $sub = $( this ).closest( 'li' ).find( 'ul' ).first();
1044			if ( $sub.length ) {
1045
1046				$descendantSubs = $sub.find( 'ul' );
1047
1048				var subOffsetLeft = $sub.offset().left,
1049					subOffsetRight = subOffsetLeft + $sub.outerWidth(),
1050					winWidth = $win.width();
1051
1052				if ( subOffsetRight > winWidth ) {
1053					$sub.add( $descendantSubs ).removeClass( 'expand-right' ).addClass( 'expand-left' );
1054				} else if ( subOffsetLeft < 0 ) {
1055					$sub.add( $descendantSubs ).removeClass( 'expand-left' ).addClass( 'expand-right' );
1056				}
1057
1058			}
1059		} );
1060
1061	}
1062
1063} // chaplin.mainMenu
1064
1065
1066/*	-----------------------------------------------------------------------------------------------
1067	Load More
1068--------------------------------------------------------------------------------------------------- */
1069
1070chaplin.loadMore = {
1071
1072	init: function() {
1073
1074		var $pagination = $( '#pagination' );
1075
1076		// First, check that there's a pagination
1077		if ( $pagination.length ) {
1078
1079			// Default values for variables
1080			window.loading = false;
1081			window.lastPage = $pagination.hasClass( 'last-page' );
1082
1083			// Load more posts
1084			chaplin.loadMore.prepare( $pagination );
1085
1086			// Update browser history when the visitor scrolls through loaded posts
1087			chaplin.loadMore.updateHistoryOnScroll();
1088
1089		}
1090
1091	},
1092
1093	prepare: function( $pagination ) {
1094
1095		// Get the query arguments from the pagination element
1096		var query_args = JSON.parse( $pagination.attr( 'data-query-args' ) );
1097
1098		// If we're already at the last page, exit out here
1099		if ( query_args.paged == query_args.max_num_pages ) {
1100			$pagination.addClass( 'last-page' );
1101		} else {
1102			$pagination.removeClass( 'last-page' );
1103		}
1104
1105		// Get the load more type (button or scroll)
1106		var loadMoreType = $pagination.data( 'pagination-type' );
1107
1108		if ( ! loadMoreType ) {
1109			var loadMoreType = 'links';
1110		}
1111
1112		// Do the appropriate load more detection, depending on the type
1113		if ( loadMoreType == 'scroll' ) {
1114			chaplin.loadMore.detectScroll( $pagination, query_args );
1115		} else if ( loadMoreType == 'button' ) {
1116			chaplin.loadMore.detectButtonClick( $pagination, query_args );
1117		}
1118
1119	},
1120
1121	// Load more on scroll
1122	detectScroll: function( $pagination, query_args ) {
1123
1124		$win.on( 'did-interval-scroll', function() {
1125
1126			// If it's the last page, or we're already loading, we're done here
1127			if ( lastPage || loading ) {
1128				return;
1129			}
1130
1131			var paginationOffset 	= $pagination.offset().top,
1132				winOffset 			= $win.scrollTop() + $win.outerHeight();
1133
1134			// If the bottom of the window is below the top of the pagination, start loading
1135			if ( ( winOffset > paginationOffset ) ) {
1136				chaplin.loadMore.loadPosts( $pagination, query_args );
1137			}
1138
1139		} );
1140
1141	},
1142
1143	// Load more on click
1144	detectButtonClick: function( $pagination, query_args ) {
1145
1146		// Load on click
1147		$( '#load-more' ).on( 'click', function() {
1148
1149			// Make sure we aren't already loading
1150			if ( loading ) {
1151				return;
1152			}
1153
1154			chaplin.loadMore.loadPosts( $pagination, query_args );
1155			return false;
1156		} );
1157
1158	},
1159
1160	// Load the posts
1161	loadPosts: function( $pagination, query_args ) {
1162
1163		// We're now loading
1164		loading = true;
1165		$pagination.addClass( 'loading' ).removeClass( 'last-page' );
1166
1167		// Increment paged to indicate another page has been loaded
1168		query_args.paged++;
1169
1170		// Prepare the query args for submission
1171		var json_query_args = JSON.stringify( query_args );
1172
1173		$.ajax({
1174			url: chaplin_ajax_load_more.ajaxurl,
1175			type: 'post',
1176			data: {
1177				action: 'chaplin_ajax_load_more',
1178				json_data: json_query_args
1179			},
1180			success: function( result ) {
1181
1182				// Get the results
1183				var $result = $( result ),
1184					$articleWrapper = $( $pagination.data( 'load-more-target' ) );
1185
1186				// If there are no results, we're at the last page
1187				if ( ! $result.length ) {
1188					loading = false;
1189					$articleWrapper.addClass( 'no-results' );
1190					$pagination.addClass( 'last-page' ).removeClass( 'loading' );
1191				}
1192
1193				if ( $result.length ) {
1194
1195					$articleWrapper.removeClass( 'no-results' );
1196
1197					// Add the paged attribute to the articles, used by updateHistoryOnScroll()
1198					$result.find( 'article' ).each( function() {
1199						$( this ).attr( 'data-post-paged', query_args.paged );
1200					} );
1201
1202					// Wait for the images to load
1203					$result.imagesLoaded( function() {
1204
1205						// Append the results
1206						$articleWrapper.append( $result );
1207
1208						$win.triggerHandler( 'ajax-content-loaded' );
1209						$win.triggerHandler( 'did-interval-scroll' );
1210
1211						// Update history
1212						chaplin.loadMore.updateHistory( query_args.paged );
1213
1214						// We're now finished with the loading
1215						loading = false;
1216						$pagination.removeClass( 'loading' );
1217
1218						// If that was the last page, make sure we don't check for any more
1219						if ( query_args.paged == query_args.max_num_pages ) {
1220							$pagination.addClass( 'last-page' );
1221							lastPage = true;
1222							return;
1223						} else {
1224							$pagination.removeClass( 'last-page' );
1225							lastPage = false;
1226						}
1227
1228					} );
1229
1230				}
1231
1232			},
1233
1234			error: function( jqXHR, exception ) {
1235				chaplinAJAXErrors( jqXHR, exception );
1236			}
1237		} );
1238
1239	},
1240
1241	// Update browser history on scroll
1242	updateHistoryOnScroll: function() {
1243
1244		// Get the initial paged value
1245		var initialPaged = chaplin.loadMore.getCurrentPaged();
1246
1247		// Get the last post visible in the viewport, and set the browser history to the paged attribute of that post
1248		$win.on( 'did-interval-scroll', function() {
1249
1250			var $posts = $( '.posts article' );
1251
1252			// Check if the page has had posts loaded
1253			// This attribute is added by the loadPosts function
1254			if ( $posts.length && $( '[data-post-paged]' ).length ) {
1255
1256				// Store the ID attributes of the posts above the bottom of the viewport
1257				var postsVisible = [];
1258
1259				// Get the bottom of the viewport
1260				var winBottom = $win.scrollTop() + $win.height();
1261
1262				$posts.each( function() {
1263
1264					var elemBottom = $( this ).offset().top + $( this ).outerHeight(),
1265						elemId = $( this ).attr( 'id' );
1266
1267					// Add or remove the ID of the post, depending on whether it's within the viewport
1268					if ( elemBottom < winBottom ) {
1269						postsVisible.push( elemId );
1270					} else {
1271						var index = postsVisible.indexOf( elemId );
1272						if ( index !== -1 ) postsVisible.splice( elemId, 1 );
1273					}
1274
1275				} );
1276
1277				// If we have visible posts, check if we need to update the history
1278				if ( postsVisible.length !== 0 ) {
1279
1280					// Get the last visible post
1281					var $lastPost = $( '#' + postsVisible[postsVisible.length - 1] );
1282
1283					// Get the paged attribute of the post, or default to the initial paged value
1284					// (The initial set of posts do not have a paged attribute)
1285					var newPaged = $lastPost.attr( 'data-post-paged' ) ? $lastPost.attr( 'data-post-paged' ) : initialPaged,
1286						currentPaged = chaplin.loadMore.getCurrentPaged();
1287
1288					// Update the browser history with the paged value of the post
1289					if ( newPaged !== currentPaged ) {
1290						chaplin.loadMore.updateHistory( newPaged );
1291					}
1292
1293				}
1294
1295			}
1296
1297		} );
1298
1299	},
1300
1301	// Update browser history
1302    updateHistory: function( paged ) {
1303
1304		var newUrl,
1305			currentUrl = document.location.href;
1306
1307		// Ensure trailing slash
1308		if ( currentUrl.substr( -1 ) != '/' ) currentUrl += '/';
1309
1310		var hasPaginationRegexp = new RegExp( '^(.*/page)/[0-9]*/(.*$)' );
1311
1312		if ( hasPaginationRegexp.test( currentUrl ) ) {
1313			if ( paged ) {
1314				newUrl = currentUrl.replace( hasPaginationRegexp, '$1/' + paged + '/$2' );
1315			} else {
1316				// If there's no paged, remove /page/X from the string
1317				var pageString = currentUrl.match( /\/page\/(\d*)/ )[0];
1318				if ( pageString ) {
1319					newUrl = currentUrl.replace( pageString, '' );
1320				}
1321			}
1322		} else {
1323			var beforeSearchReplaceRegexp = new RegExp( '^([^?]*)(\\??.*$)' );
1324			newUrl = currentUrl.replace( beforeSearchReplaceRegexp, '$1page/' + paged + '/$2' );
1325		}
1326
1327		if ( newUrl == currentUrl ) return;
1328
1329		history.pushState( {}, '', newUrl );
1330
1331	},
1332
1333	// Get current paged value
1334	getCurrentPaged: function() {
1335
1336		var currentPaged = 0,
1337			currentUrl = document.location.href;
1338
1339		if ( new RegExp( '\/page\/(\d*)' ).test( currentUrl ) ) {
1340			currentPaged = currentUrl.match( /\/page\/(\d*)/ )[1];
1341		}
1342
1343		return currentPaged;
1344
1345	},
1346
1347} // chaplin.loadMore
1348
1349
1350/*	-----------------------------------------------------------------------------------------------
1351	Function Calls
1352--------------------------------------------------------------------------------------------------- */
1353
1354$doc.ready( function() {
1355
1356	chaplin.intervalScroll.init();				// Check for scroll on an interval
1357	chaplin.resizeEnd.init();					// Trigger event at end of resize
1358	chaplin.toggles.init();						// Handle toggles
1359	chaplin.coverModals.init();					// Handle cover modals
1360	chaplin.elementInView.init();				// Check if elements are in view
1361	chaplin.fadeBlocks.init();					// Fade elements on scroll
1362	chaplin.instrinsicRatioVideos.init();		// Retain aspect ratio of videos on window resize
1363	chaplin.smoothScroll.init();				// Smooth scroll to anchor link or a specific element
1364	chaplin.stickMe.init();						// Stick elements on scroll
1365	chaplin.scrollLock.init();					// Scroll Lock
1366	chaplin.mainMenu.init();					// Main Menu
1367	chaplin.focusManagement.init();				// Focus Management
1368	chaplin.dynamicScreenHeight.init();			// Dynamic Screen Height
1369	chaplin.loadMore.init();					// Load More	
1370
1371} );

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.