PageSourceSearch

https://auf.org.uy/sitio/js/jail.js?v=0.0.2

js auf.org.uy collected 2026-10-02 03:51:58 UTC 12,141 bytes, 443 lines download raw bytes

1/*
2*  JAIL: jQuery Asynchronous Image Loader
3*
4* Copyright (c) 2011-12 Sebastiano Armeli-Battana (http://www.sebastianoarmelibattana.com)
5*
6* By Sebastiano Armeli-Battana (@sebarmeli)
7* Licensed under the MIT license.
8* https://github.com/sebarmeli/JAIL/blob/master/MIT-LICENSE.txt
9*
10* Tested with jQuery 1.3.2+ on FF 2+, Opera 10+, Safari 4+, Chrome 8+ on Win/Mac/Linux
11* and IE 6/7/8 on Win.
12*
13* Contributor : Derek Lindahl - @dlindahl
14*
15* @link http://github.com/sebarmeli/JAIL
16* @author Sebastiano Armeli-Battana
17* @date 14/10/2012
18* @version 1.0.0
19*
20*/
21;(function ( name, definition ){
22
23	var theModule = definition(jQuery),
24		hasDefine = typeof define === 'function' && define.amd;
25
26	if ( hasDefine ){  // AMD module
27
28		define( name , ['jquery'], theModule );
29		
30	}  else { // assign 'jail' to global objects
31		
32		( this.jQuery || this.$ || this )[name] = theModule;
33
34	}
35}( 'jail', function ($) {
36
37	var $window = $( window ),
38		
39		// Defaults parameters
40		defaults = {
41			id : 'jail',
42			timeout : 1,
43			effect : false,
44			speed : 400,
45			triggerElement: null,
46			offset : 0,
47			event : 'load',
48			callback : null,
49			callbackAfterEachImage : null,
50			placeholder : false,
51			loadHiddenImages : false
52		},
53		
54		// current stack of images
55		currentStack = [],
56		
57		// true if 'callback' fn is called
58		isCallbackDone = false;
59		
60	/* 
61	* Public function defining 'jail'
62	*
63	* @module jail
64	* @param elems : images to load - jQuery elements
65	* @param opts : configurations object
66	*/
67	$.jail = function( elems, opts ) {
68
69		var elements = elems || {},
70			options = $.extend( {}, defaults, opts );
71	
72		// Initialize plugin
73		$.jail.prototype.init( elements, options );
74		
75		// When the event is not specified the images will be loaded with a delay
76		if(/^(load|scroll)/.test( options.event )) {
77			// 'load' event
78			$.jail.prototype.later.call( elements, options );
79		} else {
80			$.jail.prototype.onEvent.call( elements, options );
81		}
82	};
83	
84	/* 
85	* Method in charge of initializing the plugin, storing
86	* the 'element triggering the image to load' in a data attribute 
87	* for each image and displaying the placeholder image (if existing)
88	*
89	* @method init
90	* @param {Array} elems Images to load - jQuery elements
91	* @param {Object} opts Configurations object
92	*/
93	$.jail.prototype.init = function( elements, options ) {
94		
95		// Store the selector triggering jail into 'triggerElem' data for the images selected 
96		elements.data("triggerElem", ( options.triggerElement ) ? $( options.triggerElement ) : $window );
97		
98		// Use a placeholder in case it is specified
99		if ( !!options.placeholder ) {
100			elements.each(function(){
101				$(this).attr( "src", options.placeholder );
102			});
103		}
104	};
105	
106		
107	/* 
108	* Function called when 'event' is different from "load" or "scroll". Two scenarios:
109	* a) Element triggering the images to be loaded (events available on the element: "click", "mouseover", "scroll")
110	* b) Event on the image itself triggering the image to be loaded
111	*
112	* @param options : configurations object
113	*/
114	$.jail.prototype.onEvent = function( options ) {
115		var images = this;
116		
117		if (!!options.triggerElement) {
118			
119			// Event on the 'triggerElement' obj
120			_bindEvent( options, images );
121
122		} else {
123			
124			// Event on the image itself
125			images.on( options.event + '.' + options.id, {options: options, images: images}, function(e) {
126				var $img = $(this),
127					options = e.data.options,
128					images = e.data.images;
129				
130				currentStack = $.extend( {}, images );
131				
132				// Load the image
133				_loadImage( options, $img );
134
135				// Image has been loaded so there is no need to listen anymore
136				$(e.currentTarget).unbind( e.type + '.' + options.id );
137			});
138		}
139	};
140	
141	/* 
142	* Method called when "event" is equals to "load" (default) or "scroll". The visible images will be 
143	* loaded after a specified timeout (or after 1 ms). The scroll method will be bound to the window
144	* to load  the images not visible onload.
145	*
146	* @param options : configurations object
147	*/
148	$.jail.prototype.later = function( options ) {
149		var images = this;
150
151		// After [timeout] has elapsed, load the visible images
152		setTimeout(function() {
153			
154			currentStack = $.extend( {}, images );
155			
156			//Load the visible ones
157			images.each(function(){
158				_loadImageIfVisible( options, this, images );
159			});
160			
161			// When images become available (scrolling or resizing), they will be loaded 
162			options.event = "scroll";
163			_bindEvent( options, images );
164			
165		}, options.timeout);
166	};
167		
168	/* 
169	* Bind _bufferedEventListener() to the event on window/triggerElement. The handler is bound to 
170	* resizing the window as well
171	*
172	* @param options : configurations object
173	* @param images : images in the current stack
174	*/
175	function _bindEvent ( options, images ) {
176		var triggerElem = false;
177
178		if (!!images) {
179			triggerElem = images.data("triggerElem");
180		}
181		
182		// Check if there are images to load
183		if (!!triggerElem && typeof triggerElem.on === "function") {
184			triggerElem.on( options.event + '.' + options.id, {options:options, images : images}, _bufferedEventListener );
185			$window.on( 'resize.'+options.id, {options:options, images : images}, _bufferedEventListener );
186		}
187	}
188
189	/* 
190	* Remove any elements that have been loaded from the jQuery stack.
191	* This should speed up subsequent calls by not having to iterate over the loaded elements.
192	*
193	* @param stack : current images stack
194	*/
195	function _purgeStack ( stack ) {
196		// number of images not loaded
197		var i = 0;
198
199		if (stack.length === 0) { return; }
200
201		// Check on existence of 'data-src' attribute to verify if the image has been loaded
202		while(true) {
203			if(i ===  stack.length) {
204				break;
205			} else {
206				if ($(stack[i]).attr('data-src')) {
207					i++;
208				} else {
209					stack.splice( i, 1 );
210				}
211			}
212		}
213	}
214
215	/* 
216	* Event handler for the images to be loaded. Function called when 
217	* there is a triggerElement or when there are images to be loaded after scrolling 
218	* or resizing window/container 
219	*
220	* @param e : event
221	*/
222	function _bufferedEventListener (e) {
223		var images = e.data.images,
224			options = e.data.options;
225		// Don't set a timer if one is set.
226		if (images.data("poller")) {return;}
227
228		images.data('poller', setTimeout(function() {
229			
230			currentStack = $.extend( {}, images );
231			_purgeStack(currentStack);
232			
233			// Load only the images left
234			$(currentStack).each(function (){
235				if (this === window) {
236					return;
237				}
238				_loadImageIfVisible(options, this, currentStack);
239			});
240			
241			//Unbind when there are no images
242			if ( _isAllImagesLoaded (currentStack) ) {
243				$(e.currentTarget).unbind( e.type + '.' + options.id );
244				return;
245			} 
246			// When images are not in the viewport, let's load them when they become available
247			else if (options.event !== "scroll"){
248			
249				// When images become available (scrolling or resizing), they will be loaded 
250				var container = (/scroll/i.test(options.event)) ? images.data("triggerElem") : $window;
251			
252				options.event = "scroll";
253				images.data("triggerElem", container);
254				_bindEvent( options, $(currentStack) );
255			}
256			images.data("poller", null);
257		}, options.timeout));
258	}
259	
260	/* 
261	* Check if all the images are loaded
262	*
263	* @param images : images under analysis
264	* @return boolean
265	*/
266	function _isAllImagesLoaded ( images ) {
267		var bool = true;
268		
269		$(images).each(function(){
270			if ( !!$(this).attr("data-src") ) {
271				bool = false;
272			}
273		});
274		return bool;
275	}
276
277	/* 
278	* Load the image if visible in the viewport
279	*
280	* @param options : configurations object
281	* @param image : image under analysis
282	* @param images : list of images to load
283	*/
284	function _loadImageIfVisible ( options, image, images ) {
285		var $img = $(image),
286			container = (/scroll/i.test(options.event)) ? images.data("triggerElem") : $window,
287			isVisible = true;
288
289		// If don't you want to load hidden images (default beahviour)
290		if ( !options.loadHiddenImages ) {
291			isVisible = _isVisibleInContainer( $img, container, options ) && $img.is(":visible");
292		}
293		
294		// Load the image if it is not hidden and visible in the screen
295		if( isVisible && _isInTheScreen( container, $img, options.offset ) ) {
296			_loadImage( options, $img );
297		}
298	}
299	
300	/* 
301	* Function that returns true if the image is visible inside the "window" (or specified container element)
302	*
303	* @param $ct : container - jQuery obj
304	* @param $img : image selected - jQuery obj
305	* @param optionOffset : offset
306	*/
307	function _isInTheScreen ( $ct, $img, optionOffset ) {
308		var is_ct_window  = $ct[0] === window,
309			ct_offset  = (is_ct_window ? { top:0, left:0 } : $ct.offset()),
310			ct_top     = ct_offset.top + ( is_ct_window ? $ct.scrollTop() : 0),
311			ct_left    = ct_offset.left + ( is_ct_window ? $ct.scrollLeft() : 0),
312			ct_right   = ct_left + $ct.width(),
313			ct_bottom  = ct_top + $ct.height(),
314			img_offset = $img.offset(),
315			img_width = $img.width(),
316			img_height = $img.height();
317		
318		return (ct_top - optionOffset) <= (img_offset.top + img_height) &&
319			(ct_bottom + optionOffset) >= img_offset.top &&
320				(ct_left - optionOffset)<= (img_offset.left + img_width) &&
321					(ct_right + optionOffset) >= img_offset.left;
322	}
323
324	/* 
325	* Main function --> Load the images copying the "data-href" attribute into the "src" attribute
326	*
327	* @param options : configurations object
328	* @param $img : image selected - jQuery obj
329	*/
330	function _loadImage ( options, $img ) {
331		
332		// Use cache Image object to show images only when ready
333		var cache = new Image();
334
335		cache.onload = function() {
336			$img.hide().attr("src", cache.src);
337			
338			$img.removeAttr('data-src');
339			// Images loaded with some effect if existing
340			if( options.effect) {
341
342				if ( options.speed ) {
343					$img[options.effect](options.speed);
344				} else {
345					$img[options.effect]();
346				}
347				$img.css("opacity", 1);
348				$img.show();
349			} else {
350				$img.show();
351			}
352		
353			_purgeStack(currentStack);
354		
355			// Callback after each image is loaded
356			if ( !!options.callbackAfterEachImage ) {
357				options.callbackAfterEachImage.call( this, $img, options );
358			}
359			
360			if ( _isAllImagesLoaded (currentStack) && !!options.callback && !isCallbackDone ) {
361				options.callback.call($.jail, options);
362				isCallbackDone = true;
363			}
364		};
365
366		/*
367		 * Basic on error handler. For now we limit
368		 * the plugin to exectute any callback passed
369		 * in the options object. Let the developer
370		 * decide what to do with it.
371		 */
372		cache.onerror = function(){
373			
374			if(!('error' in options)) { return; }
375
376			var args = Array.prototype.slice.call(arguments, 0);
377			args = [$img, options].concat(args);
378			options.error.apply($.jail, args);
379		};
380
381		cache.src = $img.attr("data-src");
382	}
383		
384	/* 
385	* Return if the image is visible inside a "container" / window. There are checks around
386	* "visibility" CSS property and around "overflow" property of the "container"
387	*
388	* @param $img : image selected - jQuery obj
389	* @param container : container object
390	* @param options : configurations object
391	*/
392	function _isVisibleInContainer ( $img, container, options ){
393
394		var parent = $img.parent(),
395			isVisible = true;
396
397		while ( parent.length && parent.get(0).nodeName.toUpperCase() !== "BODY" ) {
398			// Consider the 'overflow' property
399			if ( parent.css("overflow") === "hidden" ) {
400				if (!_isInTheScreen(parent, $img, options.offset)) {
401					isVisible = false;
402					break;
403				}
404			} else if ( parent.css("overflow") === "scroll" ) {
405				if (!_isInTheScreen(parent, $img, options.offset)) {
406					isVisible = false;
407					$(currentStack).data("triggerElem", parent);
408					
409					options.event = "scroll";
410					_bindEvent(options, $(currentStack));
411					break;
412				}
413			}
414			
415			if ( parent.css("visibility") === "hidden" || $img.css("visibility") === "hidden" ) {
416				isVisible = false;
417				break;
418			}
419			
420			// If container is not the window, and the parent is the container, exit from the loop
421			if ( container !== $window && parent === container ) {
422				break;
423			}
424			
425			parent = parent.parent();
426		}
427		
428		return isVisible;
429	}
430
431	// Small wrapper
432	$.fn.jail = function( options ) {
433
434		new $.jail( this, options );
435		
436		// Empty current stack
437		currentStack = [];
438		
439		return this;
440	};
441	
442	return $.jail;
443}));

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.