PageSourceSearch

https://thegincooperative.com/wp-content/themes/thegincooperative/js/unslider.js

js thegincooperative.com collected 2026-10-02 19:10:33 UTC 22,333 bytes, 754 lines download raw bytes

1
2// Document ready jquery
3$(document).ready(function() {
4    // Unslider
5    $('#toggleSearch').click(function(e) {
6        e.preventDefault();
7        e.stopPropagation();
8        $('.hiddenSearch').toggleClass('active');
9    });
10
11
12    $('#closeSearch').click(function(e) {
13        e.preventDefault();
14        e.stopPropagation();
15        $('.hiddenSearch').removeClass('active');
16    });
17
18setTimeout(function(){
19    if($('.unslider').length < 1 && $('.has_ae_slider').length < 1 && $('.main-image').length < 1){
20        $('.logoContainer').addClass('logoContainer-unslider');
21    }
22}, 750);
23    // Toggle Mobile Menu
24
25    $('#toggleMobileMenu').click(function(e) {
26        e.preventDefault();
27        e.stopPropagation();
28        $('.mobileMenuActive').addClass('active');
29        $(this).css('display', 'none');
30        $('#toggleMobileMenuClose').css('display', 'block');
31    });
32
33    $('#toggleMobileMenuClose').click(function(e) {
34        e.preventDefault();
35        e.stopPropagation();
36        $('.mobileMenuActive').removeClass('active');
37        $(this).css('display', 'none');
38        $('#toggleMobileMenu').css('display', 'block');
39    });
40
41
42        // Click outside
43
44        // Add icon to .menu-item-has-children
45        $('.menu-item-has-children > a').append('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"/></svg>');
46
47        // $('.menu-item-has-children > .sub-menu').prepend(
48        //     $('.menu-item-has-children > a').clone()
49        // );
50
51        $('.menu-item-has-children').each(function() {
52            // Prepend text "Heading" to each menu item with children
53            $(this).find('.sub-menu').prepend(
54                "<div class=\"sub-menu-heading\">" + $(this).children('a').first().text() + "</div>"
55            );
56        });
57
58
59    $('#nav_menu .menu-item-has-children > a').click(function(e) {
60        e.preventDefault();
61        e.stopPropagation();
62        if($(this).parent().children('.sub-menu').hasClass('active')){
63            $(this).parent().children('.sub-menu').removeClass('active');
64        } else {
65            $('.sub-menu').removeClass('active');
66            $(this).parent().children('.sub-menu').addClass('active');
67        }
68    });
69
70    // Click outside
71    $(document).click(function(e) {
72        $('.sub-menu').removeClass('active');
73
74        $('.sub-menu').click(function(e) {
75            e.stopPropagation();
76            return;
77        });
78
79    });
80
81});
82
83
84/**
85 *   Unslider
86 *   version 2.0
87 *   by @idiot and friends
88 */
89
90(function(factory) {
91	if (typeof module === 'object' && typeof module.exports === 'object') {
92		factory(require('jquery'));
93	} else if (typeof define === 'function' && define.amd) {
94	    // AMD. Register as an anonymous module.
95        define([], factory(window.jQuery));
96    } else {
97		factory(window.jQuery);
98	}
99}(function($) {
100	//  Don't throw any errors when jQuery
101	if(!$) {
102		return console.warn('Unslider needs jQuery');
103	}
104
105	$.Unslider = function(context, options) {
106		var self = this;
107
108		//  Create an Unslider reference we can use everywhere
109		self._ = 'unslider';
110
111		//  Store our default options in here
112		//  Everything will be overwritten by the jQuery plugin though
113		self.defaults = {
114			//  Should the slider move on its own or only when
115			//  you interact with the nav/arrows?
116			//  Only accepts boolean true/false.
117			autoplay: false,
118
119			//  3 second delay between slides moving, pass
120			//  as a number in milliseconds.
121			delay: 3000,
122
123			//  Animation speed in millseconds
124			speed: 750,
125
126			//  An easing string to use. If you're using Velocity, use a
127			//  Velocity string otherwise you can use jQuery/jQ UI options.
128			easing: 'swing', // [.42, 0, .58, 1],
129
130			//  Does it support keyboard arrows?
131			//  Can pass either true or false -
132			//  or an object with the keycodes, like so:
133			//  {
134			//	 prev: 37,
135			//	 next: 39
136			// }
137			//  You can call any internal method name
138			//  before the keycode and it'll be called.
139			keys: {
140				prev: 37,
141				next: 39
142			},
143
144			//  Do you want to generate clickable navigation
145			//  to skip to each slide? Accepts boolean true/false or
146			//  a callback function per item to generate.
147			nav: true,
148
149			//  Should there be left/right arrows to go back/forth?
150			//   -> This isn't keyboard support.
151			//  Either set true/false, or an object with the HTML
152			//  elements for each arrow like below:
153			arrows: {
154				prev: '<a class="' + self._ + '-arrow prev">Prev</a>',
155				next: '<a class="' + self._ + '-arrow next">Next</a>'
156			},
157
158			//  How should Unslider animate?
159			//  It can do one of the following types:
160			//  "fade": each slide fades in to each other
161			//  "horizontal": each slide moves from left to right
162			//  "vertical": each slide moves from top to bottom
163			animation: 'horizontal',
164
165			//  If you don't want to use a list to display your slides,
166			//  you can change it here. Not recommended and you'll need
167			//  to adjust the CSS accordingly.
168			selectors: {
169				container: 'ul:first',
170				slides: 'li'
171			},
172
173			//  Do you want to animate the heights of each slide as
174			//  it moves
175			animateHeight: false,
176
177			//  Active class for the nav
178			activeClass: self._ + '-active',
179
180			//  Have swipe support?
181			//  You can set this here with a boolean and always use
182			//  initSwipe/destroySwipe later on.
183			swipe: true,
184			// Swipe threshold -
185			// lower float for enabling short swipe
186			swipeThreshold: 0.2
187		};
188
189		//  Set defaults
190		self.$context = context;
191		self.options = {};
192
193		//  Leave our elements blank for now
194		//  Since they get changed by the options, we'll need to
195		//  set them in the init method.
196		self.$parent = null;
197		self.$container = null;
198		self.$slides = null;
199		self.$nav = null;
200		self.$arrows = [];
201
202		//  Set our indexes and totals
203		self.total = 0;
204		self.current = 0;
205
206		//  Generate a specific random ID so we don't dupe events
207		self.prefix = self._ + '-';
208		self.eventSuffix = '.' + self.prefix + ~~(Math.random() * 2e3);
209
210		//  In case we're going to use the autoplay
211		self.interval = [];
212
213		//  Get everything set up innit
214		self.init = function(options) {
215			//  Set up our options inside here so we can re-init at
216			//  any time
217			self.options = $.extend({}, self.defaults, options);
218
219			//  Our elements
220			self.$container = self.$context.find(self.options.selectors.container).addClass(self.prefix + 'wrap');
221			self.$slides = self.$container.children(self.options.selectors.slides);
222
223			//  We'll manually init the container
224			self.setup();
225
226			//  We want to keep this script as small as possible
227			//  so we'll optimise some checks
228			$.each(['nav', 'arrows', 'keys', 'infinite'], function(index, module) {
229				self.options[module] && self['init' + $._ucfirst(module)]();
230			});
231
232			//  Add swipe support
233			if(jQuery.event.special.swipe && self.options.swipe) {
234				self.initSwipe();
235			}
236
237			//  If autoplay is set to true, call self.start()
238			//  to start calling our timeouts
239			self.options.autoplay && self.start();
240
241			//  We should be able to recalculate slides at will
242			self.calculateSlides();
243
244			//  Listen to a ready event
245			self.$context.trigger(self._ + '.ready');
246
247			//  Everyday I'm chainin'
248			return self.animate(self.options.index || self.current, 'init');
249		};
250
251		self.setup = function() {
252			//  Add a CSS hook to the main element
253			self.$context.addClass(self.prefix + self.options.animation).wrap('<div class="' + self._ + '" />');
254			self.$parent = self.$context.parent('.' + self._);
255
256			//  We need to manually check if the container is absolutely
257			//  or relatively positioned
258			var position = self.$context.css('position');
259
260			//  If we don't already have a position set, we'll
261			//  automatically set it ourselves
262			if(position === 'static') {
263				self.$context.css('position', 'relative');
264			}
265
266			self.$context.css('overflow', 'hidden');
267		};
268
269		//  Set up the slide widths to animate with
270		//  so the box doesn't float over
271		self.calculateSlides = function() {
272			// update slides before recalculating the total
273			self.$slides = self.$container.children(self.options.selectors.slides);
274
275			self.total = self.$slides.length;
276
277			//  Set the total width
278			if(self.options.animation !== 'fade') {
279				var prop = 'width';
280
281				if(self.options.animation === 'vertical') {
282					prop = 'height';
283				}
284
285				self.$container.css(prop, (self.total * 100) + '%').addClass(self.prefix + 'carousel');
286				self.$slides.css(prop, (100 / self.total) + '%');
287			}
288		};
289
290
291		//  Start our autoplay
292		self.start = function() {
293			self.interval.push(setTimeout(function() {
294				//  Move on to the next slide
295				self.next();
296
297				//  If we've got autoplay set up
298				//  we don't need to keep starting
299				//  the slider from within our timeout
300				//  as .animate() calls it for us
301			}, self.options.delay));
302
303			return self;
304		};
305
306		//  And pause our timeouts
307		//  and force stop the slider if needed
308		self.stop = function() {
309            var timeout;
310            while(timeout = self.interval.pop()) {
311                clearTimeout(timeout);
312            }
313
314			return self;
315		};
316
317
318		//  Set up our navigation
319		self.initNav = function() {
320			var $nav = $('<nav class="' + self.prefix + 'nav"><ol /></nav>');
321
322			//  Build our click navigation item-by-item
323			self.$slides.each(function(key) {
324				//  If we've already set a label, let's use that
325				//  instead of generating one
326				var label = this.getAttribute('data-nav') || key + 1;
327
328				//  Listen to any callback functions
329				if($.isFunction(self.options.nav)) {
330					label = self.options.nav.call(self.$slides.eq(key), key, label);
331				}
332
333				//  And add it to our navigation item
334				$nav.children('ol').append('<li data-slide="' + key + '">' + label + '</li>');
335			});
336
337			//  Keep a copy of the nav everywhere so we can use it
338			self.$nav = $nav.insertAfter(self.$context);
339
340			//  Now our nav is built, let's add it to the slider and bind
341			//  for any click events on the generated links
342			self.$nav.find('li').on('click' + self.eventSuffix, function() {
343				//  Cache our link and set it to be active
344				var $me = $(this).addClass(self.options.activeClass);
345
346				//  Set the right active class, remove any other ones
347				$me.siblings().removeClass(self.options.activeClass);
348
349				//  Move the slide
350				self.animate($me.attr('data-slide'));
351			});
352		};
353
354
355		//  Set up our left-right arrow navigation
356		//  (Not keyboard arrows, prev/next buttons)
357		self.initArrows = function() {
358			if(self.options.arrows === true) {
359				self.options.arrows = self.defaults.arrows;
360			}
361
362			//  Loop our options object and bind our events
363			$.each(self.options.arrows, function(key, val) {
364				//  Add our arrow HTML and bind it
365				self.$arrows.push(
366					$(val).insertAfter(self.$context).on('click' + self.eventSuffix, self[key])
367				);
368			});
369		};
370
371
372		//  Set up our keyboad navigation
373		//  Allow binding to multiple keycodes
374		self.initKeys = function() {
375			if(self.options.keys === true) {
376				self.options.keys = self.defaults.keys;
377			}
378
379			$(document).on('keyup' + self.eventSuffix, function(e) {
380				$.each(self.options.keys, function(key, val) {
381					if(e.which === val) {
382						$.isFunction(self[key]) && self[key].call(self);
383					}
384				});
385			});
386		};
387
388		//  Requires jQuery.event.swipe
389		//  -> stephband.info/jquery.event.swipe
390		self.initSwipe = function() {
391			var width = self.$slides.width();
392
393			//  We don't want to have a tactile swipe in the slider
394			//  in the fade animation, as it can cause some problems
395			//  with layout, so we'll just disable it.
396			if(self.options.animation !== 'fade') {
397
398				self.$container.on({
399
400					movestart: function(e) {
401						//  If the movestart heads off in a upwards or downwards
402						//  direction, prevent it so that the browser scrolls normally.
403						if((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) {
404							return !!e.preventDefault();
405						}
406
407						self.$container.css('position', 'relative');
408					},
409
410					move: function(e) {
411						self.$container.css('left', -(100 * self.current) + (100 * e.distX / width) + '%');
412					},
413
414					moveend: function(e) {
415						// Check if swiped distance is greater than threshold.
416						// If yes slide to next/prev slide. If not animate to
417						// starting point.
418
419						if((Math.abs(e.distX) / width) > self.options.swipeThreshold) {
420
421							self[e.distX < 0 ? 'next' : 'prev']();
422						}
423						else {
424
425							self.$container.animate({left: -(100 * self.current) + '%' }, self.options.speed / 2 );
426						}
427					}
428				});
429			}
430		};
431
432		//  Infinite scrolling is a massive pain in the arse
433		//  so we need to create a whole bloody function to set
434		//  it up. Argh.
435		self.initInfinite = function() {
436			var pos = ['first', 'last'];
437
438			$.each(pos, function(index, item) {
439				self.$slides.push.apply(
440					self.$slides,
441
442					//  Exclude all cloned slides and call .first() or .last()
443					//  depending on what `item` is.
444					self.$slides.filter(':not(".' + self._ + '-clone")')[item]()
445
446					//  Make a copy of it and identify it as a clone
447					.clone().addClass(self._ + '-clone')
448
449					//  Either insert before or after depending on whether we're
450					//  the first or last clone
451					['insert' + (index === 0 ? 'After' : 'Before')](
452						//  Return the other element in the position array
453						//  if item = first, return "last"
454						self.$slides[pos[~~!index]]()
455					)
456				);
457			});
458		};
459
460		//  Remove any trace of arrows
461		//  Loop our array of arrows and use jQuery to remove
462		//  It'll unbind any event handlers for us
463		self.destroyArrows = function() {
464			$.each(self.$arrows, function(i, $arrow) {
465				$arrow.remove();
466			});
467		};
468
469		//  Remove any swipe events and reset the position
470		self.destroySwipe = function() {
471			//  We bind to 4 events, so we'll unbind those
472			self.$container.off('movestart move moveend');
473		};
474
475		//  Unset the keyboard navigation
476		//  Remove the handler
477		self.destroyKeys = function() {
478			//  Remove the event handler
479			$(document).off('keyup' + self.eventSuffix);
480		};
481
482		self.setIndex = function(to) {
483			if(to < 0) {
484				to = self.total - 1;
485			}
486
487			self.current = Math.min(Math.max(0, to), self.total - 1);
488
489			if(self.options.nav) {
490				self.$nav.find('[data-slide="' + self.current + '"]')._active(self.options.activeClass);
491			}
492
493			self.$slides.eq(self.current)._active(self.options.activeClass);
494
495			return self;
496		};
497
498		//  Despite the name, this doesn't do any animation - since there's
499		//  now three different types of animation, we let this method delegate
500		//  to the right type, keeping the name for backwards compat.
501		self.animate = function(to, dir) {
502			//  Animation shortcuts
503			//  Instead of passing a number index, we can now
504			//  use .data('unslider').animate('last');
505			//  or .unslider('animate:last')
506			//  to go to the very last slide
507			if(to === 'first') to = 0;
508			if(to === 'last') to = self.total;
509
510			//  Don't animate if it's not a valid index
511			if(isNaN(to)) {
512				return self;
513			}
514
515			if(self.options.autoplay) {
516				self.stop().start();
517			}
518
519			self.setIndex(to);
520
521			//  Add a callback method to do stuff with
522			self.$context.trigger(self._ + '.change', [to, self.$slides.eq(to)]);
523
524			//  Delegate the right method - everything's named consistently
525			//  so we can assume it'll be called "animate" +
526			var fn = 'animate' + $._ucfirst(self.options.animation);
527
528			//  Make sure it's a valid animation method, otherwise we'll get
529			//  a load of bug reports that'll be really hard to report
530			if($.isFunction(self[fn])) {
531				self[fn](self.current, dir);
532			}
533
534			return self;
535		};
536
537
538		//  Shortcuts for animating if we don't know what the current
539		//  index is (i.e back/forward)
540		//  For moving forward we need to make sure we don't overshoot.
541		self.next = function() {
542			var target = self.current + 1;
543
544			//  If we're at the end, we need to move back to the start
545			if(target >= self.total) {
546				if(self.options.noloop && !self.options.infinite) {
547					target = self.total - 1;
548				} else {
549					target = 0;
550				}
551			}
552
553			return self.animate(target, 'next');
554		};
555
556		//  The same as next, but the opposite :)
557		self.prev = function() {
558			var target = self.current - 1;
559
560			//  If we're at the first, we need to move forward to the end
561			if(target < 0) {
562				if(self.options.noloop && !self.options.infinite) {
563					target = 0;
564				} else {
565					target = self.total - 1;
566				}
567			}
568
569			return self.animate(target, 'prev');
570		};
571
572
573		//  Our default animation method, the old-school left-to-right
574		//  horizontal animation
575		self.animateHorizontal = function(to) {
576			var prop = 'left';
577
578			//  Add RTL support, slide the slider
579			//  the other way if the site is right-to-left
580			if(self.$context.attr('dir') === 'rtl') {
581				prop = 'right';
582			}
583
584			if(self.options.infinite) {
585				//  So then we need to hide the first slide
586				self.$container.css('margin-' + prop, '-100%');
587			}
588
589			return self.slide(prop, to);
590		};
591
592		//  The same animation methods, but vertical support
593		//  RTL doesn't affect the vertical direction so we
594		//  can just call as is
595		self.animateVertical = function(to) {
596			self.options.animateHeight = true;
597
598			//  Normal infinite CSS fix doesn't work for
599			//  vertical animation so we need to manually set it
600			//  with pixels. Ah well.
601			if(self.options.infinite) {
602				self.$container.css('margin-top', -self.$slides.outerHeight());
603			}
604
605			return self.slide('top', to);
606		};
607
608		//  Actually move the slide now
609		//  We have to pass a property to animate as there's
610		//  a few different directions it can now move, but it's
611		//  otherwise unchanged from before.
612		self.slide = function(prop, to) {
613			//  If we want to change the height of the slider
614			//  to match the current slide, you can set
615			//  {animateHeight: true}
616			self.animateHeight(to);
617
618			//  For infinite sliding we add a dummy slide at the end and start
619			//  of each slider to give the appearance of being infinite
620			if(self.options.infinite) {
621				var dummy;
622
623				//  Going backwards to last slide
624				if(to === self.total - 1) {
625					//  We're setting a dummy position and an actual one
626					//  the dummy is what the index looks like
627					//  (and what we'll silently update to afterwards),
628					//  and the actual is what makes it not go backwards
629					dummy = self.total - 3;
630					to = -1;
631				}
632
633				//  Going forwards to first slide
634				if(to === self.total - 2) {
635					dummy = 0;
636					to = self.total - 2;
637				}
638
639				//  If it's a number we can safely set it
640				if(typeof dummy === 'number') {
641					self.setIndex(dummy);
642
643					//  Listen for when the slide's finished transitioning so
644					//  we can silently move it into the right place and clear
645					//  this whole mess up.
646					self.$context.on(self._ + '.moved', function() {
647						if(self.current === dummy) {
648							self.$container.css(prop, -(100 * dummy) + '%').off(self._ + '.moved');
649						}
650					});
651				}
652			}
653
654			//  We need to create an object to store our property in
655			//  since we don't know what it'll be.
656			var obj = {};
657
658			//  Manually create it here
659			obj[prop] = -(100 * to) + '%';
660
661			//  And animate using our newly-created object
662			return self._move(self.$container, obj);
663		};
664
665
666		//  Fade between slides rather than, uh, sliding it
667        self.animateFade = function(to) {
668			//  If we want to change the height of the slider
669			//  to match the current slide, you can set
670			//  {animateHeight: true}
671			self.animateHeight(to);
672
673			var $active = self.$slides.eq(to).addClass(self.options.activeClass);
674
675			//  Toggle our classes
676			self._move($active.siblings().removeClass(self.options.activeClass), {opacity: 0});
677			self._move($active, {opacity: 1}, false);
678		};
679
680		// Animate height of slider
681		self.animateHeight = function(to) {
682			//  If we want to change the height of the slider
683			//  to match the current slide, you can set
684			//  {animateHeight: true}
685			if (self.options.animateHeight) {
686				self._move(self.$context, {height: self.$slides.eq(to).outerHeight()}, false);
687			}
688		};
689
690		self._move = function($el, obj, callback, speed) {
691			if(callback !== false) {
692				callback = function() {
693					self.$context.trigger(self._ + '.moved');
694				};
695			}
696
697			return $el._move(obj, speed || self.options.speed, self.options.easing, callback);
698		};
699
700		//  Allow daisy-chaining of methods
701		return self.init(options);
702	};
703
704	//  Internal (but global) jQuery methods
705	//  They're both just helpful types of shorthand for
706	//  anything that might take too long to write out or
707	//  something that might be used more than once.
708	$.fn._active = function(className) {
709		return this.addClass(className).siblings().removeClass(className);
710	};
711
712	//  The equivalent to PHP's ucfirst(). Take the first
713	//  character of a string and make it uppercase.
714	//  Simples.
715	$._ucfirst = function(str) {
716		//  Take our variable, run a regex on the first letter
717		return (str + '').toLowerCase().replace(/^./, function(match) {
718			//  And uppercase it. Simples.
719			return match.toUpperCase();
720		});
721	};
722
723	$.fn._move = function() {
724		this.stop(true, true);
725		return $.fn[$.fn.velocity ? 'velocity' : 'animate'].apply(this, arguments);
726	};
727
728	//  And set up our jQuery plugin
729	$.fn.unslider = function(opts) {
730		return this.each(function(index,elem) {
731			var $this = $(elem);
732            var unslider = $(elem).data('unslider');
733            if(unslider instanceof $.Unslider) {
734                return;
735            }
736			//  Allow usage of .unslider('function_name')
737			//  as well as using .data('unslider') to access the
738			//  main Unslider object
739			if(typeof opts === 'string' && $this.data('unslider')) {
740				opts = opts.split(':');
741
742				var call = $this.data('unslider')[opts[0]];
743
744				//  Do we have arguments to pass to the string-function?
745				if($.isFunction(call)) {
746					return call.apply($this, opts[1] ? opts[1].split(',') : null);
747				}
748			}
749
750			return $this.data('unslider', new $.Unslider($this, opts));
751		});
752	};
753
754}));

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.