PageSourceSearch

https://www.clearancejobsblog.com/wp-content/themes/cjwordpress-bl…/jquery.hc-sticky.js?ver=1.6.3

js clearancejobsblog.com collected 2026-10-03 20:34:34 UTC 21,292 bytes, 705 lines download raw bytes

1// jQuery HC-Sticky
2// =============
3// Version: 1.2.43
4// Copyright: Some Web Media
5// Author: Some Web Guy
6// Author URL: http://twitter.com/some_web_guy
7// Website: http://someweblog.com/
8// Plugin URL: https://github.com/somewebmedia/hc-sticky
9// License: Released under the MIT License www.opensource.org/licenses/mit-license.php
10// Description: Cross-browser jQuery plugin that makes any element attached to the page and always visible while you scroll.
11
12(function($, window, undefined) {
13	"use strict";
14
15	// console.log shortcut
16	var log = function(t){console.log(t)};
17
18	var $window = $(window),
19		document = window.document,
20		$document = $(document);
21
22	// detect IE version
23	var ie = (function(){var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i'); while (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]){}; return v > 4 ? v : undef})();
24
25	/*----------------------------------------------------
26						Global functions
27	----------------------------------------------------*/
28
29	// check for scroll direction and speed
30	var getScroll = function() {
31		var pageXOffset = window.pageXOffset !== undefined ? window.pageXOffset : (document.compatMode == "CSS1Compat" ? window.document.documentElement.scrollLeft : window.document.body.scrollLeft),
32			pageYOffset = window.pageYOffset !== undefined ? window.pageYOffset : (document.compatMode == "CSS1Compat" ? window.document.documentElement.scrollTop : window.document.body.scrollTop);
33
34		if (typeof getScroll.x == 'undefined') {
35			getScroll.x = pageXOffset;
36			getScroll.y = pageYOffset;
37		}
38		if (typeof getScroll.distanceX == 'undefined') {
39			getScroll.distanceX = pageXOffset;
40			getScroll.distanceY = pageYOffset;
41		} else {
42			getScroll.distanceX = pageXOffset - getScroll.x;
43			getScroll.distanceY = pageYOffset - getScroll.y;
44		}
45
46		var diffX = getScroll.x - pageXOffset,
47			diffY = getScroll.y - pageYOffset;
48
49		getScroll.direction = diffX < 0 ? 'right' :
50			diffX > 0 ? 'left' :
51			diffY <= 0 ? 'down' :
52			diffY > 0 ? 'up' : 'first';
53
54		getScroll.x = pageXOffset;
55		getScroll.y = pageYOffset;
56	};
57	$window.on('scroll', getScroll);
58
59
60	// little original style plugin
61	$.fn.style = function(style) {
62		if (!style) return null;
63
64		var $this = $(this),
65			value;
66
67		// clone element
68		var $clone = $this.clone().css('display','none');
69		// randomize the name of cloned radio buttons, otherwise selections get screwed
70		$clone.find('input:radio').attr('name','copy-' + Math.floor((Math.random()*100)+1));
71		// insert clone to DOM
72		$this.after($clone);
73
74		var getStyle = function(el, style){
75			var val;
76			if (el.currentStyle) {
77				// replace dashes with capitalized letter, e.g. padding-left to paddingLeft
78				val = el.currentStyle[style.replace(/-\w/g, function(s){return s.toUpperCase().replace('-','')})];
79			} else if (window.getComputedStyle) {
80				val = document.defaultView.getComputedStyle(el,null).getPropertyValue(style);
81			}
82			// check for margin:auto
83			val = (/margin/g.test(style)) ? ((parseInt(val) === $this[0].offsetLeft) ? val : 'auto') : val;
84			return val;
85		};
86
87		if (typeof style == 'string') {
88			value = getStyle($clone[0], style);
89		} else {
90			value = {};
91			$.each(style, function(i, s){
92				value[s] = getStyle($clone[0], s);
93			});
94		}
95
96		// destroy clone
97		$clone.remove();
98
99		return value || null;
100	};
101
102
103	/*----------------------------------------------------
104						jQuery plugin
105	----------------------------------------------------*/
106
107	$.fn.extend({
108
109		hcSticky: function(options) {
110
111			// check if selected element exist in DOM, user doesn't have to worry about that
112			if (this.length == 0) return this;
113
114			this.pluginOptions('hcSticky', {
115				top: 0,
116				bottom: 0,
117				bottomEnd: 0,
118				innerTop: 0,
119				innerSticker: null,
120				className: 'sticky',
121				wrapperClassName: 'wrapper-sticky',
122				stickTo: null,
123				responsive: true,
124				followScroll: true,
125				offResolutions: null,
126				onStart: $.noop,
127				onStop: $.noop,
128				on: true,
129				fn: null // used only by the plugin
130			}, options || {}, {
131				reinit: function(){
132					// just call itself again
133					$(this).hcSticky();
134				},
135				stop: function(){
136					$(this).pluginOptions('hcSticky', {on: false}).each(function(){
137						var $this = $(this),
138							options = $this.pluginOptions('hcSticky'),
139							$wrapper = $this.parent('.' + options.wrapperClassName);
140
141						// set current position
142						var top = $this.offset().top - $wrapper.offset().top;
143						$this.css({
144							position: 'absolute',
145							top: top,
146							bottom: 'auto',
147							left: 'auto',
148							right: 'auto'
149						}).removeClass(options.className);
150					});
151				},
152				off: function(){
153					$(this).pluginOptions('hcSticky', {on: false}).each(function(){
154						var $this = $(this),
155							options = $this.pluginOptions('hcSticky'),
156							$wrapper = $this.parent('.' + options.wrapperClassName);
157
158						// clear position
159						$this.css({
160							position: 'relative',
161							top: 'auto',
162							bottom: 'auto',
163							left: 'auto',
164							right: 'auto'
165						}).removeClass(options.className);
166
167						$wrapper.css('height', 'auto');
168
169						/* Added by me */
170						/* Clear width */
171						$this.css('width', '');
172						/**/
173					});
174				},
175				on: function(){
176					$(this).each(function(){
177						$(this).pluginOptions('hcSticky', {
178							on: true,
179							remember: {
180								offsetTop: $window.scrollTop()
181							}
182						}).hcSticky();
183					});
184				},
185				destroy: function(){
186					var $this = $(this),
187						options = $this.pluginOptions('hcSticky'),
188						$wrapper = $this.parent('.' + options.wrapperClassName);
189
190					// reset position to original
191					$this.removeData('hcStickyInit').css({
192						position: $wrapper.css('position'),
193						top: $wrapper.css('top'),
194						bottom: $wrapper.css('bottom'),
195						left: $wrapper.css('left'),
196						right: $wrapper.css('right')
197					}).removeClass(options.className);
198
199					// remove events
200					$window.off('resize', options.fn.resize).off('scroll', options.fn.scroll);
201
202					// destroy wrapper
203					$this.unwrap();
204				}
205			});
206
207			// on/off settings
208			if (options && typeof options.on != 'undefined') {
209				if (options.on) {
210					this.hcSticky('on');
211				} else {
212					this.hcSticky('off');
213				}
214			}
215
216			// stop on commands
217			if (typeof options == 'string') return this;
218
219			// do our thing
220			return this.each(function(){
221
222				var $this = $(this),
223					options = $this.pluginOptions('hcSticky');
224
225				var $wrapper = (function(){ // wrapper exists
226						var $this_wrapper = $this.parent('.' + options.wrapperClassName);
227						if ($this_wrapper.length > 0) {
228							$this_wrapper.css({
229								'height': $this.outerHeight(true),
230								'width': (function(){
231									// check if wrapper already has width in %
232									var width = $this_wrapper.style('width');
233									if (width.indexOf('%') >= 0 || width == 'auto') {
234										if ($this.css('box-sizing') == 'border-box' || $this.css('-moz-box-sizing') == 'border-box') {
235											$this.css('width', $this_wrapper.width());
236										} else {
237											$this.css('width', $this_wrapper.width() - parseInt($this.css('padding-left') - parseInt($this.css('padding-right'))));
238										}
239										return width;
240									} else {
241										return $this.outerWidth(true);
242									}
243								})()
244							});
245							return $this_wrapper;
246						} else {
247							return false;
248						}
249					})() || (function(){ // wrapper doesn't exist
250
251						var this_css = $this.style(['width', 'margin-left', 'left', 'right', 'top', 'bottom', 'float', 'display']);
252						var display = $this.css('display');
253
254						var $this_wrapper = $('<div>', {
255							'class': options.wrapperClassName
256						}).css({
257							'display': display,
258							'height': $this.outerHeight(true),
259							'width': (function(){
260								if (this_css['width'].indexOf('%') >= 0 || (this_css['width'] == 'auto' && display != 'inline-block' && display != 'inline')) { // check if element has width in %
261									$this.css('width', parseFloat($this.css('width')));
262									return this_css['width'];
263								} else if (this_css['width'] == 'auto' && (display == 'inline-block' || display == 'inline')) {
264									return $this.width();
265								} else {
266									// check if margin is set to 'auto'
267									return (this_css['margin-left'] == 'auto') ? $this.outerWidth() : $this.outerWidth(true);
268								}
269							})(),
270							'margin': (this_css['margin-left']) ? 'auto' : null,
271							'position': (function(){
272								var position = $this.css('position');
273								return position == 'static' ? 'relative' : position;
274							})(),
275							'float': this_css['float'] || null,
276							'left': this_css['left'],
277							'right': this_css['right'],
278							'top': this_css['top'],
279							'bottom': this_css['bottom'],
280							'vertical-align': 'top'
281						});
282
283						$this.wrap($this_wrapper);
284
285						// ie7 inline-block fix
286						if (ie === 7) {
287							if ($('head').find('style#hcsticky-iefix').length === 0) {
288								$('<style id="hcsticky-iefix">.' + options.wrapperClassName + ' {zoom: 1;}</style>').appendTo('head');
289							}
290						}
291
292						// return appended element
293						return $this.parent();
294					})();
295
296
297				// check if we should go further
298				if ($this.data('hcStickyInit')) return;
299				// leave our mark
300				$this.data('hcStickyInit', true);
301
302
303				// check if referring element is document
304				var stickTo_document = options.stickTo && (options.stickTo == 'document' || (options.stickTo.nodeType && options.stickTo.nodeType == 9) || (typeof options.stickTo == 'object' && options.stickTo instanceof (typeof HTMLDocument != 'undefined' ? HTMLDocument : Document))) ? true : false;
305
306				// select container ;)
307				var $container = options.stickTo
308					? stickTo_document
309						? $document
310						: typeof options.stickTo == 'string'
311							? $wrapper.parents(options.stickTo) /* Modified by me */
312							: options.stickTo
313					: $wrapper.parent();
314
315				// clear sticky styles
316				$this.css({
317					top: 'auto',
318					bottom: 'auto',
319					left: 'auto',
320					right: 'auto'
321				});
322
323				// attach event on entire page load, maybe some images inside element has been loading, so chek height again
324				$window.load(function(){
325					if ($this.outerHeight(true) > $container.height()) {
326						$wrapper.css('height', $this.outerHeight(true));
327						$this.hcSticky('reinit');
328					}
329				});
330
331				// functions for attachiung and detaching sticky
332				var _setFixed = function(args) {
333						// check if already floating
334						if ($this.hasClass(options.className)) return;
335
336						// apply styles
337						args = args || {};
338						$this.css({
339							position: 'fixed',
340							top: args.top || 0,
341							left: args.left || $wrapper.offset().left
342						}).addClass(options.className);
343
344						// start event
345						options.onStart.apply($this[0]);
346						// add class to wrpaeer
347						$wrapper.addClass('sticky-active');
348					},
349					_reset = function(args) {
350						args = args || {};
351						args.position = args.position || 'absolute';
352						args.top = args.top || 0;
353						args.left = args.left || 0;
354
355						// check if we should apply css
356						if ($this.css('position') != 'fixed' && parseInt($this.css('top')) == args.top) return;
357
358						// apply styles
359						$this.css({
360							position: args.position,
361							top: args.top,
362							left: args.left
363						}).removeClass(options.className);
364
365						// stop event
366						options.onStop.apply($this[0]);
367						// remove class from wrpaeer
368						$wrapper.removeClass('sticky-active');
369					};
370
371				// sticky scroll function
372				var onScroll = function(init) {
373
374					// check if we need to run sticky
375	        if (!options.on || !$this.is(':visible')) return;
376
377	        // if the element is the same height or larger than the container then let's reset it so that it returns to the original position
378	        if ($this.outerHeight(true) >= $container.height()) {
379	            _reset();
380
381	            return;
382	        }
383
384					var top_spacing = (options.innerSticker) ? $(options.innerSticker).position().top : ((options.innerTop) ? options.innerTop : 0),
385						wrapper_inner_top = $wrapper.offset().top,
386						bottom_limit = $container.height() - options.bottomEnd + (stickTo_document ? 0 : wrapper_inner_top),
387						top_limit = $wrapper.offset().top - options.top + top_spacing,
388						this_height = $this.outerHeight(true) + options.bottom,
389						window_height = $window.height(),
390						offset_top = $window.scrollTop(),
391						this_document_top = $this.offset().top,
392						this_window_top = this_document_top - offset_top,
393						bottom_distance;
394
395
396					// if sticky has been restarted with on/off wait for it to reach top or bottom
397					if (typeof options.remember != 'undefined' && options.remember) {
398
399						var position_top = this_document_top - options.top - top_spacing;
400
401						if (this_height - top_spacing > window_height && options.followScroll) { // element bigger than window with follow scroll on
402
403							if (position_top < offset_top && offset_top + window_height <= position_top + $this.height()) {
404								// element is in the middle of the screen, let our primary calculations do the work
405								options.remember = false;
406							}
407
408						} else { // element smaller than window or follow scroll turned off
409
410							if (options.remember.offsetTop > position_top) {
411								// slide up
412								if (offset_top <= position_top) {
413									_setFixed({
414										top: options.top - top_spacing
415									});
416									options.remember = false;
417								}
418							} else {
419								// slide down
420								if (offset_top >= position_top) {
421									_setFixed({
422										top: options.top - top_spacing
423									});
424									options.remember = false;
425								}
426							}
427
428						}
429
430						return;
431					}
432
433
434					if (offset_top > top_limit) {
435
436						// http://geek-and-poke.com/geekandpoke/2012/7/27/simply-explained.html
437
438						if (bottom_limit + options.bottom - (options.followScroll && window_height < this_height ? 0 : options.top) <= offset_top + this_height - top_spacing - ((this_height - top_spacing > window_height - (top_limit - top_spacing) && options.followScroll) ? (((bottom_distance = this_height - window_height - top_spacing) > 0) ? bottom_distance : 0) : 0)) {
439							// bottom reached end
440							_reset({
441								top: bottom_limit - this_height + options.bottom - wrapper_inner_top
442							});
443						} else if (this_height - top_spacing > window_height && options.followScroll) {
444
445							if (this_window_top + this_height <= window_height) { // element bigger than window with follow scroll on
446
447								if (getScroll.direction == 'down') {
448									// scroll down
449									_setFixed({
450										top: window_height - this_height
451									});
452								} else {
453									// scroll up
454									if (this_window_top < 0 && $this.css('position') == 'fixed') {
455										_reset({
456											top: this_document_top - (top_limit + options.top - top_spacing) - getScroll.distanceY
457										});
458									}
459								}
460
461							} else { // element smaller than window or follow scroll turned off
462
463								if (getScroll.direction == 'up' && this_document_top >= offset_top + options.top - top_spacing) {
464									// scroll up
465									_setFixed({
466										top: options.top - top_spacing
467									});
468								} else if (getScroll.direction == 'down' && this_document_top + this_height > window_height && $this.css('position') == 'fixed') {
469									// scroll down
470									_reset({
471										top: this_document_top - (top_limit + options.top - top_spacing) - getScroll.distanceY
472									});
473								}
474
475							}
476						} else {
477							// starting (top) fixed position
478							_setFixed({
479								top: options.top - top_spacing
480							});
481						}
482					} else {
483						// reset
484						_reset();
485					}
486
487				};
488
489
490				// store resize data in case responsive is on
491				var resize_timeout = false,
492					$resize_clone = false;
493
494				var onResize = function() {
495
496					// check if sticky is attached to scroll event
497					attachScroll();
498
499					// check for off resolutions
500					checkResolutions();
501
502					// check if we need to run sticky
503					if (!options.on) return;
504
505					var setLeft = function(){
506						// set new left position
507						if ($this.css('position') == 'fixed') {
508							$this.css('left', $wrapper.offset().left);
509						} else {
510							$this.css('left', 0);
511						}
512					};
513
514					// check for width change (css media queries)
515					if (options.responsive) {
516						// clone element and make it invisible
517						if (!$resize_clone) {
518							$resize_clone = $this.clone().attr('style', '').css({
519								visibility: 'hidden',
520								height: 0,
521								overflow: 'hidden',
522								paddingTop: 0,
523								paddingBottom: 0,
524								marginTop: 0,
525								marginBottom: 0
526							});
527							$wrapper.after($resize_clone);
528						}
529
530						var wrapper_width = $wrapper.style('width');
531						var resize_clone_width = $resize_clone.style('width');
532
533						if (resize_clone_width == 'auto' && wrapper_width != 'auto') {
534							resize_clone_width = parseInt($this.css('width'));
535						}
536
537						// recalculate wrpaeer width
538						if (resize_clone_width != wrapper_width) {
539							$wrapper.width(resize_clone_width);
540						}
541
542						// clear previous timeout
543						if (resize_timeout) {
544							clearTimeout(resize_timeout);
545						}
546						// timedout destroing of cloned elements so we don't clone it again and again while resizing the window
547						resize_timeout = setTimeout(function() {
548							// clear timeout id
549							resize_timeout = false;
550							// destroy cloned element
551							$resize_clone.remove();
552							$resize_clone = false;
553						}, 250);
554					}
555
556					// set new left position
557					setLeft();
558
559					// recalculate inner element width (maybe original width was in %)
560					if ($this.outerWidth(true) != $wrapper.width()) {
561						var this_w = ($this.css('box-sizing') == 'border-box' || $this.css('-moz-box-sizing') == 'border-box')
562							? $wrapper.width()
563							: $wrapper.width() - parseInt($this.css('padding-left')) - parseInt($this.css('padding-right'));
564						// subtract margins
565						this_w = this_w - parseInt($this.css('margin-left')) - parseInt($this.css('margin-right'));
566						// set new width
567						$this.css('width', this_w);
568					}
569				};
570
571
572				// remember scroll and resize callbacks so we can attach and detach them
573				$this.pluginOptions('hcSticky', {fn: {
574					scroll: onScroll,
575					resize: onResize
576				}});
577
578
579				// check for off resolutions
580				var checkResolutions = function(){
581					if (options.offResolutions) {
582						// convert to array
583						if (!$.isArray(options.offResolutions)) {
584							options.offResolutions = [options.offResolutions];
585						}
586
587						var isOn = true;
588
589						$.each(options.offResolutions, function(i, rez){
590							if (rez < 0) {
591								// below
592								if ($window.width() < rez * -1) {
593									isOn = false;
594									$this.hcSticky('off');
595								}
596							} else {
597								// abowe
598								if ($window.width() > rez) {
599									isOn = false;
600									$this.hcSticky('off');
601								}
602							}
603						});
604
605						// turn on again
606						if (isOn && !options.on) {
607							$this.hcSticky('on');
608						}
609					}
610				};
611				checkResolutions();
612
613
614				// attach resize function to event
615				$window.on('resize', onResize);
616
617
618				// attaching scroll function to event
619				var attachScroll = function(){
620					var isAttached = false;
621					if ($._data(window, 'events').scroll != undefined) {
622						$.each($._data(window, 'events').scroll, function(i, f){
623							if (f.handler == options.fn.scroll) {
624								isAttached = true;
625							}
626						});
627					}
628					if (!isAttached) {
629						// run it once to disable glitching
630						options.fn.scroll(true);
631						// attach function to scroll event only once
632						$window.on('scroll', options.fn.scroll);
633					}
634				};
635				attachScroll();
636
637			});
638		}
639	});
640
641})(jQuery, this);
642
643
644
645// jQuery HC-PluginOptions
646// =============
647// Version: 1.0
648// Copyright: Some Web Media
649// Author: Some Web Guy
650// Author URL: http://twitter.com/some_web_guy
651// Website: http://someweblog.com/
652// License: Released under the MIT License www.opensource.org/licenses/mit-license.php
653
654(function($, undefined) {
655	"use strict";
656
657	$.fn.extend({
658
659		pluginOptions: function(pluginName, defaultOptions, userOptions, commands) {
660
661			// create object to store data
662			if (!this.data(pluginName)) this.data(pluginName, {});
663
664			// return options
665			if (pluginName && typeof defaultOptions == 'undefined') return this.data(pluginName).options;
666
667			// update
668			userOptions = userOptions || (defaultOptions || {});
669
670			if (typeof userOptions == 'object' || userOptions === undefined) {
671
672				// options
673				return this.each(function(){
674					var $this = $(this);
675
676					if (!$this.data(pluginName).options) {
677						// init our options and attach to element
678						$this.data(pluginName, {options: $.extend(defaultOptions, userOptions || {})});
679						// attach commands if any
680						if (commands) {
681							$this.data(pluginName).commands = commands;
682						}
683					} else {
684						// update existing options
685						$this.data(pluginName, $.extend($this.data(pluginName), {options: $.extend($this.data(pluginName).options, userOptions || {})}));
686					}
687				});
688
689			} else if (typeof userOptions == 'string') {
690
691				return this.each(function(){
692					$(this).data(pluginName).commands[userOptions].call(this);
693				});
694
695			} else {
696
697				return this;
698
699			}
700
701		}
702
703	});
704
705})(jQuery);

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.