PageSourceSearch

https://liveuptehachapi.com/Areas/NewsFlash/Assets/Scripts/Carousel.jquery.js

js liveuptehachapi.com collected 2026-09-24 22:04:40 UTC 16,562 bytes, 510 lines download raw bytes

1/*
2Terminology:
3
4min/max slide width : Defines the threshold for allowable widths of the slides. If they get too
5                      narrow or too wide, the carousel is resized.
6
7gutter width        : Defines the gap between slides at load. Can change slightly when carousel
8                      flexes in width after load.
9
10Teaser              : If there are n (where n >= 3) slides visible in a set of slides with length
11                      'count', this option:
12                      - if circular, moves slides[count] to be slides[0]
13                      - chops off the first half of slides[0] and the last half of of slides[n] by
14                        shifting the slider to the left by half a slide width
15                      - places the arrows between slides[0] & slides[count] & slides[n-1] & slides[n]
16
17Circular            : By default, the next/previous arrows are disabled if there are no more slides
18                      to navigate to. If there are more slides than can be be displayed at once, this
19                      option forces the next/previous arrows to always navigate to more slides. Also,
20                      if a set of slides does not divide evenly into n groups, this option fills
21                      the remaining slots with duplicate slides
22
23n                   : For any given width of the carousel, n is the maximum number of
24                      _whole_ slides visible.
25
26j                   : Index of the currently visible slide in slot "1"
27
28Scenario [A]        : count <= n
29                      1+ slides visible, no arrows
30                      { [1]   [2] }
31
32Scenario [B]        : count > n && ( n < 3 || !teaser )
33                      1+ slides visible, arrows
34                      { < [1]   [2] > }
35
36Scenario [C]        : count > n && n >= 3 && teaser
37                      3+ (whole) slides visible, arrows, teaser
38                      {4] < [1]   [2] > [3}
39
40*/
41
42; (function ($, window, undefined) {
43	'use strict';
44
45	var DEBUG = false;
46	var diag = function (msg) {
47		if (DEBUG && window.console) {
48			window.console.log('[ AdaptiveCarousel ] ' + msg);
49		}
50	};
51
52	// Create the defaults once
53	var pluginName = "adaptiveCarousel",
54		defaults = {
55			// Defaults
56			minSlideWidth: 180, // in px
57			maxSlideWidth: 300, // in px
58			gutterWidth: 40,  // in px
59			transitionTiming: 500, // in ms
60			easeMethod: 'easeInOutExpo', // Choose from: http://easings.net/ or http://gsgd.co.uk/sandbox/jquery/easing/
61			teaser: false, // See Terminology
62			circular: false  // See Terminology
63		};
64
65
66	// The actual plugin constructor
67	function AdaptiveCarousel(options, element) {
68		var self = this;
69
70		this.element = element;
71		this._defaults = defaults;
72		this._name = pluginName;
73		this.settings = $.extend({}, defaults, options);
74
75		this.$carousel = $(this.element);
76		this.$window = self.$carousel.find('.cpWindow');
77		this.$slider = self.$carousel.find('.cpSlider');
78		this.slides = self.$slider.find('li');
79		this.$firstSlide = self.$slider.find('li:first-child');
80		this.count = self.slides.length;
81		this.origCount = self.count;
82		this.n = 0;
83		this.j = 0;
84
85		// Label the original slides on first run
86		for (var i = 0; i < self.count; i++) {
87			$(self.slides[i]).addClass('slide' + i);
88		}
89
90		// Initialize
91		this.init();
92
93		this.$carousel.delegate('.arrow', 'click', function (e) {
94			e.preventDefault();
95			diag('Before moving, j = ' + self.j);
96			if ($(this).hasClass('prev')) {
97				self.moveBack();
98			} else if ($(this).hasClass('next')) {
99				self.moveForward();
100			}
101			diag('After moving, j = ' + self.j);
102		});
103
104		//Support swiping if framework is already loaded. Otherwise, it should take care on invoke after it is loaded (use: window.Pages.rwdReady)
105		if (typeof ($$) !== 'undefined' && self.$carousel.attr('id')) {
106			$$('#' + self.$carousel.attr('id')).on('swipeRight', function (e, a) {
107				self.adaptiveCarousel("moveBack");
108			});
109			$$('#' + self.$carousel.attr('id')).on('swipeLeft', function (e) {
110				self.adaptiveCarousel("moveForward");
111			});
112		}
113
114		// Recalculate the number of slides displayed on window resize
115		$(window).smartresize(function () {
116			self.onResize();
117		});
118	}
119
120	AdaptiveCarousel.prototype = {
121		init: function () {
122
123			// local variables
124			var self = this;
125
126			self.n = findN();
127			sizeTheSlides(whichScenario());
128
129			if (!self.settings.circular)
130				self.setArrowState();
131
132			self.initImageNextAndPrev();
133
134			// Finding the appropriate number of slides to display at one time
135			function findN() {
136				var n = 0;
137				if (self.$window.width() >= (self.settings.minSlideWidth + self.settings.gutterWidth)) {
138					var carouselWidth = self.$carousel.width();
139					n = Math.floor((carouselWidth - self.settings.gutterWidth - self.settings.minSlideWidth) / (self.settings.gutterWidth + self.settings.minSlideWidth));
140				}
141				return n > 0 ? n : 1;
142			}
143
144			// Determining which of the three scenarios (see Terminology) the carousel fits
145			function whichScenario() {
146				diag('n = ' + self.n);
147				if (self.count <= self.n) {
148					return 'A';
149				} else {
150					if (self.n < 3 || !self.settings.teaser) {
151						return 'B';
152					} else {
153						return 'C';
154					}
155				}
156			}
157
158			// The heart of the script
159			function sizeTheSlides(scenario) {
160				/* Note: This may seem like excessive if statements, but the scenarios make it more clear
161						 and many of these operation must occur in a specific order.
162				*/
163
164				var carouselWidth = self.$carousel.width();
165				var sliderWidth;
166				if (scenario === 'A') {
167					diag('Fits [A]');
168					sliderWidth = carouselWidth;
169				} else {
170					if (scenario === 'B') {
171						diag('Fits [B]');
172						// Make sure there's room for the arrow (gutterWidth) on either side of the first/last
173						// visible slides
174						var windowMargin;
175						//The value below is based on pure trial/error to fix an issue with IE in cotext to carousel display
176						//https://system.netsuite.com/app/crm/support/issuedb/issue.nl?id=3211942&l=T
177						//IE basically rounds up the math calculations to 2 decimal places causing some display issues.
178						//Adding the error correction value gives the carousel arrows enough space to display right and not overlap
179						//the images.
180						var ieErrorCorrectionValue = .0095;
181						if (/(?:\b(MS)?IE\s+|\bTrident\/7\.0;.*\s+rv:)(\d+)/.test(navigator.userAgent)) {
182							windowMargin = (((self.settings.gutterWidth / (2 * carouselWidth))) + ieErrorCorrectionValue) * 100;
183						} else {
184							windowMargin = ((self.settings.gutterWidth / (2 * carouselWidth))) * 100;
185						}
186						self.$window.css({
187							margin: '0 ' + windowMargin + '%',
188							width: (100 - windowMargin * 2) + '%'
189						});
190					}
191
192					diag('Fits [B] or [C]');
193					sliderWidth = self.$slider.width();
194				}
195
196				var margin = (self.settings.gutterWidth / sliderWidth) * 100;
197
198				if (scenario === 'B' || scenario === 'C') {
199					diag('Fits [B] or [C]');
200					if (self.settings.circular) {
201						diag('is circular');
202
203						// Make clones
204						var startClones = self.slides.slice(self.count - self.n, self.count).clone().addClass('clone'),
205							endClones = self.slides.slice(0, self.n).clone().addClass('clone');
206
207						// Attach clones
208						self.$slider.prepend(startClones);
209						self.$slider.append(endClones);
210
211						// Adjust starting position and count
212						self.j = self.n;
213						self.slides = self.$slider.find('li');
214						self.count = self.slides.length;
215					}
216
217					// Adjust margin to be relative to n/count
218					margin = margin * (self.n / self.count);
219
220					// Adjust slider to hold slides in a row
221					self.$slider.width(self.count * (100 / self.n) + '%');
222					sliderWidth = self.$slider.width();
223
224					/* Couldn't quite figure this out
225					if ( Modernizr.csstransitions ) {
226						self.$window.before('<style>.js .animated .cpSlider { -webkit-transition-duration: ' + self.settings.transitionTiming + 'ms; transition-duration: ' + self.settings.transitionTiming + 'ms; }</style>');
227						self.$carousel.addClass('animated');
228					}
229					*/
230					self.$window.after('<a href="#" class="arrow next"><span class="visuallyHidden">Next</span></a><a href="#" class="arrow prev"><span class="visuallyHidden">Previous</span></a>');
231				}
232
233				if (scenario === 'A' || scenario === 'B') {
234
235					diag('Fits [A] or [B]');
236
237					var slideWidth = (100 - self.count * margin) / self.count;
238					self.slides.outerWidth(slideWidth + '%');
239
240					var firstSlideWidth = self.$firstSlide.outerWidth();
241
242					if (firstSlideWidth > self.settings.maxSlideWidth || firstSlideWidth < self.settings.minSlideWidth) {
243						if (firstSlideWidth > self.settings.maxSlideWidth) {
244							diag('Slides too wide');
245							slideWidth = (self.settings.maxSlideWidth / sliderWidth) * 100;
246						} else {
247							diag('Slides too narrow');
248							//Only enforce minimum width if margins wouldn't become negative
249							//Formula is PossibleNewMargin = (100 - self.count * PossibleNewSlideWidth) / self.count
250							if (((100 - self.count * ((self.settings.minSlideWidth / sliderWidth) * 100)) / self.count) > 0) {
251								slideWidth = (self.settings.minSlideWidth / sliderWidth) * 100;
252							}
253						}
254						self.slides.outerWidth(slideWidth + '%');
255						margin = (100 - self.count * slideWidth) / self.count;
256					}
257
258					if (scenario === 'B') {
259						diag('Fits [B]');
260						self.moveTheSlides('dir', 0);
261						self.$carousel.find('.arrow').width((self.settings.gutterWidth / carouselWidth) * 100 + '%');
262					}
263
264				} else {
265					diag('Fits [C]');
266					self.slides.outerWidth((100 - self.count * margin) / self.count + '%');
267					self.$carousel.addClass('teaser');
268					self.moveTheSlides('dir', 0);
269					self.$carousel.find('.arrow').width(((self.$firstSlide.outerWidth() / 2 + self.settings.gutterWidth / 2) / carouselWidth) * 100 + '%');
270				}
271
272				self.slides.css('margin', '0 ' + margin / 2 + '%');
273			}
274		},
275		moveTheSlides: function (dir, speed) {
276
277			var self = this,
278				m = self.n,
279				offset = 0;
280			if (self.$carousel.hasClass('teaser')) {
281				m--;
282				offset = 0.5;
283			}
284
285			if (dir === 'back') {
286				self.j = self.j - m;
287				if (!self.settings.circular && self.j < 0) {
288					self.j = 0;
289				}
290			} else if (dir === 'forward') {
291				self.j = self.j + m;
292				if (!self.settings.circular && self.j > (self.count - m)) {
293					self.j = self.count - m;
294				}
295			}
296
297			var left = (-self.j + offset) * (100 / self.n);
298
299			/* Couldn't quite figure this out
300			if ( !Modernizr.csstransitions ) {
301			*/
302
303			self.$slider.animate({
304				left: left + '%',
305			}, speed, self.settings.easeMethod);
306			/* Couldn't quite figure this out
307		} else {
308
309			if ( speed === 0 ) {
310				self.$carousel.removeClass('animated');
311			}
312				self.$slider.css('left', left + '%');
313				if ( speed === 0 ) {
314					setTimeout( function() { self.$carousel.addClass('animated') }, self.settings.transitionTiming );
315				}
316		}
317		*/
318
319			if (dir === 'forward' || dir === 'back') {
320				if (self.settings.circular) {
321
322					// Checking to see if we're past the beginning or end of a circular carousel
323					if ((self.j < self.n) || (self.j > self.origCount)) {
324
325						if (self.j < self.n) {
326							diag("We're past the beginning");
327							self.j = self.j + self.origCount;
328						} else {
329							diag("We're past the end");
330							self.j = self.j - self.origCount;
331						}
332
333						// Switch to non-cloned position, instantly, after a delay equal to transition time
334						setTimeout(self.moveTheSlides('dir', 0), self.settings.transitionTiming);
335					}
336				} else {
337					diag('Set arrow state after movement');
338					self.setArrowState();
339				}
340			}
341
342			self.initImageNextAndPrev();
343
344			return self.j;
345
346		},
347		// Sometimes the arrows need to enabled/disabled
348		setArrowState: function () {
349			var self = this;
350			self.$carousel.find('.arrow').removeClass('disabled');
351			if (self.j === 0) {
352				self.$carousel.find('.arrow.prev').addClass('disabled');
353			} else if (self.j >= (self.count - self.n)) {
354				self.$carousel.find('.arrow.next').addClass('disabled');
355			}
356		},
357		onResize: function () {
358			var self = this;
359			if (self.$firstSlide.outerWidth() < self.settings.minSlideWidth || self.$firstSlide.outerWidth() >= self.settings.maxSlideWidth) {
360				diag('Resize!');
361
362				// Resetting things back to a fresh, known state for calculations
363				self.$window.css({
364					margin: '0',
365					width: '100%'
366				});
367				self.$slider.css({
368					left: '0',
369					width: '100%'
370				});
371
372				self.$carousel.removeClass('teaser');
373				self.$carousel.find('.clone').remove();
374				self.$carousel.find('.arrow').remove();
375				self.slides = self.$slider.find('li');
376				self.count = self.origCount;
377
378				// Re-initialize
379				self.init();
380			}
381		},
382		moveForward: function () {
383			var self = this;
384			if (self.$carousel.find('a.arrow.next').length == 1)
385				self.moveTheSlides('forward', self.settings.transitionTiming);
386		},
387		moveBack: function () {
388			var self = this;
389			if (self.$carousel.find('a.arrow.prev').length == 1)
390				self.moveTheSlides('back', self.settings.transitionTiming);
391		},
392		initImageNextAndPrev: function () {
393			var self = this;
394
395			var loadImage = function (widgetItem) {
396				var image = $(widgetItem).find('img');
397
398				if (image.length !== 0) {
399					var $this = $(image),
400						delayLoadUrl = $this.attr('data-delay-load'),
401						imgSrc = $this.attr('src');
402
403					if (delayLoadUrl !== imgSrc) {
404						if (delayLoadUrl !== undefined && delayLoadUrl !== '' && delayLoadUrl !== null) {
405							var imageUrl = document.createElement('a');
406							imageUrl.href = delayLoadUrl;
407
408							if (imageUrl.protocol === 'http:' || imageUrl.protocol === 'https:') {
409								for (var imageIndex = 0; imageIndex < image.length; imageIndex++) {
410									image[imageIndex].src = imageUrl.href;
411								}
412								$this.removeAttr('data-delay-load');
413							}
414						}
415					}
416				}
417			};
418
419			if ($("img[data-delay-load]", self.element).length > 0) {
420				var $widgetItems = $("li.widgetItem", self.element);
421
422				for (var i = 0; i <= self.n; i++) {
423					var forward = self.j + i;
424
425					if (forward > $widgetItems.length) {
426						var diff = forward - $widgetItems.length;
427						loadImage($widgetItems[diff]);
428					}
429					else {
430						loadImage($widgetItems[forward]);
431					}
432
433					if (self.settings.circular) {
434						var backward = self.j - i;
435
436						if (backward < 0) {
437							var diff = $widgetItems.length + backward;
438							loadImage($widgetItems[diff]);
439						}
440						else {
441							loadImage($widgetItems[backward]);
442						}
443					}
444				}
445			}
446		}
447	};
448
449	/* jQuery Plugin Support */
450	$.fn.adaptiveCarousel = function (options) {
451		if (typeof options === 'string') {
452			var args = Array.prototype.slice.call(arguments, 1);
453			this.each(function () {
454				var instance = $.data(this, 'adaptiveCarousel');
455				if (!instance) {
456					diag("cannot call methods on adaptiveCarousel prior to initialization; " +
457						"attempted to call method '" + options + "'");
458					return;
459				}
460				if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
461					diag("no such method '" + options + "' for adaptiveCarousel instance");
462					return;
463				}
464				instance[options].apply(instance, args);
465			});
466		}
467		else {
468			this.each(function () {
469				var instance = $.data(this, 'adaptiveCarousel');
470				if (instance) {
471					instance.init(options);
472				}
473				else {
474					instance = $.data(this, 'adaptiveCarousel', new AdaptiveCarousel(options, this));
475				}
476			});
477		}
478
479		return this;
480	};
481
482})(jQuery, window);
483
484(function ($, sr) {
485
486	// debouncing function from John Hann
487	// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
488	var debounce = function (func, threshold, execAsap) {
489		var timeout;
490
491		return function debounced() {
492			var obj = this, args = arguments;
493			function delayed() {
494				if (!execAsap)
495					func.apply(obj, args);
496				timeout = null;
497			};
498
499			if (timeout)
500				clearTimeout(timeout);
501			else if (execAsap)
502				func.apply(obj, args);
503
504			timeout = setTimeout(delayed, threshold || 100);
505		};
506	};
507	// smartresize
508	jQuery.fn[sr] = function (fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
509
510})(jQuery, 'smartresize');

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.