PageSourceSearch

https://1c.uz/local/templates/1c/js/jquery.overscroll.js?146003588422709

js 1c.uz collected 2026-10-07 02:58:58 UTC 22,709 bytes, 792 lines download raw bytes

1/**
2 * Overscroll v1.7.2
3 *  A jQuery Plugin that emulates the iPhone scrolling experience in a browser.
4 *  http://azoffdesign.com/overscroll
5 *
6 * Intended for use with the latest jQuery
7 *  http://code.jquery.com/jquery-latest.js
8 *  
9 * Copyright 2013, Jonathan Azoff
10 * Licensed under the MIT license.
11 *  https://github.com/azoff/overscroll/blob/master/mit.license
12 *
13 * For API documentation, see the README file
14 *  http://azof.fr/pYCzuM
15 *
16 * Date: Tuesday, March 18th 2013
17 */
18(function(global, dom, browser, math, wait, cancel, namespace, $, none){
19
20	// We want to run this plug-in in strict-mode
21	// so that we may benefit from its optimizations
22	'use strict';
23
24	// The key used to bind-instance specific data to an object
25	var datakey = 'overscroll';
26
27    // create <body> node if there's not one present (e.g., for test runners)
28	if (dom.body === null) {
29		dom.documentElement.appendChild(
30			dom.createElement('body')
31		);
32	}
33
34	// quick fix for IE 8 and below since getComputedStyle() is not supported
35	// TODO: find a better solution
36	if (!global.getComputedStyle) {
37		global.getComputedStyle = function (el, pseudo) {
38			this.el = el;
39			this.getPropertyValue = function (prop) {
40				var re = /(\-([a-z]){1})/g;
41				if (prop == 'float') prop = 'styleFloat';
42				if (re.test(prop)) {
43					prop = prop.replace(re, function () {
44						return arguments[2].toUpperCase();
45					});
46				}
47				return el.currentStyle[prop] ? el.currentStyle[prop] : null;
48			};
49			return this;
50		};
51	}
52
53	// runs feature detection for overscroll
54	var compat = {
55		animate: (function(){
56			var fn = global.requestAnimationFrame    ||
57				global.webkitRequestAnimationFrame ||
58				global.mozRequestAnimationFrame    ||
59				global.oRequestAnimationFrame      ||
60				global.msRequestAnimationFrame     ||
61				function(callback) { wait(callback, 1000/60); };
62			return function(callback) {
63				fn.call(global, callback);
64			};
65		})(),
66		overflowScrolling: (function(){
67			var style = '';
68			var div = dom.createElement('div');
69			var prefixes = ['webkit', 'moz', 'o', 'ms'];
70			dom.body.appendChild(div);
71			$.each(prefixes, function(i, prefix){
72				div.style[prefix + 'OverflowScrolling'] = 'touch';
73			});
74			div.style.overflowScrolling = 'touch';
75			var computedStyle = global.getComputedStyle(div);
76			if (!!computedStyle.overflowScrolling) {
77				style = 'overflow-scrolling';
78			} else {
79				$.each(prefixes, function(i, prefix){
80					if (!!computedStyle[prefix + 'OverflowScrolling']) {
81						style = '-' + prefix + '-overflow-scrolling';
82					}
83					return !style;
84				});
85			}
86			div.parentNode.removeChild(div);
87			return style;
88		})(),
89		cursor: (function() {
90			var div = dom.createElement('div');
91			var prefixes = ['webkit', 'moz'];
92			var gmail = 'https://mail.google.com/mail/images/2/';
93			var style = {
94				grab:     'url('+gmail+'openhand.cur), move',
95				grabbing: 'url('+gmail+'closedhand.cur), move'
96			};
97			dom.body.appendChild(div);
98			$.each(prefixes, function(i, prefix){
99				var found, cursor = '-' + prefix + '-grab';
100				div.style.cursor = cursor;
101				var computedStyle = global.getComputedStyle(div);
102				found = computedStyle.cursor === cursor;
103				if (found) {
104					style = {
105						grab:     '-' + prefix + '-grab',
106						grabbing: '-' + prefix + '-grabbing'
107					};
108				}
109				return !found;
110			});
111			div.parentNode.removeChild(div);
112			return style;
113		})()
114	};
115
116	// These are all the events that could possibly
117	// be used by the plug-in
118	var events = {
119		drag:       'mousemove touchmove',
120		end:        'mouseup mouseleave click touchend touchcancel',
121		hover:      'mouseenter mouseleave',
122		ignored:    'select dragstart drag',
123		scroll:     'scroll',
124		start:      'mousedown touchstart',
125		wheel:      'mousewheel DOMMouseScroll'
126	};
127
128	// These settings are used to tweak drift settings
129	// for the plug-in
130	var settings = {
131		captureThreshold:   3,
132		driftDecay:         1.1,
133		driftSequences:     22,
134		driftTimeout:       100,
135		scrollDelta:        15,
136		thumbOpacity:       0.7,
137		thumbThickness:     6,
138		thumbTimeout:       400,
139		wheelDelta:         20,
140		wheelTicks:        120
141	};
142
143	// These defaults are used to complement any options
144	// passed into the plug-in entry point
145	var defaults = {
146		cancelOn:       'select,input,textarea',
147		direction:      'multi',
148		dragHold:       false,
149		hoverThumbs:    false,
150		scrollDelta:    settings.scrollDelta,
151		showThumbs:     true,
152		persistThumbs:  false,
153		captureWheel:   true,
154		wheelDelta:     settings.wheelDelta,
155		wheelDirection: 'multi',
156		zIndex:         999
157	};
158
159	// Triggers a DOM event on the overscrolled element.
160	// All events are namespaced under the overscroll name
161	function triggerEvent(event, target) {
162		target.trigger('overscroll:' + event);
163	}
164
165	// Utility function to return a timestamp
166	function time() {
167		return (new Date()).getTime();
168	}
169
170	// Captures the position from an event, modifies the properties
171	// of the second argument to persist the position, and then
172	// returns the modified object
173	function capturePosition(event, position, index) {
174		position.x = event.pageX;
175		position.y = event.pageY;
176		position.time = time();
177		position.index = index;
178		return position;
179	}
180
181	// Used to move the thumbs around an overscrolled element
182	function moveThumbs(thumbs, sizing, left, top) {
183
184		var ml, mt;
185
186		if (thumbs && thumbs.added) {
187			if (thumbs.horizontal) {
188				ml = left * (1 + sizing.container.width / sizing.container.scrollWidth);
189				mt = top + sizing.thumbs.horizontal.top;
190				thumbs.horizontal.css('margin', mt + 'px 0 0 ' + ml + 'px');
191			}
192			if (thumbs.vertical) {
193				ml = left + sizing.thumbs.vertical.left;
194				mt = top * (1 + sizing.container.height / sizing.container.scrollHeight);
195				thumbs.vertical.css('margin', mt + 'px 0 0 ' + ml + 'px');
196			}
197		}
198
199	}
200
201	// Used to toggle the thumbs on and off
202	// of an overscrolled element
203	function toggleThumbs(thumbs, options, dragging) {
204		if (thumbs && thumbs.added && !options.persistThumbs) {
205			if (dragging) {
206				if (thumbs.vertical) {
207					thumbs.vertical.stop(true, true).fadeTo('fast', settings.thumbOpacity);
208				}
209				if (thumbs.horizontal) {
210					thumbs.horizontal.stop(true, true).fadeTo('fast', settings.thumbOpacity);
211				}
212			} else {
213				if (thumbs.vertical) {
214					thumbs.vertical.fadeTo('fast', 0);
215				}
216				if (thumbs.horizontal) {
217					thumbs.horizontal.fadeTo('fast', 0);
218				}
219			}
220		}
221	}
222
223	// Defers click event listeners to after a mouseup event.
224	// Used to avoid unintentional clicks
225	function deferClick(target) {
226		var clicks, key = 'events';
227		var events = $._data ? $._data(target[0], key) : target.data(key);
228		if (events && events.click) {
229			clicks = events.click.slice();
230			target.off('click').one('click', function(){
231				$.each(clicks, function(i, click){
232					target.click(click);
233				}); return false;
234			});
235		}
236	}
237
238	// Toggles thumbs on hover. This event is only triggered
239	// if the hoverThumbs option is set
240	function hover(event) {
241		var data = event.data,
242		thumbs   = data.thumbs,
243		options  = data.options,
244		dragging = event.type === 'mouseenter';
245		toggleThumbs(thumbs, options, dragging);
246	}
247
248	// This function is only ever used when the overscrolled element
249	// scrolled outside of the scope of this plugin.
250	function scroll(event) {
251		var data = event.data;
252		if (!data.flags.dragged) {
253			/*jshint validthis:true */
254			moveThumbs(data.thumbs, data.sizing, this.scrollLeft, this.scrollTop);
255		}
256	}
257
258	// handles mouse wheel scroll events
259	function wheel(event) {
260
261		// prevent any default wheel behavior
262		event.preventDefault();
263
264		var data = event.data,
265		options = data.options,
266		sizing = data.sizing,
267		thumbs = data.thumbs,
268		dwheel = data.wheel,
269		flags = data.flags,
270		original = event.originalEvent,
271		delta = 0, deltaX = 0, deltaY = 0;
272
273		// stop any drifts
274		flags.drifting = false;
275
276		// normalize the wheel ticks
277		if (original.detail) {
278			delta = -original.detail;
279			if (original.detailX) {
280				deltaX = -original.detailX;
281			}
282			if (original.detailY) {
283				deltaY = -original.detailY;
284			}
285		} else if (original.wheelDelta) {
286			delta = original.wheelDelta / settings.wheelTicks;
287			if (original.wheelDeltaX) {
288				deltaX = original.wheelDeltaX / settings.wheelTicks;
289			}
290			if (original.wheelDeltaY) {
291				deltaY = original.wheelDeltaY / settings.wheelTicks;
292			}
293		}
294
295		// apply a pixel delta to each tick
296		delta  *= options.wheelDelta;
297		deltaX *= options.wheelDelta;
298		deltaY *= options.wheelDelta;
299
300		// initialize flags if this is the first tick
301		if (!dwheel) {
302			data.target.data(datakey).dragging = flags.dragging = true;
303			data.wheel = dwheel = { timeout: null };
304			toggleThumbs(thumbs, options, true);
305		}
306
307		// actually modify scroll offsets
308		if (options.wheelDirection === 'vertical'){
309			/*jshint validthis:true */
310			this.scrollTop -= delta;
311		} else if ( options.wheelDirection === 'horizontal') {
312			this.scrollLeft -= delta;
313		} else {
314			this.scrollLeft -= deltaX;
315			this.scrollTop  -= deltaY || delta;
316		}
317
318		if (dwheel.timeout) { cancel(dwheel.timeout); }
319
320		moveThumbs(thumbs, sizing, this.scrollLeft, this.scrollTop);
321
322		dwheel.timeout = wait(function() {
323			data.target.data(datakey).dragging = flags.dragging = false;
324			toggleThumbs(thumbs, options, data.wheel = null);
325		}, settings.thumbTimeout);
326
327	}
328
329	// updates the current scroll offset during a mouse move
330	function drag(event) {
331
332		event.preventDefault();
333
334		var data = event.data,
335		touches  = event.originalEvent.touches,
336		options  = data.options,
337		sizing   = data.sizing,
338		thumbs   = data.thumbs,
339		position = data.position,
340		flags    = data.flags,
341		target   = data.target.get(0);
342
343
344		// correct page coordinates for touch devices
345		if (touches && touches.length) {
346			event = touches[0];
347		}
348
349		if (!flags.dragged) {
350			toggleThumbs(thumbs, options, true);
351		}
352
353		flags.dragged = true;
354
355		if (options.direction !== 'vertical') {
356			target.scrollLeft -= (event.pageX - position.x);
357		}
358
359		if (data.options.direction !== 'horizontal') {
360			target.scrollTop -= (event.pageY - position.y);
361		}
362
363		capturePosition(event, data.position);
364
365		if (--data.capture.index <= 0) {
366			data.target.data(datakey).dragging = flags.dragging = true;
367			capturePosition(event, data.capture, settings.captureThreshold);
368		}
369
370		moveThumbs(thumbs, sizing, target.scrollLeft, target.scrollTop);
371
372	}
373
374	// sends the overscrolled element into a drift
375	function drift(target, event, callback) {
376
377		var data   = event.data, dx, dy, xMod, yMod,
378		capture    = data.capture,
379		options    = data.options,
380		sizing     = data.sizing,
381		thumbs     = data.thumbs,
382		elapsed    = time() - capture.time,
383		scrollLeft = target.scrollLeft,
384		scrollTop  = target.scrollTop,
385		decay      = settings.driftDecay;
386
387		// only drift if enough time has passed since
388		// the last capture event
389		if (elapsed > settings.driftTimeout) {
390			callback(data); return;
391		}
392
393		// determine offset between last capture and current time
394		dx = options.scrollDelta * (event.pageX - capture.x);
395		dy = options.scrollDelta * (event.pageY - capture.y);
396
397		// update target scroll offsets
398		if (options.direction !== 'vertical') {
399			scrollLeft -= dx;
400		} if (options.direction !== 'horizontal') {
401			scrollTop -= dy;
402		}
403
404		// split the distance to travel into a set of sequences
405		xMod = dx / settings.driftSequences;
406		yMod = dy / settings.driftSequences;
407
408		triggerEvent('driftstart', data.target);
409
410		data.drifting = true;
411
412		// animate the drift sequence
413		compat.animate(function render() {
414			if (data.drifting) {
415				var min = 1, max = -1;
416				data.drifting = false;
417				if (yMod > min && target.scrollTop > scrollTop || yMod < max && target.scrollTop < scrollTop) {
418					data.drifting = true;
419					target.scrollTop -= yMod;
420					yMod /= decay;
421				}
422				if (xMod > min && target.scrollLeft > scrollLeft || xMod < max && target.scrollLeft < scrollLeft) {
423					data.drifting = true;
424					target.scrollLeft -= xMod;
425					xMod /= decay;
426				}
427				moveThumbs(thumbs, sizing, target.scrollLeft, target.scrollTop);
428				compat.animate(render);
429			} else {
430				triggerEvent('driftend', data.target);
431				callback(data);
432			}
433		});
434
435	}
436
437	// starts the drag operation and binds the mouse move handler
438	function start(event) {
439
440		var data = event.data,
441		touches  = event.originalEvent.touches,
442		target   = data.target,
443		dstart   = data.start = $(event.target),
444		flags    = data.flags;
445
446		// stop any drifts
447		flags.drifting = false;
448
449		// only start drag if the user has not explictly banned it.
450		if (dstart.size() && !dstart.is(data.options.cancelOn)) {
451
452			// without this the simple "click" event won't be recognized on touch clients
453			if (!touches) { event.preventDefault(); }
454
455			if (!compat.overflowScrolling) {
456				target.css('cursor', compat.cursor.grabbing);
457				target.data(datakey).dragging = flags.dragging = flags.dragged = false;
458
459				// apply the drag listeners to the doc or target
460				if(data.options.dragHold) {
461					$(document).on(events.drag, data, drag);
462				} else {
463					target.on(events.drag, data, drag);
464				}
465			}
466
467			data.position = capturePosition(event, {});
468			data.capture = capturePosition(event, {}, settings.captureThreshold);
469			triggerEvent('dragstart', target);
470
471		}
472
473	}
474
475	// ends the drag operation and unbinds the mouse move handler
476	function stop(event) {
477
478		var data = event.data,
479		target = data.target,
480		options = data.options,
481		flags = data.flags,
482		thumbs = data.thumbs,
483
484		// hides the thumbs after the animation is done
485		done = function () {
486			if (thumbs && !options.hoverThumbs) {
487				toggleThumbs(thumbs, options, false);
488			}
489		};
490
491		// remove drag listeners from doc or target
492		if(options.dragHold) {
493			$(document).unbind(events.drag, drag);
494		} else {
495			target.unbind(events.drag, drag);
496		}
497
498		// only fire events and drift if we started with a
499		// valid position
500		if (data.position) {
501
502			triggerEvent('dragend', target);
503
504			// only drift if a drag passed our threshold
505			if (flags.dragging && !compat.overflowScrolling) {
506				drift(target.get(0), event, done);
507			} else {
508				done();
509			}
510
511		}
512
513		// only if we moved, and the mouse down is the same as
514		// the mouse up target do we defer the event
515		if (flags.dragging && !compat.overflowScrolling && data.start && data.start.is(event.target)) {
516			deferClick(data.start);
517		}
518
519		// clear all internal flags and settings
520		target.data(datakey).dragging =
521			data.start     =
522			data.capture   =
523			data.position  =
524			flags.dragged  =
525			flags.dragging = false;
526
527		// set the cursor back to normal
528		target.css('cursor', compat.cursor.grab);
529
530	}
531
532	// Ensures that a full set of options are provided
533	// for the plug-in. Also does some validation
534	function getOptions(options) {
535
536		// fill in missing values with defaults
537		options = $.extend({}, defaults, options);
538
539		// check for inconsistent directional restrictions
540		if (options.direction !== 'multi' && options.direction !== options.wheelDirection) {
541			options.wheelDirection = options.direction;
542		}
543
544		// ensure positive values for deltas
545		options.scrollDelta = math.abs(parseFloat(options.scrollDelta));
546		options.wheelDelta  = math.abs(parseFloat(options.wheelDelta));
547
548		// fix values for scroll offset
549		options.scrollLeft = options.scrollLeft === none ? null : math.abs(parseFloat(options.scrollLeft));
550		options.scrollTop  = options.scrollTop  === none ? null : math.abs(parseFloat(options.scrollTop));
551
552		return options;
553
554	}
555
556	// Returns the sizing information (bounding box) for the
557	// target DOM element
558	function getSizing(target) {
559
560		var $target  = $(target),
561		width        = $target.width(),
562		height       = $target.height(),
563		scrollWidth  = width >= target.scrollWidth ? width : target.scrollWidth,
564		scrollHeight = height >= target.scrollHeight ? height : target.scrollHeight,
565		hasScroll    = scrollWidth > width || scrollHeight > height;
566
567		return {
568			valid: hasScroll,
569			container: {
570				width: width,
571				height: height,
572				scrollWidth: scrollWidth,
573				scrollHeight: scrollHeight
574			},
575			thumbs: {
576				horizontal: {
577					width: width * width / scrollWidth,
578					height: settings.thumbThickness,
579					corner: settings.thumbThickness / 2,
580					left: 0,
581					top: height - settings.thumbThickness
582				},
583				vertical: {
584					width: settings.thumbThickness,
585					height: height * height / scrollHeight,
586					corner: settings.thumbThickness / 2,
587					left: width - settings.thumbThickness,
588					top: 0
589				}
590			}
591		};
592
593	}
594
595	// Attempts to get (or implicitly creates) the
596	// remover function for the target passed
597	// in as an argument
598	function getRemover(target, orCreate) {
599
600		var $target = $(target), thumbs,
601		data        = $target.data(datakey) || {},
602		style       = $target.attr('style'),
603		fallback    = orCreate ? function () {
604
605			data = $target.data(datakey);
606			thumbs = data.thumbs;
607
608			// restore original styles (if any)
609			if (style) {
610				$target.attr('style', style);
611			} else {
612				$target.removeAttr('style');
613			}
614
615			// remove any created thumbs
616			if (thumbs) {
617				if (thumbs.horizontal) { thumbs.horizontal.remove(); }
618				if (thumbs.vertical)   { thumbs.vertical.remove();   }
619			}
620
621			// remove any bound overscroll events and data
622			$target
623				.removeData(datakey)
624				.off(events.wheel,      wheel)
625				.off(events.start,      start)
626				.off(events.end,        stop)
627				.off(events.ignored,    ignore);
628
629		} : $.noop;
630
631		return $.isFunction(data.remover) ? data.remover : fallback;
632
633	}
634
635	// Genterates CSS specific to a particular thumb.
636	// It requires sizing data and options
637	function getThumbCss(size, options) {
638		return {
639			position: 'absolute',
640			opacity: options.persistThumbs ? settings.thumbOpacity : 0,
641			'background-color': 'black',
642			width: size.width + 'px',
643			height: size.height + 'px',
644			'border-radius': size.corner + 'px',
645			'margin': size.top + 'px 0 0 ' + size.left + 'px',
646			'z-index': options.zIndex
647		};
648	}
649
650	// Creates the DOM elements used as "thumbs" within
651	// the target container.
652	function createThumbs(target, sizing, options) {
653
654		var div = '<div/>',
655		thumbs  = {},
656		css     = false;
657
658		if (sizing.container.scrollWidth > 0 && options.direction !== 'vertical') {
659			css = getThumbCss(sizing.thumbs.horizontal, options);
660			thumbs.horizontal = $(div).css(css).addClass('resizable-horizontal').prependTo(target);
661		}
662
663		if (sizing.container.scrollHeight > 0 && options.direction !== 'horizontal') {
664			css = getThumbCss(sizing.thumbs.vertical, options);
665			thumbs.vertical = $(div).css(css).prependTo(target);
666		}
667
668		thumbs.added = !!css;
669
670		return thumbs;
671
672	}
673
674	// ignores events on the overscroll element
675	function ignore(event) {
676		event.preventDefault();
677	}
678
679	// This function takes a jQuery element, some
680	// (optional) options, and sets up event metadata
681	// for each instance the plug-in affects
682	function setup(target, options) {
683
684		// create initial data properties for this instance
685		options = getOptions(options);
686		var sizing = getSizing(target),
687		thumbs, data = {
688			options: options, sizing: sizing,
689			flags: { dragging: false },
690			remover: getRemover(target, true)
691		};
692
693		// only apply handlers if the overscrolled element
694		// actually has an area to scroll
695		if (sizing.valid) {
696			// provide a circular-reference, enable events, and
697			// apply any required CSS
698			data.target = target = $(target).css({
699				position: 'relative',
700				cursor: compat.cursor.grab
701			}).on(events.start, data, start)
702				.on(events.end, data, stop)
703				.on(events.ignored, data, ignore);
704
705			// apply the stop listeners for drag end
706			if(options.dragHold) {
707				$(document).on(events.end, data, stop);
708			} else {
709				data.target.on(events.end, data, stop);
710			}
711
712			// apply any user-provided scroll offsets
713			if (options.scrollLeft !== null) {
714				target.scrollLeft(options.scrollLeft);
715			} if (options.scrollTop !== null) {
716				target.scrollTop(options.scrollTop);
717			}
718
719			// use native oversroll, if it exists
720			if (compat.overflowScrolling) {
721				target.css(compat.overflowScrolling, 'touch');
722			} else {
723				target.on(events.scroll, data, scroll);
724			}
725
726			// check to see if the user would like mousewheel support
727			if (options.captureWheel) {
728				target.on(events.wheel, data, wheel);
729			}
730
731			// add thumbs and listeners (if we're showing them)
732			if (options.showThumbs) {
733				if (compat.overflowScrolling) {
734					target.css('overflow', 'scroll');
735				} else {
736					target.css('overflow', 'hidden');
737					data.thumbs = thumbs = createThumbs(target, sizing, options);
738					if (thumbs.added) {
739						moveThumbs(thumbs, sizing, target.scrollLeft(), target.scrollTop());
740						if (options.hoverThumbs) {
741							target.on(events.hover, data, hover);
742						}
743					}
744				}
745			} else {
746				target.css('overflow', 'hidden');
747			}
748
749			target.data(datakey, data);
750		}
751
752	}
753
754	// Removes any event listeners and other instance-specific
755	// data from the target. It attempts to leave the target
756	// at the state it found it.
757	function teardown(target) {
758		getRemover(target)();
759	}
760
761	// This is the entry-point for enabling the plug-in;
762	// You can find it's exposure point at the end
763	// of this closure
764	function overscroll(options) {
765		/*jshint validthis:true */
766		return this.removeOverscroll().each(function() {
767			setup(this, options);
768		});
769	}
770
771	// This is the entry-point for disabling the plug-in;
772	// You can find it's exposure point at the end
773	// of this closure
774	function removeOverscroll() {
775		/*jshint validthis:true */
776		return this.each(function () {
777			teardown(this);
778		});
779	}
780
781	// Extend overscroll to expose settings to the user
782	overscroll.settings = settings;
783
784	// Extend jQuery's prototype to expose the plug-in.
785	// If the supports native overflowScrolling, overscroll will not
786	// attempt to override the browser's built in support
787	$.extend(namespace, {
788		overscroll:         overscroll,
789		removeOverscroll:   removeOverscroll
790	});
791
792})(window, document, navigator, Math, setTimeout, clearTimeout, jQuery.fn, 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.