PageSourceSearch

https://tsf.iproa.org/includes/pofo/html/js/jquery.stellar.js

js iproa.org collected 2026-09-29 05:50:38 UTC 23,282 bytes, 660 lines download raw bytes

vendor: 23,282 bytes, lines 1-660
1/*!
2 * Stellar.js v0.6.2
3 * http://markdalgleish.com/projects/stellar.js
4 *
5 * Copyright 2014, Mark Dalgleish
6 * This content is released under the MIT license
7 * http://markdalgleish.mit-license.org
8 */
9
10;(function($, window, document, undefined) {
11
12	var pluginName = 'stellar',
13		defaults = {
14			scrollProperty: 'scroll',
15			positionProperty: 'position',
16			horizontalScrolling: true,
17			verticalScrolling: true,
18			horizontalOffset: 0,
19			verticalOffset: 0,
20			responsive: false,
21			parallaxBackgrounds: true,
22			parallaxElements: true,
23			hideDistantElements: true,
24			hideElement: function($elem) { $elem.hide(); },
25			showElement: function($elem) { $elem.show(); }
26		},
27
28		scrollProperty = {
29			scroll: {
30				getLeft: function($elem) { return $elem.scrollLeft(); },
31				setLeft: function($elem, val) { $elem.scrollLeft(val); },
32
33				getTop: function($elem) { return $elem.scrollTop();	},
34				setTop: function($elem, val) { $elem.scrollTop(val); }
35			},
36			position: {
37				getLeft: function($elem) { return parseInt($elem.css('left'), 10) * -1; },
38				getTop: function($elem) { return parseInt($elem.css('top'), 10) * -1; }
39			},
40			margin: {
41				getLeft: function($elem) { return parseInt($elem.css('margin-left'), 10) * -1; },
42				getTop: function($elem) { return parseInt($elem.css('margin-top'), 10) * -1; }
43			},
44			transform: {
45				getLeft: function($elem) {
46					var computedTransform = getComputedStyle($elem[0])[prefixedTransform];
47					return (computedTransform !== 'none' ? parseInt(computedTransform.match(/(-?[0-9]+)/g)[4], 10) * -1 : 0);
48				},
49				getTop: function($elem) {
50					var computedTransform = getComputedStyle($elem[0])[prefixedTransform];
51					return (computedTransform !== 'none' ? parseInt(computedTransform.match(/(-?[0-9]+)/g)[5], 10) * -1 : 0);
52				}
53			}
54		},
55
56		positionProperty = {
57			position: {
58				setLeft: function($elem, left) { $elem.css('left', left); },
59				setTop: function($elem, top) { $elem.css('top', top); }
60			},
61			transform: {
62				setPosition: function($elem, left, startingLeft, top, startingTop) {
63					$elem[0].style[prefixedTransform] = 'translate3d(' + (left - startingLeft) + 'px, ' + (top - startingTop) + 'px, 0)';
64				}
65			}
66		},
67
68		// Returns a function which adds a vendor prefix to any CSS property name
69		vendorPrefix = (function() {
70			var prefixes = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,
71				style = $('script')[0].style,
72				prefix = '',
73				prop;
74
75			for (prop in style) {
76				if (prefixes.test(prop)) {
77					prefix = prop.match(prefixes)[0];
78					break;
79				}
80			}
81
82			if ('WebkitOpacity' in style) { prefix = 'Webkit'; }
83			if ('KhtmlOpacity' in style) { prefix = 'Khtml'; }
84
85			return function(property) {
86				return prefix + (prefix.length > 0 ? property.charAt(0).toUpperCase() + property.slice(1) : property);
87			};
88		}()),
89
90		prefixedTransform = vendorPrefix('transform'),
91
92		supportsBackgroundPositionXY = $('<div />', { style: 'background:#fff' }).css('background-position-x') !== undefined,
93
94		setBackgroundPosition = (supportsBackgroundPositionXY ?
95			function($elem, x, y) {
96				$elem.css({
97					'background-position-x': x,
98					'background-position-y': y
99				});
100			} :
101			function($elem, x, y) {
102				$elem.css('background-position', x + ' ' + y);
103			}
104		),
105
106		getBackgroundPosition = (supportsBackgroundPositionXY ?
107			function($elem) {
108				return [
109					$elem.css('background-position-x'),
110					$elem.css('background-position-y')
111				];
112			} :
113			function($elem) {
114				return $elem.css('background-position').split(' ');
115			}
116		),
117
118		requestAnimFrame = (
119			window.requestAnimationFrame       ||
120			window.webkitRequestAnimationFrame ||
121			window.mozRequestAnimationFrame    ||
122			window.oRequestAnimationFrame      ||
123			window.msRequestAnimationFrame     ||
124			function(callback) {
125				setTimeout(callback, 1000 / 60);
126			}
127		);
128
129	function Plugin(element, options) {
130		this.element = element;
131		this.options = $.extend({}, defaults, options);
132
133		this._defaults = defaults;
134		this._name = pluginName;
135
136		this.init();
137	}
138
139	Plugin.prototype = {
140		init: function() {
141			this.options.name = pluginName + '_' + Math.floor(Math.random() * 1e9);
142
143			this._defineElements();
144			this._defineGetters();
145			this._defineSetters();
146			this._handleWindowLoadAndResize();
147			this._detectViewport();
148
149			this.refresh({ firstLoad: true });
150
151			if (this.options.scrollProperty === 'scroll') {
152				this._handleScrollEvent();
153			} else {
154				this._startAnimationLoop();
155			}
156		},
157		_defineElements: function() {
158			if (this.element === document.body) this.element = window;
159			this.$scrollElement = $(this.element);
160			this.$element = (this.element === window ? $('body') : this.$scrollElement);
161			this.$viewportElement = (this.options.viewportElement !== undefined ? $(this.options.viewportElement) : (this.$scrollElement[0] === window || this.options.scrollProperty === 'scroll' ? this.$scrollElement : this.$scrollElement.parent()) );
162		},
163		_defineGetters: function() {
164			var self = this,
165				scrollPropertyAdapter = scrollProperty[self.options.scrollProperty];
166
167			this._getScrollLeft = function() {
168				return scrollPropertyAdapter.getLeft(self.$scrollElement);
169			};
170
171			this._getScrollTop = function() {
172				return scrollPropertyAdapter.getTop(self.$scrollElement);
173			};
174		},
175		_defineSetters: function() {
176			var self = this,
177				scrollPropertyAdapter = scrollProperty[self.options.scrollProperty],
178				positionPropertyAdapter = positionProperty[self.options.positionProperty],
179				setScrollLeft = scrollPropertyAdapter.setLeft,
180				setScrollTop = scrollPropertyAdapter.setTop;
181
182			this._setScrollLeft = (typeof setScrollLeft === 'function' ? function(val) {
183				setScrollLeft(self.$scrollElement, val);
184			} : $.noop);
185
186			this._setScrollTop = (typeof setScrollTop === 'function' ? function(val) {
187				setScrollTop(self.$scrollElement, val);
188			} : $.noop);
189
190			this._setPosition = positionPropertyAdapter.setPosition ||
191				function($elem, left, startingLeft, top, startingTop) {
192					if (self.options.horizontalScrolling) {
193						positionPropertyAdapter.setLeft($elem, left, startingLeft);
194					}
195
196					if (self.options.verticalScrolling) {
197						positionPropertyAdapter.setTop($elem, top, startingTop);
198					}
199				};
200		},
201		_handleWindowLoadAndResize: function() {
202			var self = this,
203				$window = $(window);
204
205			if (self.options.responsive) {
206				$window.bind('load.' + this.name, function() {
207					self.refresh();
208				});
209			}
210
211			$window.bind('resize.' + this.name, function() {
212				self._detectViewport();
213
214				if (self.options.responsive) {
215					self.refresh();
216				}
217			});
218		},
219		refresh: function(options) {
220			var self = this,
221				oldLeft = self._getScrollLeft(),
222				oldTop = self._getScrollTop();
223
224			if (!options || !options.firstLoad) {
225				this._reset();
226			}
227
228			this._setScrollLeft(0);
229			this._setScrollTop(0);
230
231			this._setOffsets();
232			this._findParticles();
233			this._findBackgrounds();
234
235			// Fix for WebKit background rendering bug
236			if (options && options.firstLoad && /WebKit/.test(navigator.userAgent)) {
237				$(window).load(function() {
238					var oldLeft = self._getScrollLeft(),
239						oldTop = self._getScrollTop();
240
241					self._setScrollLeft(oldLeft + 1);
242					self._setScrollTop(oldTop + 1);
243
244					self._setScrollLeft(oldLeft);
245					self._setScrollTop(oldTop);
246				});
247			}
248
249			this._setScrollLeft(oldLeft);
250			this._setScrollTop(oldTop);
251		},
252		_detectViewport: function() {
253			var viewportOffsets = this.$viewportElement.offset(),
254				hasOffsets = viewportOffsets !== null && viewportOffsets !== undefined;
255
256			this.viewportWidth = this.$viewportElement.width();
257			this.viewportHeight = this.$viewportElement.height();
258
259			this.viewportOffsetTop = (hasOffsets ? viewportOffsets.top : 0);
260			this.viewportOffsetLeft = (hasOffsets ? viewportOffsets.left : 0);
261		},
262		_findParticles: function() {
263			var self = this,
264				scrollLeft = this._getScrollLeft(),
265				scrollTop = this._getScrollTop();
266
267			if (this.particles !== undefined) {
268				for (var i = this.particles.length - 1; i >= 0; i--) {
269					this.particles[i].$element.data('stellar-elementIsActive', undefined);
270				}
271			}
272
273			this.particles = [];
274
275			if (!this.options.parallaxElements) return;
276
277			this.$element.find('[data-stellar-ratio]').each(function(i) {
278				var $this = $(this),
279					horizontalOffset,
280					verticalOffset,
281					positionLeft,
282					positionTop,
283					marginLeft,
284					marginTop,
285					$offsetParent,
286					offsetLeft,
287					offsetTop,
288					parentOffsetLeft = 0,
289					parentOffsetTop = 0,
290					tempParentOffsetLeft = 0,
291					tempParentOffsetTop = 0;
292
293				// Ensure this element isn't already part of another scrolling element
294				if (!$this.data('stellar-elementIsActive')) {
295					$this.data('stellar-elementIsActive', this);
296				} else if ($this.data('stellar-elementIsActive') !== this) {
297					return;
298				}
299
300				self.options.showElement($this);
301
302				// Save/restore the original top and left CSS values in case we refresh the particles or destroy the instance
303				if (!$this.data('stellar-startingLeft')) {
304					$this.data('stellar-startingLeft', $this.css('left'));
305					$this.data('stellar-startingTop', $this.css('top'));
306				} else {
307					$this.css('left', $this.data('stellar-startingLeft'));
308					$this.css('top', $this.data('stellar-startingTop'));
309				}
310
311				positionLeft = $this.position().left;
312				positionTop = $this.position().top;
313
314				// Catch-all for margin top/left properties (these evaluate to 'auto' in IE7 and IE8)
315				marginLeft = ($this.css('margin-left') === 'auto') ? 0 : parseInt($this.css('margin-left'), 10);
316				marginTop = ($this.css('margin-top') === 'auto') ? 0 : parseInt($this.css('margin-top'), 10);
317
318				offsetLeft = $this.offset().left - marginLeft;
319				offsetTop = $this.offset().top - marginTop;
320
321				// Calculate the offset parent
322				$this.parents().each(function() {
323					var $this = $(this);
324
325					if ($this.data('stellar-offset-parent') === true) {
326						parentOffsetLeft = tempParentOffsetLeft;
327						parentOffsetTop = tempParentOffsetTop;
328						$offsetParent = $this;
329
330						return false;
331					} else {
332						tempParentOffsetLeft += $this.position().left;
333						tempParentOffsetTop += $this.position().top;
334					}
335				});
336
337				// Detect the offsets
338				horizontalOffset = ($this.data('stellar-horizontal-offset') !== undefined ? $this.data('stellar-horizontal-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-horizontal-offset') !== undefined ? $offsetParent.data('stellar-horizontal-offset') : self.horizontalOffset));
339				verticalOffset = ($this.data('stellar-vertical-offset') !== undefined ? $this.data('stellar-vertical-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-vertical-offset') !== undefined ? $offsetParent.data('stellar-vertical-offset') : self.verticalOffset));
340
341				// Add our object to the particles collection
342				self.particles.push({
343					$element: $this,
344					$offsetParent: $offsetParent,
345					isFixed: $this.css('position') === 'fixed',
346					horizontalOffset: horizontalOffset,
347					verticalOffset: verticalOffset,
348					startingPositionLeft: positionLeft,
349					startingPositionTop: positionTop,
350					startingOffsetLeft: offsetLeft,
351					startingOffsetTop: offsetTop,
352					parentOffsetLeft: parentOffsetLeft,
353					parentOffsetTop: parentOffsetTop,
354					stellarRatio: ($this.data('stellar-ratio') !== undefined ? $this.data('stellar-ratio') : 1),
355					width: $this.outerWidth(true),
356					height: $this.outerHeight(true),
357					isHidden: false
358				});
359			});
360		},
361		_findBackgrounds: function() {
362			var self = this,
363				scrollLeft = this._getScrollLeft(),
364				scrollTop = this._getScrollTop(),
365				$backgroundElements;
366
367			this.backgrounds = [];
368
369			if (!this.options.parallaxBackgrounds) return;
370
371			$backgroundElements = this.$element.find('[data-stellar-background-ratio]');
372
373			if (this.$element.data('stellar-background-ratio')) {
374                $backgroundElements = $backgroundElements.add(this.$element);
375			}
376
377			$backgroundElements.each(function() {
378				var $this = $(this),
379					backgroundPosition = getBackgroundPosition($this),
380					horizontalOffset,
381					verticalOffset,
382					positionLeft,
383					positionTop,
384					marginLeft,
385					marginTop,
386					offsetLeft,
387					offsetTop,
388					$offsetParent,
389					parentOffsetLeft = 0,
390					parentOffsetTop = 0,
391					tempParentOffsetLeft = 0,
392					tempParentOffsetTop = 0;
393
394				// Ensure this element isn't already part of another scrolling element
395				if (!$this.data('stellar-backgroundIsActive')) {
396					$this.data('stellar-backgroundIsActive', this);
397				} else if ($this.data('stellar-backgroundIsActive') !== this) {
398					return;
399				}
400
401				// Save/restore the original top and left CSS values in case we destroy the instance
402				if (!$this.data('stellar-backgroundStartingLeft')) {
403					$this.data('stellar-backgroundStartingLeft', backgroundPosition[0]);
404					$this.data('stellar-backgroundStartingTop', backgroundPosition[1]);
405				} else {
406					setBackgroundPosition($this, $this.data('stellar-backgroundStartingLeft'), $this.data('stellar-backgroundStartingTop'));
407				}
408
409				// Catch-all for margin top/left properties (these evaluate to 'auto' in IE7 and IE8)
410				marginLeft = ($this.css('margin-left') === 'auto') ? 0 : parseInt($this.css('margin-left'), 10);
411				marginTop = ($this.css('margin-top') === 'auto') ? 0 : parseInt($this.css('margin-top'), 10);
412
413				offsetLeft = $this.offset().left - marginLeft - scrollLeft;
414				offsetTop = $this.offset().top - marginTop - scrollTop;
415				
416				// Calculate the offset parent
417				$this.parents().each(function() {
418					var $this = $(this);
419
420					if ($this.data('stellar-offset-parent') === true) {
421						parentOffsetLeft = tempParentOffsetLeft;
422						parentOffsetTop = tempParentOffsetTop;
423						$offsetParent = $this;
424
425						return false;
426					} else {
427						tempParentOffsetLeft += $this.position().left;
428						tempParentOffsetTop += $this.position().top;
429					}
430				});
431
432				// Detect the offsets
433				horizontalOffset = ($this.data('stellar-horizontal-offset') !== undefined ? $this.data('stellar-horizontal-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-horizontal-offset') !== undefined ? $offsetParent.data('stellar-horizontal-offset') : self.horizontalOffset));
434				verticalOffset = ($this.data('stellar-vertical-offset') !== undefined ? $this.data('stellar-vertical-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-vertical-offset') !== undefined ? $offsetParent.data('stellar-vertical-offset') : self.verticalOffset));
435
436				self.backgrounds.push({
437					$element: $this,
438					$offsetParent: $offsetParent,
439					isFixed: $this.css('background-attachment') === 'fixed',
440					horizontalOffset: horizontalOffset,
441					verticalOffset: verticalOffset,
442					startingValueLeft: backgroundPosition[0],
443					startingValueTop: backgroundPosition[1],
444					startingBackgroundPositionLeft: (isNaN(parseInt(backgroundPosition[0], 10)) ? 0 : parseInt(backgroundPosition[0], 10)),
445					startingBackgroundPositionTop: (isNaN(parseInt(backgroundPosition[1], 10)) ? 0 : parseInt(backgroundPosition[1], 10)),
446					startingPositionLeft: $this.position().left,
447					startingPositionTop: $this.position().top,
448					startingOffsetLeft: offsetLeft,
449					startingOffsetTop: offsetTop,
450					parentOffsetLeft: parentOffsetLeft,
451					parentOffsetTop: parentOffsetTop,
452					stellarRatio: ($this.data('stellar-background-ratio') === undefined ? 1 : $this.data('stellar-background-ratio'))
453				});
454			});
455		},
456		_reset: function() {
457			var particle,
458				startingPositionLeft,
459				startingPositionTop,
460				background,
461				i;
462
463			for (i = this.particles.length - 1; i >= 0; i--) {
464				particle = this.particles[i];
465				startingPositionLeft = particle.$element.data('stellar-startingLeft');
466				startingPositionTop = particle.$element.data('stellar-startingTop');
467
468				this._setPosition(particle.$element, startingPositionLeft, startingPositionLeft, startingPositionTop, startingPositionTop);
469
470				this.options.showElement(particle.$element);
471
472				particle.$element.data('stellar-startingLeft', null).data('stellar-elementIsActive', null).data('stellar-backgroundIsActive', null);
473			}
474
475			for (i = this.backgrounds.length - 1; i >= 0; i--) {
476				background = this.backgrounds[i];
477
478				background.$element.data('stellar-backgroundStartingLeft', null).data('stellar-backgroundStartingTop', null);
479
480				setBackgroundPosition(background.$element, background.startingValueLeft, background.startingValueTop);
481			}
482		},
483		destroy: function() {
484			this._reset();
485
486			this.$scrollElement.unbind('resize.' + this.name).unbind('scroll.' + this.name);
487			this._animationLoop = $.noop;
488
489			$(window).unbind('load.' + this.name).unbind('resize.' + this.name);
490		},
491		_setOffsets: function() {
492			var self = this,
493				$window = $(window);
494
495			$window.unbind('resize.horizontal-' + this.name).unbind('resize.vertical-' + this.name);
496
497			if (typeof this.options.horizontalOffset === 'function') {
498				this.horizontalOffset = this.options.horizontalOffset();
499				$window.bind('resize.horizontal-' + this.name, function() {
500					self.horizontalOffset = self.options.horizontalOffset();
501				});
502			} else {
503				this.horizontalOffset = this.options.horizontalOffset;
504			}
505
506			if (typeof this.options.verticalOffset === 'function') {
507				this.verticalOffset = this.options.verticalOffset();
508				$window.bind('resize.vertical-' + this.name, function() {
509					self.verticalOffset = self.options.verticalOffset();
510				});
511			} else {
512				this.verticalOffset = this.options.verticalOffset;
513			}
514		},
515		_repositionElements: function() {
516			var scrollLeft = this._getScrollLeft(),
517				scrollTop = this._getScrollTop(),
518				horizontalOffset,
519				verticalOffset,
520				particle,
521				fixedRatioOffset,
522				background,
523				bgLeft,
524				bgTop,
525				isVisibleVertical = true,
526				isVisibleHorizontal = true,
527				newPositionLeft,
528				newPositionTop,
529				newOffsetLeft,
530				newOffsetTop,
531				i;
532
533			// First check that the scroll position or container size has changed
534			if (this.currentScrollLeft === scrollLeft && this.currentScrollTop === scrollTop && this.currentWidth === this.viewportWidth && this.currentHeight === this.viewportHeight) {
535				return;
536			} else {
537				this.currentScrollLeft = scrollLeft;
538				this.currentScrollTop = scrollTop;
539				this.currentWidth = this.viewportWidth;
540				this.currentHeight = this.viewportHeight;
541			}
542
543			// Reposition elements
544			for (i = this.particles.length - 1; i >= 0; i--) {
545				particle = this.particles[i];
546
547				fixedRatioOffset = (particle.isFixed ? 1 : 0);
548
549				// Calculate position, then calculate what the particle's new offset will be (for visibility check)
550				if (this.options.horizontalScrolling) {
551					newPositionLeft = (scrollLeft + particle.horizontalOffset + this.viewportOffsetLeft + particle.startingPositionLeft - particle.startingOffsetLeft + particle.parentOffsetLeft) * -(particle.stellarRatio + fixedRatioOffset - 1) + particle.startingPositionLeft;
552					newOffsetLeft = newPositionLeft - particle.startingPositionLeft + particle.startingOffsetLeft;
553				} else {
554					newPositionLeft = particle.startingPositionLeft;
555					newOffsetLeft = particle.startingOffsetLeft;
556				}
557
558				if (this.options.verticalScrolling) {
559					newPositionTop = (scrollTop + particle.verticalOffset + this.viewportOffsetTop + particle.startingPositionTop - particle.startingOffsetTop + particle.parentOffsetTop) * -(particle.stellarRatio + fixedRatioOffset - 1) + particle.startingPositionTop;
560					newOffsetTop = newPositionTop - particle.startingPositionTop + particle.startingOffsetTop;
561				} else {
562					newPositionTop = particle.startingPositionTop;
563					newOffsetTop = particle.startingOffsetTop;
564				}
565
566				// Check visibility
567				if (this.options.hideDistantElements) {
568					isVisibleHorizontal = !this.options.horizontalScrolling || newOffsetLeft + particle.width > (particle.isFixed ? 0 : scrollLeft) && newOffsetLeft < (particle.isFixed ? 0 : scrollLeft) + this.viewportWidth + this.viewportOffsetLeft;
569					isVisibleVertical = !this.options.verticalScrolling || newOffsetTop + particle.height > (particle.isFixed ? 0 : scrollTop) && newOffsetTop < (particle.isFixed ? 0 : scrollTop) + this.viewportHeight + this.viewportOffsetTop;
570				}
571
572				if (isVisibleHorizontal && isVisibleVertical) {
573					if (particle.isHidden) {
574						this.options.showElement(particle.$element);
575						particle.isHidden = false;
576					}
577
578					this._setPosition(particle.$element, newPositionLeft, particle.startingPositionLeft, newPositionTop, particle.startingPositionTop);
579				} else {
580					if (!particle.isHidden) {
581						this.options.hideElement(particle.$element);
582						particle.isHidden = true;
583					}
584				}
585			}
586
587			// Reposition backgrounds
588			for (i = this.backgrounds.length - 1; i >= 0; i--) {
589				background = this.backgrounds[i];
590
591				fixedRatioOffset = (background.isFixed ? 0 : 1);
592				bgLeft = (this.options.horizontalScrolling ? (scrollLeft + background.horizontalOffset - this.viewportOffsetLeft - background.startingOffsetLeft + background.parentOffsetLeft - background.startingBackgroundPositionLeft) * (fixedRatioOffset - background.stellarRatio) + 'px' : background.startingValueLeft);
593				bgTop = (this.options.verticalScrolling ? (scrollTop + background.verticalOffset - this.viewportOffsetTop - background.startingOffsetTop + background.parentOffsetTop - background.startingBackgroundPositionTop) * (fixedRatioOffset - background.stellarRatio) + 'px' : background.startingValueTop);
594
595				setBackgroundPosition(background.$element, bgLeft, bgTop);
596			}
597		},
598		_handleScrollEvent: function() {
599			var self = this,
600				ticking = false;
601
602			var update = function() {
603				self._repositionElements();
604				ticking = false;
605			};
606
607			var requestTick = function() {
608				if (!ticking) {
609					requestAnimFrame(update);
610					ticking = true;
611				}
612			};
613			
614			this.$scrollElement.bind('scroll.' + this.name, requestTick);
615			requestTick();
616		},
617		_startAnimationLoop: function() {
618			var self = this;
619
620			this._animationLoop = function() {
621				requestAnimFrame(self._animationLoop);
622				self._repositionElements();
623			};
624			this._animationLoop();
625		}
626	};
627
628	$.fn[pluginName] = function (options) {
629		var args = arguments;
630		if (options === undefined || typeof options === 'object') {
631			return this.each(function () {
632				if (!$.data(this, 'plugin_' + pluginName)) {
633					$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
634				}
635			});
636		} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
637			return this.each(function () {
638				var instance = $.data(this, 'plugin_' + pluginName);
639				if (instance instanceof Plugin && typeof instance[options] === 'function') {
640					instance[options].apply(instance, Array.prototype.slice.call(args, 1));
641				}
642				if (options === 'destroy') {
643					$.data(this, 'plugin_' + pluginName, null);
644				}
645			});
646		}
647	};
648
649	$[pluginName] = function(options) {
650		var $window = $(window);
651		return $window.stellar.apply($window, Array.prototype.slice.call(arguments, 0));
652	};
653
654	// Expose the scroll and position property function hashes so they can be extended
655	$[pluginName].scrollProperty = scrollProperty;
656	$[pluginName].positionProperty = positionProperty;
657
658	// Expose the plugin class so it can be modified
659	window.Stellar = Plugin;
660}(jQuery, this, document));

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.