PageSourceSearch

https://www.uhr-werk.at/wp-content/plugins/the-grid/frontend/assets/js/the-grid-slider.js

js uhr-werk.at collected 2026-10-05 22:16:09 UTC 56,406 bytes, 2,015 lines download raw bytes

1/*! 
2 * The Grid Slider v1.0.0
3 * Copyright © 2015 All Rights Reserved. 
4 * @author Themeone [http://theme-one.com/the-grid/]
5 */
6 
7/*jslint bitwise: true */
8
9;(function ($, w, undefined) {
10	'use strict';
11
12	var pluginName = 'TG_Slider',
13		className  = 'TG_Slider',
14		namespace  = pluginName,
15		// Local WindowAnimationTiming interface
16		cAF = w.cancelAnimationFrame || w.cancelRequestAnimationFrame,
17		rAF = w.requestAnimationFrame,
18		// Support indicators
19		transform, gpuAcceleration,
20		// Other global values
21		$doc = $(document),
22		dragInitEvents = 'touchstart.' + namespace + ' mousedown.' + namespace,
23		dragMouseEvents = 'mousemove.' + namespace + ' mouseup.' + namespace,
24		dragTouchEvents = 'touchmove.' + namespace + ' touchend.' + namespace,
25		wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel.' : 'mousewheel.') + namespace,
26		clickEvent = 'click.' + namespace,
27		mouseDownEvent = 'mousedown.' + namespace,
28		interactiveElements = ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'],
29		tmpArray = [],
30		time,
31		// Math shorthands
32		abs   = Math.abs,
33		sqrt  = Math.sqrt,
34		pow   = Math.pow,
35		round = Math.round,
36		max   = Math.max,
37		min   = Math.min;
38
39	// Keep track of last fired global wheel event
40	var lastGlobalWheel = 0;
41	$doc.on(wheelEvent, function (event) {
42		var TG_Slider = event.originalEvent[namespace];
43		var time = +new Date();
44		// Update last global wheel time, but only when event didn't originate
45		// in TG_Slider frame, or the origin was less than scrollHijack time ago
46		if (!TG_Slider || TG_Slider.options.scrollHijack < time - lastGlobalWheel) lastGlobalWheel = time;
47	});
48
49	/**
50	 * TG_Slider.
51	 *
52	 * @class
53	 *
54	 * @param {Element} frame       DOM element of TG_Slider container.
55	 * @param {Object}  options     Object with options.
56	 * @param {Object}  callbackMap Callbacks map.
57	 */
58	function TG_Slider(frame, options, callbackMap) {
59		// Extend options
60		var o = $.extend({}, TG_Slider.defaults, options),
61			// Private variables
62			self = this,
63			parallax = isNumber(frame),
64			// Frame
65			$frame = $(frame),
66			$slidee = o.slidee ? $(o.slidee).eq(0) : $frame.children().eq(0),
67			frameSize = 0,
68			slideeSize = 0,
69			pos = {
70				start: 0,
71				center: 0,
72				end: 0,
73				cur: 0,
74				dest: 0
75			},
76			// Scrollbar
77			$sb = $(o.scrollBar).eq(0),
78			$handle = $sb.children().eq(0),
79			sbSize = 0,
80			handleSize = 0,
81			hPos = {
82				start: 0,
83				end: 0,
84				cur: 0
85			},
86			// Pagesbar
87			$pb = $(o.pagesBar),
88			$pages = 0,
89			pages = [],
90			// Items
91			$items = 0,
92			items = [],
93			rel = {
94				firstItem: 0,
95				lastItem: 0,
96				centerItem: 0,
97				activeItem: null,
98				activePage: 0
99			},
100			// Styles
101			frameStyles = new StyleRestorer($frame[0]),
102			slideeStyles = new StyleRestorer($slidee[0]),
103			sbStyles = new StyleRestorer($sb[0]),
104			handleStyles = new StyleRestorer($handle[0]),
105			// Navigation type booleans
106			basicNav = o.itemNav === 'basic',
107			forceCenteredNav = o.itemNav === 'forceCentered',
108			centeredNav = o.itemNav === 'centered' || forceCenteredNav,
109			itemNav = !parallax && (basicNav || centeredNav || forceCenteredNav),
110			// Miscellaneous
111			$scrollSource = o.scrollSource ? $(o.scrollSource) : $frame,
112			$dragSource = o.dragSource ? $(o.dragSource) : $frame,
113			$forwardButton = $(o.forward),
114			$backwardButton = $(o.backward),
115			$prevButton = $(o.prev),
116			$nextButton = $(o.next),
117			$prevPageButton = $(o.prevPage),
118			$nextPageButton = $(o.nextPage),
119			callbacks = {},
120			last = {},
121			animation = {},
122			move = {},
123			dragging = {
124				released: 1
125			},
126			scrolling = {
127				last: 0,
128				delta: 0,
129				resetTime: 200
130			},
131			renderID = 0,
132			historyID = 0,
133			cycleID = 0,
134			continuousID = 0,
135			i, l;
136
137		// Normalizing frame
138		if (!parallax) {
139			frame = $frame[0];
140		}
141
142		// Expose properties
143		self.initialized = 0;
144		self.frame = frame;
145		self.slidee = $slidee[0];
146		self.pos = pos;
147		self.rel = rel;
148		self.items = items;
149		self.pages = pages;
150		self.isPaused = 0;
151		self.options = o;
152		self.dragging = dragging;
153
154		/**
155		 * Loading function.
156		 *
157		 * Populate arrays, set sizes, bind events, ...
158		 *
159		 * @param {Boolean} [isInit] Whether load is called from within self.init().
160		 * @return {Void}
161		 */
162		function load(isInit) {
163			
164			// Local variables
165			var lastItemsCount = 0,
166				lastPagesCount = pages.length,
167				data = $slidee.data('TG_Layout'),
168				itemGutter = (data) ? data.options[data.options.layoutMode].gutter.offsetWidth : 0;
169
170			// for backend
171			if (!data) { return false; }
172			
173			// Reset global variables
174			frameSize = $frame.width();
175			sbSize = $sb.width();
176			slideeSize = $slidee.outerWidth();
177			pages.length = 0;			
178			// Set position limits & relatives
179			pos.start = 0;
180			pos.end = max(slideeSize - frameSize, 0);
181
182			// Sizes & offsets for item based navigations
183			if (itemNav) {
184				
185				// Save the number of current items
186				lastItemsCount = items.length;
187
188				// Reset itemNav related variables
189				$items = $slidee.children(o.itemSelector);
190				items.length = 0;
191
192				// Needed variables
193				var paddingStart = getPx($slidee, o.horizontal ? 'paddingLeft' : 'paddingTop'),
194					paddingEnd = getPx($slidee, o.horizontal ? 'paddingRight' : 'paddingBottom'),
195					borderBox = $($items).css('boxSizing') === 'border-box',
196					filteredItems = data.filteredItems,
197					ignoredMargin = 0,
198					lastItemIndex = 0,
199					lastItem,
200					max_width = 0,
201					pos_items = [],
202					new_pos_item = [];
203				
204				for (var i = 0; i < filteredItems.length; i++) {
205					var width = parseFloat(getComputedStyle(filteredItems[i].element).width)+itemGutter,
206						pos_x = filteredItems[i].position.x;
207					max_width = (pos_x+width > max_width) ? pos_x+width : max_width;
208					pos_items.push(pos_x);
209				}
210				pos_items.push(max_width);
211				pos_items.sort(function(a,b){return a - b;});
212				for (var i = 1; i < pos_items.length; i++) {
213					new_pos_item.push(pos_items[i]-pos_items[i-1]);
214				}
215
216				// Reset slideeSize
217				slideeSize = 0;
218
219				// Iterate through filtered items
220				$(filteredItems).each(function (i, element) {
221					
222					// set item with and margin (gutter)
223					var itemMarginStart = itemGutter/2,
224						itemMarginEnd = itemGutter/2;
225					var item = {};
226					item.el = element;
227					item.size = new_pos_item[i];
228					item.half = item.size / 2;
229					item.start = slideeSize - itemMarginStart;
230					item.center = item.start - round(frameSize / 2 - item.size / 2);
231					item.end = item.start - frameSize + item.size;
232					
233					// Account for slidee padding
234					if (!i) {
235						slideeSize += paddingStart;
236					}
237					// Increment slidee size for size of the active element
238					slideeSize += item.size;
239
240					// Try to account for vertical margin collapsing in vertical mode
241					if (!o.horizontal) {
242						// Subtract smaller margin, but only when top margin is not 0, and this is not the first element
243						if (itemMarginEnd && itemMarginStart && i > 0) {
244							slideeSize -= min(itemMarginStart, itemMarginEnd);
245						}
246					}
247
248					// Things to be done on last item
249					if (i === lastItemIndex) {
250						item.end += paddingEnd;
251						slideeSize += paddingEnd;
252						ignoredMargin = itemMarginEnd;
253					}
254
255					// Add item object to items array
256					if (item.size) {
257						items.push(item);
258						lastItem = item;
259					}
260					
261				});
262
263				// Resize SLIDEE to fit all items
264				$slidee[0].style[o.horizontal ? 'width' : 'height'] = (borderBox ? slideeSize: slideeSize - paddingStart - paddingEnd) + 'px';				
265
266				// Adjust internal SLIDEE size for last margin
267				slideeSize -= ignoredMargin;
268
269				// Set limits
270				if (items.length) {
271					pos.start =  items[0][forceCenteredNav ? 'center' : 'start'];
272					pos.end = forceCenteredNav ? lastItem.center : frameSize < slideeSize ? lastItem.end : pos.start;
273				} else {
274					pos.start = pos.end = 0;
275				}
276			}
277			
278			// Calculate SLIDEE center position
279			pos.center = round(pos.end / 2 + pos.start / 2);
280
281			// Update relative positions
282			updateRelatives();
283
284			// Pages
285			if (!parallax && frameSize > 0) {
286				var tempPagePos = pos.start;
287				var pagesHtml = '';
288
289				// Populate pages array
290				if (itemNav) {
291					$.each(items, function (i, item) {						
292						if (forceCenteredNav) {
293							pages.push(item.center);
294						} else if (item.start + item.size > tempPagePos && tempPagePos <= pos.end) {
295							tempPagePos = item.start;
296							pages.push(item.size < frameSize && data.options.layoutMode === 'justified' ? item.start+(item.size-frameSize)/2 : item.start);
297							tempPagePos += frameSize;
298							if (tempPagePos > pos.end && tempPagePos < pos.end + frameSize) {
299								pages.push(pos.end);
300							}
301						}
302					});
303				} else {
304					while (tempPagePos - frameSize < pos.end) {
305						pages.push(tempPagePos);
306						tempPagePos += frameSize;
307					}
308				}
309
310				// Pages bar
311				if ($pb[0] && lastPagesCount !== pages.length) {
312					for (var i = 0; i < pages.length; i++) {
313						pagesHtml += o.pageBuilder.call(self, i);
314					}
315					if (pages.length === 1) {
316						pagesHtml = null;
317					}
318					$pages = $pb.html(pagesHtml).children();
319					$pages.eq(rel.activePage).addClass(o.activeClass);
320					
321				}
322			}
323
324			// Extend relative variables object with some useful info
325			rel.slideeSize = slideeSize;
326			rel.frameSize = frameSize;
327			rel.sbSize = sbSize;
328			rel.handleSize = handleSize;
329
330			// Activate requested position
331			if (itemNav) {
332				if (isInit && o.startAt != null) {
333					//activate(o.startAt);
334					self[centeredNav ? 'toCenter' : 'toStart'](o.startAt);
335				}
336				// Fix possible overflowing
337				var activeItem = items[rel.activeItem];
338				slideTo(centeredNav && activeItem ? activeItem.center : within(pos.dest, pos.start, pos.end));
339			} else {
340				if (isInit) {
341					if (o.startAt != null) slideTo(o.startAt, 1);
342				} else {
343					// Fix possible overflowing
344					slideTo(within(pos.dest, pos.start, pos.end));
345				}
346			}
347
348			// Trigger load event
349			trigger('load');
350		}
351		self.reload = function () { load(); };
352
353		/**
354		 * Animate to a position.
355		 *
356		 * @param {Int}  newPos    New position.
357		 * @param {Bool} immediate Reposition immediately without an animation.
358		 * @param {Bool} dontAlign Do not align items, use the raw position passed in first argument.
359		 *
360		 * @return {Void}
361		 */
362		function slideTo(newPos, immediate, dontAlign) {
363			// Align items
364			if (itemNav && dragging.released && !dontAlign) {
365				var tempRel = getRelatives(newPos);
366				var isNotBordering = newPos > pos.start && newPos < pos.end;
367
368				if (centeredNav) {
369					if (isNotBordering) {
370						newPos = items[tempRel.centerItem].center;
371					}
372					if (forceCenteredNav && o.activateMiddle) {
373						activate(tempRel.centerItem);
374					}
375				} else if (isNotBordering) {
376					newPos = items[tempRel.firstItem].start;
377				}
378			}
379
380			// Handle overflowing position limits
381			if (dragging.init && dragging.slidee && o.elasticBounds) {
382				if (newPos > pos.end) {
383					newPos = pos.end + (newPos - pos.end) / 6;
384				} else if (newPos < pos.start) {
385					newPos = pos.start + (newPos - pos.start) / 6;
386				}
387			} else {
388				newPos = within(newPos, pos.start, pos.end);
389			}
390
391			// Update the animation object
392			animation.start = +new Date();
393			animation.time = 0;
394			animation.from = pos.cur;
395			animation.to = newPos;
396			animation.delta = newPos - pos.cur;
397			animation.tweesing = dragging.tweese || dragging.init && !dragging.slidee;
398			animation.immediate = !animation.tweesing && (immediate || dragging.init && dragging.slidee || !o.speed);
399
400			// Reset dragging tweesing request
401			dragging.tweese = 0;
402
403			// Start animation rendering
404			if (newPos !== pos.dest) {
405				pos.dest = newPos;
406				trigger('change');
407				if (!renderID) {
408					render();
409				}
410			}
411
412			// Reset next cycle timeout
413			resetCycle();
414
415			// Synchronize states
416			updateRelatives();
417			updateButtonsState();
418			syncPagesbar();
419		}
420
421		/**
422		 * Render animation frame.
423		 *
424		 * @return {Void}
425		 */
426		function render() {
427			
428			if (!self.initialized) {
429				return;
430			}
431
432			// If first render call, wait for next animationFrame
433			if (!renderID) {
434				renderID = rAF(render);
435				if (dragging.released) {
436					trigger('moveStart');
437				}
438				return;
439			}
440
441			// If immediate repositioning is requested, don't animate.
442			if (animation.immediate) {
443				pos.cur = animation.to;
444			}
445			// Use tweesing for animations without known end point
446			else if (animation.tweesing) {
447				animation.tweeseDelta = animation.to - pos.cur;
448				// Fuck Zeno's paradox
449				if (abs(animation.tweeseDelta) < 0.1) {
450					pos.cur = animation.to;
451				} else {
452					pos.cur += animation.tweeseDelta * (dragging.released ? o.swingSpeed : o.syncSpeed);
453				}
454			}
455			// Use tweening for basic animations with known end point
456			else {
457				animation.time = min(+new Date() - animation.start, o.speed);
458				pos.cur = animation.from + animation.delta * $.easing[o.easing](animation.time/o.speed, animation.time, 0, 1, o.speed);
459			}
460
461			// If there is nothing more to render break the rendering loop, otherwise request new animation frame.
462			if (animation.to === pos.cur) {
463				pos.cur = animation.to;
464				dragging.tweese = renderID = 0;
465			} else {
466				renderID = rAF(render);
467			}
468
469			trigger('move');
470
471			// Update SLIDEE position
472			if (!parallax) {
473				if (transform) {
474					$slidee[0].style[transform] = gpuAcceleration + (o.horizontal ? 'translateX' : 'translateY') + '(' + (-pos.cur) + 'px)';
475				} else {
476					$slidee[0].style[o.horizontal ? 'left' : 'top'] = -round(pos.cur) + 'px';
477				}
478			}
479
480			// When animation reached the end, and dragging is not active, trigger moveEnd
481			if (!renderID && dragging.released) {
482				trigger('moveEnd');
483			}
484
485		}
486
487		/**
488		 * Synchronizes pagesbar with SLIDEE.
489		 *
490		 * @return {Void}
491		 */
492		function syncPagesbar() {
493			if ($pages[0] && last.page !== rel.activePage) {
494				last.page = rel.activePage;
495				$pages.removeClass(o.activeClass).eq(rel.activePage).addClass(o.activeClass);
496				trigger('activePage', last.page);
497			}
498		}
499
500		/**
501		 * Returns the position object.
502		 *
503		 * @param {Mixed} item
504		 *
505		 * @return {Object}
506		 */
507		self.getPos = function (item) {
508			if (itemNav) {
509				var index = getIndex(item);
510				return index !== -1 ? items[index] : false;
511			} else {
512				var $item = $slidee.find(item).eq(0);
513
514				if ($item[0]) {
515					var offset = o.horizontal ? $item.offset().left - $slidee.offset().left : $item.offset().top - $slidee.offset().top;
516					var size = $item[o.horizontal ? 'outerWidth' : 'outerHeight']();
517
518					return {
519						start: offset,
520						center: offset - frameSize / 2 + size / 2,
521						end: offset - frameSize + size,
522						size: size
523					};
524				} else {
525					return false;
526				}
527			}
528		};
529
530		/**
531		 * Continuous move in a specified direction.
532		 *
533		 * @param  {Bool} forward True for forward movement, otherwise it'll go backwards.
534		 * @param  {Int}  speed   Movement speed in pixels per frame. Overrides options.moveBy value.
535		 *
536		 * @return {Void}
537		 */
538		self.moveBy = function (speed) {
539			move.speed = speed;
540			// If already initiated, or there is nowhere to move, abort
541			if (dragging.init || !move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) {
542				return;
543			}
544			// Initiate move object
545			move.lastTime = +new Date();
546			move.startPos = pos.cur;
547			// Set dragging as initiated
548			continuousInit('button');
549			dragging.init = 1;
550			// Start movement
551			trigger('moveStart');
552			cAF(continuousID);
553			moveLoop();
554		};
555
556		/**
557		 * Continuous movement loop.
558		 *
559		 * @return {Void}
560		 */
561		function moveLoop() {
562			// If there is nowhere to move anymore, stop
563			if (!move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) {
564				self.stop();
565			}
566			// Request new move loop if it hasn't been stopped
567			continuousID = dragging.init ? rAF(moveLoop) : 0;
568			// Update move object
569			move.now = +new Date();
570			move.pos = pos.cur + (move.now - move.lastTime) / 1000 * move.speed;
571			// Slide
572			slideTo(dragging.init ? move.pos : round(move.pos));
573			// Normally, this is triggered in render(), but if there
574			// is nothing to render, we have to do it manually here.
575			if (!dragging.init && pos.cur === pos.dest) {
576				trigger('moveEnd');
577			}
578			// Update times for future iteration
579			move.lastTime = move.now;
580		}
581
582		/**
583		 * Stops continuous movement.
584		 *
585		 * @return {Void}
586		 */
587		self.stop = function () {
588			if (dragging.source === 'button') {
589				dragging.init = 0;
590				dragging.released = 1;
591			}
592		};
593
594		/**
595		 * Activate previous item.
596		 *
597		 * @return {Void}
598		 */
599		self.prev = function () {
600			self.activate(rel.activeItem == null ? 0 : rel.activeItem - 1);
601		};
602
603		/**
604		 * Activate next item.
605		 *
606		 * @return {Void}
607		 */
608		self.next = function () {
609			self.activate(rel.activeItem == null ? 0 : rel.activeItem + 1);
610		};
611
612		/**
613		 * Activate previous page.
614		 *
615		 * @return {Void}
616		 */
617		self.prevPage = function () {
618			self.activatePage(rel.activePage - 1);
619		};
620
621		/**
622		 * Activate next page.
623		 *
624		 * @return {Void}
625		 */
626		self.nextPage = function () {
627			self.activatePage(rel.activePage + 1);
628		};
629
630		/**
631		 * Slide SLIDEE by amount of pixels.
632		 *
633		 * @param {Int}  delta     Pixels/Items. Positive means forward, negative means backward.
634		 * @param {Bool} immediate Reposition immediately without an animation.
635		 *
636		 * @return {Void}
637		 */
638		self.slideBy = function (delta, immediate) {
639			if (!delta) {
640				return;
641			}
642			if (itemNav) {
643				self[centeredNav ? 'toCenter' : 'toStart'](
644					within((centeredNav ? rel.centerItem : rel.firstItem) + o.scrollBy * delta, 0, items.length)
645				);
646			} else {
647				slideTo(pos.dest + delta, immediate);
648			}
649		};
650
651		/**
652		 * Animate SLIDEE to a specific position.
653		 *
654		 * @param {Int}  pos       New position.
655		 * @param {Bool} immediate Reposition immediately without an animation.
656		 *
657		 * @return {Void}
658		 */
659		self.slideTo = function (pos, immediate) {
660			slideTo(pos, immediate);
661		};
662
663		/**
664		 * Core method for handling `toLocation` methods.
665		 *
666		 * @param  {String} location
667		 * @param  {Mixed}  item
668		 * @param  {Bool}   immediate
669		 *
670		 * @return {Void}
671		 */
672		function to(location, item, immediate) {
673			// Optional arguments logic
674			if (type(item) === 'boolean') {
675				immediate = item;
676				item = undefined;
677			}
678
679			if (item === undefined) {
680				slideTo(pos[location], immediate);
681			} else {
682				// You can't align items to sides of the frame
683				// when centered navigation type is enabled
684				if (centeredNav && location !== 'center') {
685					return;
686				}
687
688				var itemPos = self.getPos(item);
689				if (itemPos) {
690					slideTo(itemPos[location], immediate, !centeredNav);
691				}
692			}
693		}
694
695		/**
696		 * Animate element or the whole SLIDEE to the start of the frame.
697		 *
698		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
699		 * @param {Bool}  immediate Reposition immediately without an animation.
700		 *
701		 * @return {Void}
702		 */
703		self.toStart = function (item, immediate) {
704			to('start', item, immediate);
705		};
706
707		/**
708		 * Animate element or the whole SLIDEE to the end of the frame.
709		 *
710		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
711		 * @param {Bool}  immediate Reposition immediately without an animation.
712		 *
713		 * @return {Void}
714		 */
715		self.toEnd = function (item, immediate) {
716			to('end', item, immediate);
717		};
718
719		/**
720		 * Animate element or the whole SLIDEE to the center of the frame.
721		 *
722		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
723		 * @param {Bool}  immediate Reposition immediately without an animation.
724		 *
725		 * @return {Void}
726		 */
727		self.toCenter = function (item, immediate) {
728			to('center', item, immediate);
729		};
730
731		/**
732		 * Get the index of an item in SLIDEE.
733		 *
734		 * @param {Mixed} item     Item DOM element.
735		 *
736		 * @return {Int}  Item index, or -1 if not found.
737		 */
738
739		function getIndex(item) {
740			return item != null ?
741					isNumber(item) ?
742						item >= 0 && item < items.length ? item : -1 :
743						$items.index(item) :
744					-1;
745		}
746		// Expose getIndex without lowering the compressibility of it,
747		// as it is used quite often throughout TG_Slider.
748		self.getIndex = getIndex;
749
750		/**
751		 * Get index of an item in SLIDEE based on a variety of input types.
752		 *
753		 * @param  {Mixed} item DOM element, positive or negative integer.
754		 *
755		 * @return {Int}   Item index, or -1 if not found.
756		 */
757		function getRelativeIndex(item) {
758			return getIndex(isNumber(item) && item < 0 ? item + items.length : item);
759		}
760
761		/**
762		 * Activates an item.
763		 *
764		 * @param  {Mixed} item Item DOM element, or index starting at 0.
765		 *
766		 * @return {Mixed} Activated item index or false on fail.
767		 */
768		/*function activate(item, force) {
769			var index = getIndex(item);
770
771			if (!itemNav || index < 0) {
772				return false;
773			}
774			
775			// Update classes, last active index, and trigger active event only when there
776			// has been a change. Otherwise just return the current active index.
777			if (last.active !== index || force) {
778				// Update classes
779				$items.eq(rel.activeItem).removeClass(o.activeClass);
780				$items.eq(index).addClass(o.activeClass);
781				last.active = rel.activeItem = index;
782
783				updateButtonsState();
784				trigger('active', index);
785			}
786
787			return index;
788		}*/
789
790		/**
791		 * Activates an item and helps with further navigation when o.smart is enabled.
792		 *
793		 * @param {Mixed} item      Item DOM element, or index starting at 0.
794		 * @param {Bool}  immediate Whether to reposition immediately in smart navigation.
795		 *
796		 * @return {Void}
797		 */
798		/*self.activate = function (item, immediate) {
799			var index = activate(item);
800
801			// Smart navigation
802			if (o.smart && index !== false) {
803				// When centeredNav is enabled, center the element.
804				// Otherwise, determine where to position the element based on its current position.
805				// If the element is currently on the far end side of the frame, assume that user is
806				// moving forward and animate it to the start of the visible frame, and vice versa.
807				if (centeredNav) {
808					self.toCenter(index, immediate);
809				} else if (index >= rel.lastItem) {
810					self.toStart(index, immediate);
811				} else if (index <= rel.firstItem) {
812					self.toEnd(index, immediate);
813				} else {
814					resetCycle();
815				}
816			}
817		};*/
818
819		/**
820		 * Activates a page.
821		 *
822		 * @param {Int}  index     Page index, starting from 0.
823		 * @param {Bool} immediate Whether to reposition immediately without animation.
824		 *
825		 * @return {Void}
826		 */
827		self.activatePage = function (index, immediate) {
828			if (isNumber(index)) {
829				slideTo(pages[within(index, 0, pages.length - 1)], immediate);
830			}
831		};
832
833		/**
834		 * Return relative positions of items based on their visibility within FRAME.
835		 *
836		 * @param {Int} slideePos Position of SLIDEE.
837		 *
838		 * @return {Void}
839		 */
840		function getRelatives(slideePos) {
841			slideePos = within(isNumber(slideePos) ? slideePos : pos.dest, pos.start, pos.end);
842
843			var relatives = {};
844			var centerOffset = forceCenteredNav ? 0 : frameSize / 2;
845
846			// Determine active page
847			if (!parallax) {
848				for (var p = 0, pl = pages.length; p < pl; p++) {
849					if (slideePos >= pos.end || p === pages.length - 1) {
850						relatives.activePage = pages.length - 1;
851						break;
852					}
853
854					if (slideePos <= pages[p] + centerOffset) {
855						relatives.activePage = p;
856						break;
857					}
858				}
859			}
860
861			// Relative item indexes
862			if (itemNav) {
863				var first = false;
864				var last = false;
865				var center = false;
866
867				// From start
868				for (var i = 0, il = items.length; i < il; i++) {
869					// First item
870					if (first === false && slideePos <= items[i].start + items[i].half) {
871						first = i;
872					}
873
874					// Center item
875					if (center === false && slideePos <= items[i].center + items[i].half) {
876						center = i;
877					}
878
879
880					// Last item
881					if (i === il - 1 || slideePos <= items[i].end + items[i].half) {
882						last = i;
883						break;
884					}
885				}
886
887				// Safe assignment, just to be sure the false won't be returned
888				relatives.firstItem = isNumber(first) ? first : 0;
889				relatives.centerItem = isNumber(center) ? center : relatives.firstItem;
890				relatives.lastItem = isNumber(last) ? last : relatives.centerItem;
891			}
892
893			return relatives;
894		}
895
896		/**
897		 * Update object with relative positions.
898		 *
899		 * @param {Int} newPos
900		 *
901		 * @return {Void}
902		 */
903		function updateRelatives(newPos) {
904			$.extend(rel, getRelatives(newPos));
905		}
906
907		/**
908		 * Disable navigation buttons when needed.
909		 *
910		 * Adds disabledClass, and when the button is <button> or <input>, activates :disabled state.
911		 *
912		 * @return {Void}
913		 */
914		function updateButtonsState() {
915			var isStart = pos.dest <= pos.start;
916			var isEnd = pos.dest >= pos.end;
917			var slideePosState = (isStart ? 1 : 0) | (isEnd ? 2 : 0);
918
919			// Update paging buttons only if there has been a change in SLIDEE position
920			if (last.slideePosState !== slideePosState) {
921				last.slideePosState = slideePosState;
922
923				if ($prevPageButton.is('button,input')) {
924					$prevPageButton.prop('disabled', isStart);
925				}
926
927				if ($nextPageButton.is('button,input')) {
928					$nextPageButton.prop('disabled', isEnd);
929				}
930
931				$prevPageButton.add($backwardButton)[isStart ? 'addClass' : 'removeClass'](o.disabledClass);
932				$nextPageButton.add($forwardButton)[isEnd ? 'addClass' : 'removeClass'](o.disabledClass);
933			}
934
935			// Forward & Backward buttons need a separate state caching because we cannot "property disable"
936			// them while they are being used, as disabled buttons stop emitting mouse events.
937			if (last.fwdbwdState !== slideePosState && dragging.released) {
938				last.fwdbwdState = slideePosState;
939
940				if ($backwardButton.is('button,input')) {
941					$backwardButton.prop('disabled', isStart);
942				}
943
944				if ($forwardButton.is('button,input')) {
945					$forwardButton.prop('disabled', isEnd);
946				}
947			}
948
949			// Item navigation
950			if (itemNav && rel.activeItem != null) {
951				var isFirst = rel.activeItem === 0;
952				var isLast = rel.activeItem >= items.length - 1;
953				var itemsButtonState = (isFirst ? 1 : 0) | (isLast ? 2 : 0);
954
955				if (last.itemsButtonState !== itemsButtonState) {
956					last.itemsButtonState = itemsButtonState;
957
958					if ($prevButton.is('button,input')) {
959						$prevButton.prop('disabled', isFirst);
960					}
961
962					if ($nextButton.is('button,input')) {
963						$nextButton.prop('disabled', isLast);
964					}
965
966					$prevButton[isFirst ? 'addClass' : 'removeClass'](o.disabledClass);
967					$nextButton[isLast ? 'addClass' : 'removeClass'](o.disabledClass);
968				}
969			}
970		}
971
972		/**
973		 * Resume cycling.
974		 *
975		 * @param {Int} priority Resume pause with priority lower or equal than this. Used internally for pauseOnHover.
976		 *
977		 * @return {Void}
978		 */
979		self.resume = function (priority) {
980			if (!o.cycleBy || !o.cycleInterval || o.cycleBy === 'items' && (!items[0] || rel.activeItem == null) || priority < self.isPaused) {
981				return;
982			}
983
984			self.isPaused = 0;
985
986			if (cycleID) {
987				cycleID = clearTimeout(cycleID);
988			} else {
989				trigger('resume');
990			}
991
992			cycleID = setTimeout(function () {
993				trigger('cycle');
994				switch (o.cycleBy) {
995					case 'items':
996						self.activate(rel.activeItem >= items.length - 1 ? 0 : rel.activeItem + 1);
997						break;
998
999					case 'pages':
1000						self.activatePage(rel.activePage >
1000= pages.length - 1 ? 0 : rel.activePage + 1);
1001						break;
1002				}
1003			}, o.cycleInterval);
1004		};
1005
1006		/**
1007		 * Pause cycling.
1008		 *
1009		 * @param {Int} priority Pause priority. 100 is default. Used internally for pauseOnHover.
1010		 *
1011		 * @return {Void}
1012		 */
1013		self.pause = function (priority) {
1014			if (priority < self.isPaused) {
1015				return;
1016			}
1017
1018			self.isPaused = priority || 100;
1019
1020			if (cycleID) {
1021				cycleID = clearTimeout(cycleID);
1022				trigger('pause');
1023			}
1024		};
1025
1026		/**
1027		 * Toggle cycling.
1028		 *
1029		 * @return {Void}
1030		 */
1031		self.toggle = function () {
1032			self[cycleID ? 'pause' : 'resume']();
1033		};
1034
1035		/**
1036		 * Updates a signle or multiple option values.
1037		 *
1038		 * @param {Mixed} name  Name of the option that should be updated, or object that will extend the options.
1039		 * @param {Mixed} value New option value.
1040		 *
1041		 * @return {Void}
1042		 */
1043		/*self.set = function (name, value) {
1044			if ($.isPlainObject(name)) {
1045				$.extend(o, name);
1046			} else if (o.hasOwnProperty(name)) {
1047				o[name] = value;
1048			}
1049		};*/
1050
1051		/**
1052		 * Registers callbacks.
1053		 *
1054		 * @param  {Mixed} name  Event name, or callbacks map.
1055		 * @param  {Mixed} fn    Callback, or an array of callback functions.
1056		 *
1057		 * @return {Void}
1058		 */
1059		self.on = function (name, fn) {
1060			// Callbacks map
1061			if (type(name) === 'object') {
1062				for (var key in name) {
1063					if (name.hasOwnProperty(key)) {
1064						self.on(key, name[key]);
1065					}
1066				}
1067			// Callback
1068			} else if (type(fn) === 'function') {
1069				var names = name.split(' ');
1070				for (var n = 0, nl = names.length; n < nl; n++) {
1071					callbacks[names[n]] = callbacks[names[n]] || [];
1072					if (callbackIndex(names[n], fn) === -1) {
1073						callbacks[names[n]].push(fn);
1074					}
1075				}
1076			// Callbacks array
1077			} else if (type(fn) === 'array') {
1078				for (var f = 0, fl = fn.length; f < fl; f++) {
1079					self.on(name, fn[f]);
1080				}
1081			}
1082		};
1083
1084		/**
1085		 * Registers callbacks to be executed only once.
1086		 *
1087		 * @param  {Mixed} name  Event name, or callbacks map.
1088		 * @param  {Mixed} fn    Callback, or an array of callback functions.
1089		 *
1090		 * @return {Void}
1091		 */
1092		/*self.one = function (name, fn) {
1093			function proxy() {
1094				fn.apply(self, arguments);
1095				self.off(name, proxy);
1096			}
1097			self.on(name, proxy);
1098		};*/
1099
1100		/**
1101		 * Remove one or all callbacks.
1102		 *
1103		 * @param  {String} name Event name.
1104		 * @param  {Mixed}  fn   Callback, or an array of callback functions. Omit to remove all callbacks.
1105		 *
1106		 * @return {Void}
1107		 */
1108		/*self.off = function (name, fn) {
1109			if (fn instanceof Array) {
1110				for (var f = 0, fl = fn.length; f < fl; f++) {
1111					self.off(name, fn[f]);
1112				}
1113			} else {
1114				var names = name.split(' ');
1115				for (var n = 0, nl = names.length; n < nl; n++) {
1116					callbacks[names[n]] = callbacks[names[n]] || [];
1117					if (fn == null) {
1118						callbacks[names[n]].length = 0;
1119					} else {
1120						var index = callbackIndex(names[n], fn);
1121						if (index !== -1) {
1122							callbacks[names[n]].splice(index, 1);
1123						}
1124					}
1125				}
1126			}
1127		};*/
1128
1129		/**
1130		 * Returns callback array index.
1131		 *
1132		 * @param  {String}   name Event name.
1133		 * @param  {Function} fn   Function
1134		 *
1135		 * @return {Int} Callback array index, or -1 if isn't registered.
1136		 */
1137		function callbackIndex(name, fn) {
1138			for (var i = 0, l = callbacks[name].length; i < l; i++) {
1139				if (callbacks[name][i] === fn) {
1140					return i;
1141				}
1142			}
1143			return -1;
1144		}
1145
1146		/**
1147		 * Reset next cycle timeout.
1148		 *
1149		 * @return {Void}
1150		 */
1151		function resetCycle() {
1152			if (dragging.released && !self.isPaused) {
1153				self.resume();
1154			}
1155		}
1156
1157		/**
1158		 * Calculate SLIDEE representation of handle position.
1159		 *
1160		 * @param  {Int} handlePos
1161		 *
1162		 * @return {Int}
1163		 */
1164		function handleToSlidee(handlePos) {
1165			return round(within(handlePos, hPos.start, hPos.end) / hPos.end * (pos.end - pos.start)) + pos.start;
1166		}
1167
1168		/**
1169		 * Keeps track of a dragging delta history.
1170		 *
1171		 * @return {Void}
1172		 */
1173		function draggingHistoryTick() {
1174			// Looking at this, I know what you're thinking :) But as we need only 4 history states, doing it this way
1175			// as opposed to a proper loop is ~25 bytes smaller (when minified with GCC), a lot faster, and doesn't
1176			// generate garbage. The loop version would create 2 new variables on every tick. Unexaptable!
1177			dragging.history[0] = dragging.history[1];
1178			dragging.history[1] = dragging.history[2];
1179			dragging.history[2] = dragging.history[3];
1180			dragging.history[3] = dragging.delta;
1181		}
1182
1183		/**
1184		 * Initialize continuous movement.
1185		 *
1186		 * @return {Void}
1187		 */
1188		function continuousInit(source) {
1189			dragging.released = 0;
1190			dragging.source = source;
1191			dragging.slidee = source === 'slidee';
1192		}
1193
1194		/**
1195		 * Dragging initiator.
1196		 *
1197		 * @param  {Event} event
1198		 *
1199		 * @return {Void}
1200		 */
1201		function dragInit(event) {
1202			var isTouch = event.type === 'touchstart';
1203			var source = event.data.source;
1204			var isSlidee = source === 'slidee';
1205
1206			// Ignore when already in progress, or interactive element in non-touch navivagion
1207			if (dragging.init || !isTouch && isInteractive(event.target)) {
1208				return;
1209			}
1210
1211			// Handle dragging conditions
1212			if (source === 'handle' && (!o.dragHandle || hPos.start === hPos.end)) {
1213				return;
1214			}
1215
1216			// SLIDEE dragging conditions
1217			if (isSlidee && !(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
1218				return;
1219			}
1220
1221			if (!isTouch) {
1222				// prevents native image dragging in Firefox
1223				stopDefault(event);
1224			}
1225
1226			// Reset dragging object
1227			continuousInit(source);
1228
1229			// Properties used in dragHandler
1230			dragging.init = 0;
1231			dragging.$source = $(event.target);
1232			dragging.touch = isTouch;
1233			dragging.pointer = isTouch ? event.originalEvent.touches[0] : event;
1234			dragging.initX = dragging.pointer.pageX;
1235			dragging.initY = dragging.pointer.pageY;
1236			dragging.initPos = isSlidee ? pos.cur : hPos.cur;
1237			dragging.start = +new Date();
1238			dragging.time = 0;
1239			dragging.path = 0;
1240			dragging.delta = 0;
1241			dragging.locked = 0;
1242			dragging.history = [0, 0, 0, 0];
1243			dragging.pathToLock = isSlidee ? isTouch ? 30 : 10 : 0;
1244
1245			// Bind dragging events
1246			$doc.on(isTouch ? dragTouchEvents : dragMouseEvents, dragHandler);
1247
1248			// Pause ongoing cycle
1249			self.pause(1);
1250
1251			// Add dragging class
1252			(isSlidee ? $slidee : $handle).addClass(o.draggedClass);
1253
1254			// Trigger moveStart event
1255			trigger('moveStart');
1256
1257			// Keep track of a dragging path history. This is later used in the
1258			// dragging release swing calculation when dragging SLIDEE.
1259			if (isSlidee) {
1260				historyID = setInterval(draggingHistoryTick, 10);
1261			}
1262		}
1263
1264		/**
1265		 * Handler for dragging scrollbar handle or SLIDEE.
1266		 *
1267		 * @param  {Event} event
1268		 *
1269		 * @return {Void}
1270		 */
1271		function dragHandler(event) {
1272			dragging.released = event.type === 'mouseup' || event.type === 'touchend';
1273			dragging.pointer = dragging.touch ? event.originalEvent[dragging.released ? 'changedTouches' : 'touches'][0] : event;
1274			dragging.pathX = dragging.pointer.pageX - dragging.initX;
1275			dragging.pathY = dragging.pointer.pageY - dragging.initY;
1276			dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2));
1277			dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
1278
1279			if (!dragging.released && dragging.path < 1) return;
1280
1281			if (!dragging.init) {
1282				if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) {
1283					dragging.init = 1;
1284				} else {
1285					return dragEnd();
1286				}
1287			}
1288
1289			stopDefault(event);
1290
1291			// Disable click on a source element, as it is unwelcome when dragging
1292			if (!dragging.locked && dragging.path > dragging.pathToLock && dragging.slidee) {
1293				dragging.locked = 1;
1294				dragging.$source.on(clickEvent, disableOneEvent);
1295			}
1296
1297			// Cancel dragging on release
1298			if (dragging.released) {
1299				dragEnd();
1300
1301				// Adjust path with a swing on mouse release
1302				if (o.releaseSwing && dragging.slidee) {
1303					dragging.swing = (dragging.delta - dragging.history[0]) / 40 * 300;
1304					dragging.delta += dragging.swing;
1305					dragging.tweese = abs(dragging.swing) > 10;
1306				}
1307			}
1308
1309			slideTo(dragging.slidee ? round(dragging.initPos - dragging.delta) : handleToSlidee(dragging.initPos + dragging.delta));
1310		}
1311
1312		/**
1313		 * Stops dragging and cleans up after it.
1314		 *
1315		 * @return {Void}
1316		 */
1317		function dragEnd() {
1318			clearInterval(historyID);
1319			dragging.released = true;
1320			$doc.off(dragging.touch ? dragTouchEvents : dragMouseEvents, dragHandler);
1321			(dragging.slidee ? $slidee : $handle).removeClass(o.draggedClass);
1322
1323			// Make sure that disableOneEvent is not active in next tick.
1324			setTimeout(function () {
1325				dragging.$source.off(clickEvent, disableOneEvent);
1326			});
1327
1328			// Normally, this is triggered in render(), but if there
1329			// is nothing to render, we have to do it manually here.
1330			if (pos.cur === pos.dest && dragging.init) {
1331				trigger('moveEnd');
1332			}
1333
1334			// Resume ongoing cycle
1335			self.resume(1);
1336
1337			dragging.init = 0;
1338		}
1339
1340		/**
1341		 * Check whether element is interactive.
1342		 *
1343		 * @return {Boolean}
1344		 */
1345		function isInteractive(element) {
1346			return ~$.inArray(element.nodeName, interactiveElements) || $(element).is(o.interactive);
1347		}
1348
1349		/**
1350		 * Continuous movement cleanup on mouseup.
1351		 *
1352		 * @return {Void}
1353		 */
1354		function movementReleaseHandler() {
1355			self.stop();
1356			$doc.off('mouseup', movementReleaseHandler);
1357		}
1358
1359		/**
1360		 * Buttons navigation handler.
1361		 *
1362		 * @param  {Event} event
1363		 *
1364		 * @return {Void}
1365		 */
1366		function buttonsHandler(event) {
1367			/*jshint validthis:true */
1368			stopDefault(event);
1369			switch (this) {
1370				case $forwardButton[0]:
1371				case $backwardButton[0]:
1372					self.moveBy($forwardButton.is(this) ? o.moveBy : -o.moveBy);
1373					$doc.on('mouseup', movementReleaseHandler);
1374					break;
1375
1376				case $prevButton[0]:
1377					self.prev();
1378					break;
1379
1380				case $nextButton[0]:
1381					self.next();
1382					break;
1383
1384				case $prevPageButton[0]:
1385					self.prevPage();
1386					break;
1387
1388				case $nextPageButton[0]:
1389					self.nextPage();
1390					break;
1391			}
1392		}
1393
1394		/**
1395		 * Mouse wheel delta normalization.
1396		 *
1397		 * @param  {Event} event
1398		 *
1399		 * @return {Int}
1400		 */
1401		/*function normalizeWheelDelta(event) {
1402			// wheelDelta needed only for IE8-
1403			scrolling.curDelta = ((o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta);
1404			scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
1405			if (!itemNav) {
1406				return scrolling.curDelta;
1407			}
1408			time = +new Date();
1409			if (scrolling.last < time - scrolling.resetTime) {
1410				scrolling.delta = 0;
1411			}
1412			scrolling.last = time;
1413			scrolling.delta += scrolling.curDelta;
1414			if (abs(scrolling.delta) < 1) {
1415				scrolling.finalDelta = 0;
1416			} else {
1417				scrolling.finalDelta = round(scrolling.delta / 1);
1418				scrolling.delta %= 1;
1419			}
1420			return scrolling.finalDelta;
1421		}*/
1422
1423		/**
1424		 * Mouse scrolling handler.
1425		 *
1426		 * @param  {Event} event
1427		 *
1428		 * @return {Void}
1429		 */
1430		/*function scrollHandler(event) {
1431			// Mark event as originating in a TG_Slider instance
1432			event.originalEvent[namespace] = self;
1433			// Don't hijack global scrolling
1434			var time = +new Date();
1435			if (lastGlobalWheel + o.scrollHijack > time && $scrollSource[0] !== document && $scrollSource[0] !== window) {
1436				lastGlobalWheel = time;
1437				return;
1438			}
1439			// Ignore if there is no scrolling to be done
1440			if (!o.scrollBy || pos.start === pos.end) {
1441				return;
1442			}
1443			var delta = normalizeWheelDelta(event.originalEvent);
1444			// Trap scrolling only when necessary and/or requested
1445			if (o.scrollTrap || delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
1446				stopDefault(event, 1);
1447			}
1448			self.slideBy(o.scrollBy * delta);
1449		}*/
1450
1451		/**
1452		 * Scrollbar click handler.
1453		 *
1454		 * @param  {Event} event
1455		 *
1456		 * @return {Void}
1457		 */
1458		/*function scrollbarHandler(event) {
1459			// Only clicks on scroll bar. Ignore the handle.
1460			if (o.clickBar && event.target === $sb[0]) {
1461				stopDefault(event);
1462				// Calculate new handle position and sync SLIDEE to it
1463				slideTo(handleToSlidee((o.horizontal ? event.pageX - $sb.offset().left : event.pageY - $sb.offset().top) - handleSize / 2));
1464			}
1465		}*/
1466
1467		/**
1468		 * Keyboard input handler.
1469		 *
1470		 * @param  {Event} event
1471		 *
1472		 * @return {Void}
1473		 */
1474		function keyboardHandler(event) {
1475			if (!o.keyboardNavBy) {
1476				return;
1477			}
1478
1479			switch (event.which) {
1480				// Left or Up
1481				case o.horizontal ? 37 : 38:
1482					stopDefault(event);
1483					self[o.keyboardNavBy === 'pages' ? 'prevPage' : 'prev']();
1484					break;
1485
1486				// Right or Down
1487				case o.horizontal ? 39 : 40:
1488					stopDefault(event);
1489					self[o.keyboardNavBy === 'pages' ? 'nextPage' : 'next']();
1490					break;
1491			}
1492		}
1493
1494		/**
1495		 * Click on item activation handler.
1496		 *
1497		 * @param  {Event} event
1498		 *
1499		 * @return {Void}
1500		 */
1501		/*function activateHandler(event) {
1502
1503			// Ignore clicks on interactive elements.
1504			if (isInteractive(this)) {
1505				event.originalEvent[namespace + 'ignore'] = true;
1506				return;
1507			}
1508
1509			// Ignore events that:
1510			// - are not originating from direct SLIDEE children
1511			// - originated from interactive elements
1512			if (this.parentNode !== $slidee[0] || event.originalEvent[namespace + 'ignore']) return;
1513
1514			self.activate(this);
1515		}*/
1516
1517		/**
1518		 * Click on page button handler.
1519		 *
1520		 * @param {Event} event
1521		 *
1522		 * @return {Void}
1523		 */
1524		function activatePageHandler() {
1525			/*jshint validthis:true */
1526			// Accept only events from direct pages bar children.
1527			if (this.parentNode === $pb[0]) {
1528				self.activatePage($pages.index(this));
1529			}
1530		}
1531
1532		/**
1533		 * Pause on hover handler.
1534		 *
1535		 * @param  {Event} event
1536		 *
1537		 * @return {Void}
1538		 */
1539		function pauseOnHoverHandler(event) {
1540			if (o.pauseOnHover) {
1541				self[event.type === 'mouseenter' ? 'pause' : 'resume'](2);
1542			}
1543		}
1544
1545		/**
1546		 * Trigger callbacks for event.
1547		 *
1548		 * @param  {String} name Event name.
1549		 * @param  {Mixed}  argX Arguments passed to callbacks.
1550		 *
1551		 * @return {Void}
1552		 */
1553		function trigger(name, arg1) {
1554			if (callbacks[name]) {
1555				l = callbacks[name].length;
1556				// Callbacks will be stored and executed from a temporary array to not
1557				// break the execution queue when one of the callbacks unbinds itself.
1558				tmpArray.length = 0;
1559				for (i = 0; i < l; i++) {
1560					tmpArray.push(callbacks[name][i]);
1561				}
1562				// Execute the callbacks
1563				for (i = 0; i < l; i++) {
1564					tmpArray[i].call(self, name, arg1);
1565				}
1566			}
1567		}
1568
1569		/**
1570		 * Destroys instance and everything it created.
1571		 *
1572		 * @return {Void}
1573		 */
1574		/*self.destroy = function () {
1575			// Unbind all events
1576			$scrollSource
1577				.add($handle)
1578				.add($sb)
1579				.add($pb)
1580				.add($forwardButton)
1581				.add($backwardButton)
1582				.add($prevButton)
1583				.add($nextButton)
1584				.add($prevPageButton)
1585				.add($nextPageButton)
1586				.off('.' + namespace);
1587
1588			// Unbinding specifically as to not nuke out other instances
1589			$doc.off('keydown', keyboardHandler);
1590
1591			// Remove classes
1592			$prevButton
1593				.add($nextButton)
1594				.add($prevPageButton)
1595				.add($nextPageButton)
1596				.removeClass(o.disabledClass);
1597
1598			if ($items && rel.activeItem != null) {
1599				$items.eq(rel.activeItem).removeClass(o.activeClass);
1600			}
1601
1602			// Remove page items
1603			$pb.empty();
1604
1605			if (!parallax) {
1606				// Unbind events from frame
1607				$frame.off('.' + namespace);
1608				// Restore original styles
1609				frameStyles.restore();
1610				slideeStyles.restore();
1611				sbStyles.restore();
1612				handleStyles.restore();
1613				// Remove the instance from element data storage
1614				$.removeData(frame, namespace);
1615			}
1616
1617			// Clean up collections
1618			items.length = pages.length = 0;
1619			last = {};
1620
1621			// Reset initialized status and return the instance
1622			self.initialized = 0;
1623			return self;
1624		};*/
1625
1626		/**
1627		 * Initialize.
1628		 *
1629		 * @return {Object}
1630		 */
1631		self.init = function () {
1632			if (self.initialized) {
1633				return;
1634			}
1635
1636			// Register callbacks map
1637			self.on(callbackMap);
1638
1639			// Save styles
1640			var holderProps = ['overflow', 'position'];
1641			var movableProps = ['position', 'webkitTransform', 'msTransform', 'transform', 'left', 'top', 'width', 'height'];
1642			frameStyles.save.apply(frameStyles, holderProps);
1643			sbStyles.save.apply(sbStyles, holderProps);
1644			slideeStyles.save.apply(slideeStyles, movableProps);
1645			handleStyles.save.apply(handleStyles, movableProps);
1646
1647			// Set required styles
1648			var $movables = $handle;
1649			if (!parallax) {
1650				$movables = $movables.add($slidee);
1651				$frame.css('overflow', 'hidden');
1652				if (!transform && $frame.css('position') === 'static') {
1653					$frame.css('position', 'relative');
1654				}
1655			}
1656			if (transform) {
1657				if (gpuAcceleration) {
1658					$movables.css(transform, gpuAcceleration);
1659				}
1660			} else {
1661				if ($sb.css('position') === 'static') {
1662					$sb.css('position', 'relative');
1663				}
1664				$movables.css({ position: 'absolute' });
1665			}
1666
1667			// Navigation buttons
1668			if (o.forward) {
1669				$forwardButton.on(mouseDownEvent, buttonsHandler);
1670			}
1671			if (o.backward) {
1672				$backwardButton.on(mouseDownEvent, buttonsHandler);
1673			}
1674			if (o.prev) {
1675				$prevButton.on(clickEvent, buttonsHandler);
1676			}
1677			if (o.next) {
1678				$nextButton.on(clickEvent, buttonsHandler);
1679			}
1680			if (o.prevPage) {
1681				$prevPageButton.on(clickEvent, buttonsHandler);
1682			}
1683			if (o.nextPage) {
1684				$nextPageButton.on(clickEvent, buttonsHandler);
1685			}
1686
1687			// Scrolling navigation
1688			//$scrollSource.on(wheelEvent, scrollHandler);
1689
1690			// Clicking on scrollbar navigation
1691			/*if ($sb[0]) {
1692				$sb.on(clickEvent, scrollbarHandler);
1693			}*/
1694
1695			// Click on items navigation
1696			/*if (itemNav && o.activateOn) {
1697				$frame.on(o.activateOn + '.' + namespace, '*', activateHandler);
1698			}*/
1699
1700			// Pages navigation
1701			if ($pb[0] && o.activatePageOn) {
1702				$pb.on(o.activatePageOn + '.' + namespace, '*', activatePageHandler);
1703			}
1704
1705			// Dragging navigation
1706			$dragSource.on(dragInitEvents, { source: 'slidee' }, dragInit);
1707
1708			// Scrollbar dragging navigation
1709			if ($handle) {
1710				$handle.on(dragInitEvents, { source: 'handle' }, dragInit);
1711			}
1712
1713			// Keyboard navigation
1714			$doc.on('keydown', keyboardHandler);
1715
1716			if (!parallax) {
1717				// Pause on hover
1718				$frame.on('mouseenter.' + namespace + ' mouseleave.' + namespace, pauseOnHoverHandler);
1719				// Reset native FRAME element scroll
1720				$frame.on('scroll.' + namespace, resetScroll);
1721			}
1722
1723			// Mark instance as initialized
1724			self.initialized = 1;
1725
1726			// Load
1727			load(true);
1728
1729			// Initiate automatic cycling
1730			if (o.cycleBy && !parallax) {
1731				self[o.startPaused ? 'pause' : 'resume']();
1732			}
1733
1734			// Return instance
1735			return self;
1736		};
1737	}
1738
1739	/**
1740	 * Return type of the value.
1741	 *
1742	 * @param  {Mixed} value
1743	 *
1744	 * @return {String}
1745	 */
1746	function type(value) {
1747		if (value == null) {
1748			return String(value);
1749		}
1750
1751		if (typeof value === 'object' || typeof value === 'function') {
1752			return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
1753		}
1754
1755		return typeof value;
1756	}
1757
1758	/**
1759	 * Event preventDefault & stopPropagation helper.
1760	 *
1761	 * @param {Event} event     Event object.
1762	 * @param {Bool}  noBubbles Cancel event bubbling.
1763	 *
1764	 * @return {Void}
1765	 */
1766	function stopDefault(event, noBubbles) {
1767		event.preventDefault();
1768		if (noBubbles) {
1769			event.stopPropagation();
1770		}
1771	}
1772
1773	/**
1774	 * Disables an event it was triggered on and unbinds itself.
1775	 *
1776	 * @param  {Event} event
1777	 *
1778	 * @return {Void}
1779	 */
1780	function disableOneEvent(event) {
1781		/*jshint validthis:true */
1782		stopDefault(event, 1);
1783		$(this).off(event.type, disableOneEvent);
1784	}
1785
1786	/**
1787	 * Resets native element scroll values to 0.
1788	 *
1789	 * @return {Void}
1790	 */
1791	function resetScroll() {
1792		/*jshint validthis:true */
1793		this.scrollLeft = 0;
1794		this.scrollTop = 0;
1795	}
1796
1797	/**
1798	 * Check if variable is a number.
1799	 *
1800	 * @param {Mixed} value
1801	 *
1802	 * @return {Boolean}
1803	 */
1804	function isNumber(value) {
1805		return !isNaN(parseFloat(value)) && isFinite(value);
1806	}
1807
1808	/**
1809	 * Parse style to pixels.
1810	 *
1811	 * @param {Object}   $item    jQuery object with element.
1812	 * @param {Property} property CSS property to get the pixels from.
1813	 *
1814	 * @return {Int}
1815	 */
1816	function getPx($item, property) {
1817		return 0 | round(String($item.css(property)).replace(/[^\-0-9.]/g, ''));
1818	}
1819
1820	/**
1821	 * Make sure that number is within the limits.
1822	 *
1823	 * @param {Number} number
1824	 * @param {Number} min
1825	 * @param {Number} max
1826	 *
1827	 * @return {Number}
1828	 */
1829	function within(number, min, max) {
1830		return number < min ? min : number > max ? max : number;
1831	}
1832
1833	/**
1834	 * Saves element styles for later restoration.
1835	 *
1836	 * Example:
1837	 *   var styles = new StyleRestorer(frame);
1838	 *   styles.save('position');
1839	 *   element.style.position = 'absolute';
1840	 *   styles.restore(); // restores to state before the assignment above
1841	 *
1842	 * @param {Element} element
1843	 */
1844	function StyleRestorer(element) {
1845		var self = {};
1846		self.style = {};
1847		self.save = function () {
1848			if (!element || !element.nodeType) return;
1849			for (var i = 0; i < arguments.length; i++) {
1850				self.style[arguments[i]] = element.style[arguments[i]];
1851			}
1852			return self;
1853		};
1854		self.restore = function () {
1855			if (!element || !element.nodeType) return;
1856			for (var prop in self.style) {
1857				if (self.style.hasOwnProperty(prop)) element.style[prop] = self.style[prop];
1858			}
1859			return self;
1860		};
1861		return self;
1862	}
1863
1864	// Local WindowAnimationTiming interface polyfill
1865	(function (w) {
1866		rAF = w.requestAnimationFrame
1867			|| w.webkitRequestAnimationFrame
1868			|| fallback;
1869
1870		/**
1871		* Fallback implementation.
1872		*/
1873		var prev = new Date().getTime();
1874		function fallback(fn) {
1875			var curr = new Date().getTime();
1876			var ms = Math.max(0, 16 - (curr - prev));
1877			var req = setTimeout(fn, ms);
1878			prev = curr;
1879			return req;
1880		}
1881
1882		/**
1883		* Cancel.
1884		*/
1885		var cancel = w.cancelAnimationFrame
1886			|| w.webkitCancelAnimationFrame
1887			|| w.clearTimeout;
1888
1889		cAF = function(id){
1890			cancel.call(w, id);
1891		};
1892	}(window));
1893
1894	// Feature detects
1895	(function () {
1896		var prefixes = ['', 'Webkit', 'Moz', 'ms', 'O'];
1897		var el = document.createElement('div');
1898
1899		function testProp(prop) {
1900			for (var p = 0, pl = prefixes.length; p < pl; p++) {
1901				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
1902				if (el.style[prefixedProp] != null) {
1903					return prefixedProp;
1904				}
1905			}
1906		}
1907
1908		// Global support indicators
1909		transform = testProp('transform');
1910		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
1911	}());
1912
1913	// Expose class globally
1914	w[className] = TG_Slider;
1915
1916	// jQuery proxy
1917	$.fn[pluginName] = function (options, callbackMap) {
1918		var method, methodArgs;
1919
1920		// Attributes logic
1921		if (!$.isPlainObject(options)) {
1922			if (type(options) === 'string' || options === false) {
1923				method = options === false ? 'destroy' : options;
1924				methodArgs = Array.prototype.slice.call(arguments, 1);
1925			}
1926			options = {};
1927		}
1928
1929		// Apply to all elements
1930		return this.each(function (i, element) {
1931			// Call with prevention against multiple instantiations
1932			var plugin = $.data(element, namespace);
1933
1934			if (!plugin && !method) {
1935				// Create a new object if it doesn't exist yet
1936				plugin = $.data(element, namespace, new TG_Slider(element, options, callbackMap).init());
1937			} else if (plugin && method) {
1938				// Call method
1939				if (plugin[method]) {
1940					plugin[method].apply(plugin, methodArgs);
1941				}
1942			}
1943		});
1944	};
1945
1946	// Default options
1947	/*TG_Slider.defaults = {
1948		slidee:     null,  // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
1949		horizontal: false, // Switch to horizontal mode.
1950
1951		// Item based navigation
1952		itemNav:        null,  // Item navigation type. Can be: 'basic', 'centered', 'forceCentered'.
1953		itemSelector:   null,  // Select only items that match this selector.
1954		smart:          false, // Repositions the activated item to help with further navigation.
1955		activateOn:     null,  // Activate an item on this event. Can be: 'click', 'mouseenter', ...
1956		activateMiddle: false, // Always activate the item in the middle of the FRAME. forceCentered only.
1957
1958		// Scrolling
1959		scrollSource: null,  // Element for catching the mouse wheel scrolling. Default is FRAME.
1960		scrollBy:     0,     // Pixels or items to move per one mouse scroll. 0 to disable scrolling.
1961		scrollHijack: 300,   // Milliseconds since last wheel event after which it is acceptable to hijack global scroll.
1962		scrollTrap:   false, // Don't bubble scrolling when hitting scrolling limits.
1963
1964		// Dragging
1965		dragSource:    null,  // Selector or DOM element for catching dragging events. Default is FRAME.
1966		mouseDragging: false, // Enable navigation by dragging the SLIDEE with mouse cursor.
1967		touchDragging: false, // Enable navigation by dragging the SLIDEE with touch events.
1968		releaseSwing:  false, // Ease out on dragging swing release.
1969		swingSpeed:    0.2,   // Swing synchronization speed, where: 1 = instant, 0 = infinite.
1970		elasticBounds: false, // Stretch SLIDEE position limits when dragging past FRAME boundaries.
1971		interactive:   null,  // Selector for special interactive elements.
1972
1973		// Scrollbar
1974		scrollBar:     null,  // Selector or DOM element for scrollbar container.
1975		dragHandle:    false, // Whether the scrollbar handle should be draggable.
1976		dynamicHandle: false, // Scrollbar handle represents the ratio between hidden and visible content.
1977		minHandleSize: 50,    // Minimal height or width (depends on TG_Slider direction) of a handle in pixels.
1978		clickBar:      false, // Enable navigation by clicking on scrollbar.
1979		syncSpeed:     0.5,   // Handle =>
1979 SLIDEE synchronization speed, where: 1 = instant, 0 = infinite.
1980
1981		// Pagesbar
1982		pagesBar:       null, // Selector or DOM element for pages bar container.
1983		activatePageOn: null, // Event used to activate page. Can be: click, mouseenter, ...
1984		pageBuilder:          // Page item generator.
1985			function (index) {
1986				return '<li>' + (index + 1) + '</li>';
1987			},
1988
1989		// Navigation buttons
1990		forward:  null, // Selector or DOM element for "forward movement" button.
1991		backward: null, // Selector or DOM element for "backward movement" button.
1992		prev:     null, // Selector or DOM element for "previous item" button.
1993		next:     null, // Selector or DOM element for "next item" button.
1994		prevPage: null, // Selector or DOM element for "previous page" button.
1995		nextPage: null, // Selector or DOM element for "next page" button.
1996
1997		// Automated cycling
1998		cycleBy:       null,  // Enable automatic cycling by 'items' or 'pages'.
1999		cycleInterval: 5000,  // Delay between cycles in milliseconds.
2000		pauseOnHover:  false, // Pause cycling when mouse hovers over the FRAME.
2001		startPaused:   false, // Whether to start in paused sate.
2002
2003		// Mixed options
2004		moveBy:        300,     // Speed in pixels per second used by forward and backward buttons.
2005		speed:         0,       // Animations speed in milliseconds. 0 to disable animations.
2006		easing:        'swing', // Easing for duration based (tweening) animations.
2007		startAt:       null,    // Starting offset in pixels or items.
2008		keyboardNavBy: null,    // Enable keyboard navigation by 'items' or 'pages'.
2009
2010		// Classes
2011		draggedClass:  'dragged', // Class for dragged elements (like SLIDEE or scrollbar handle).
2012		activeClass:   'active',  // Class for active items and pages.
2013		disabledClass: 'disabled' // Class for disabled navigation elements.
2014	};*/
2015}(jQuery, window));

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.