( function( window, $, undefined ) { | |
var $window = $( window ), | |
images = $( 'img[data-lazy]'), | |
throttle_id; | |
/** | |
* Determine whether or not a given image is in the current viewport. | |
* | |
* @param {DOMElement} image | |
* | |
* @return {Boolean} | |
*/ | |
function inView( image ) { | |
var $image = $( image ), | |
view_top = $window.scrollTop() - 300, | |
view_bottom = view_top + $window.height() + 600, | |
height = $image.height(), | |
_top = $image.offset().top, | |
_bottom = _top + height; | |
// Only fire on elements with non-zero heights.If the top edge is above the bottom threshold, or the bottom | |
// edge is below the top threshold, then the image is visible and should be loaded. Otherwise, return false. | |
return ( height > 0 ) && ( _top <= view_bottom ) && ( _bottom >= view_top ); | |
} | |
/** | |
* Iterate through a jQuery array of images and, if they're visible, load them into the page. | |
* | |
* @param {Array} images | |
*/ | |
function maybeLoad( images ) { | |
var did_lazy_load = false; | |
// Iterate through every image on the page that has a `data-lazy` attribute. | |
images.each( function( i, image ) { | |
if ( image.hasAttribute( 'data-lazy') && inView( image ) ) { | |
image.src = image.getAttribute( 'data-lazy' ); | |
image.removeAttribute( 'data-lazy' ); | |
// Fire a jQuery event on the image in case anyone else is watching. | |
$( image ).trigger( 'lazy-load' ); | |
// Keep track that we need to repopulate the `images` array | |
did_lazy_load = true; | |
} | |
} ); | |
// Repopulate our `images` array | |
if ( did_lazy_load ) { | |
images = $( 'img[data-lazy]' ); | |
} | |
} | |
$window.on( 'scroll', function() { | |
if ( undefined === throttle_id ) { | |
// We're already living in a throttled environment, so exit | |
return; | |
} | |
// If we've gotten this far, it means it's the first call to 'scroll' the application has received. | |
// Set up a timeout to fire our callback in 250 milliseconds | |
throttle_id = window.setTimeout( | |
function() { | |
maybeLoad( images ); | |
throttle_id = undefined; | |
}, | |
250 | |
); | |
} ); | |
// Fire our image parser immediately to force visible images into the display | |
maybeLoad( images ); | |
} )( window, jQuery ); |
( function( window, $, undefined ) { | |
var document = window.document, | |
$document = $( document ); | |
/** | |
* Universal callback to load a video player iFrame into a modal window. | |
* | |
* @param {Event} e | |
*/ | |
function play_video( e ) { | |
var $this = $( this ), | |
video = this.getAttribute( 'data-embed' ), | |
content = document.createElement( 'iframe' ), | |
overlay = document.createElement( 'div' ), | |
modal = document.createElement( 'div' ), | |
closer = document.createElement( 'a' ), | |
$overlay = $( overlay ), $modal = $( modal ), $closer = $( closer ), | |
close_video; | |
// Build out the iFrame that will contain our video player. We want the iFrame to be full-screen in this implementation. | |
content.width = '100%'; | |
content.height = '100%'; | |
content.src = video; | |
content.className = 'iframe_video'; | |
// Set up the styling for the modal overlay atop which the player will display. | |
overlay.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #000;z-index: 159900;'; | |
// jQuery is used to set the overlay's opacity for cross browser-compatibility. Immediately wire close_video as a click | |
// callback - we've declared the variable already so it's available, but we'll define the callback function itself later. | |
$overlay.css( 'opacity', 0.7 ).on( 'click', close_video ); | |
// Set up the styling for the modal window in which the video plays. | |
modal.style.cssText = 'position: fixed; top: 30px; left: 30px; right: 30px; bottom: 30px; background-color: #fff; z-index: 160000;'; | |
// Set up an anchor tag to serve as our close trigger. This tag, when clicked, will remove the video and overlay from the DOM. | |
closer.className = 'iframe_close'; | |
closer.href = '#'; | |
closer.innerText = 'close'; | |
$closer.on( 'click', function( e ) { | |
e.preventDefault(); | |
close_video(); | |
} ); | |
modal.appendChild( closer ); | |
/** | |
* Define the close video callback. Both `$modal` and `$overlay` must be defined first before we can build out the function. | |
*/ | |
close_video = function() { | |
$modal.remove(); | |
$overlay.remove(); | |
}; | |
// Append our elements to the page | |
modal.appendChild( content ); | |
document.appendChild( modal ); | |
} | |
$document.on( 'click', '.iframe_play', play_video ); | |
} )( window, jQuery ); |
Sorry I forgot to say, my "images" collection seems empty, its lenght = 0 when debugging on line 36 (you can see it in the console).
Cheers!
Yep, there was a typo in my first script - there are two references to images = $( 'image[data-lazy]' )
. These should be images = $( 'img[data-lazy]' )
and has been corrected above.
Additionally, the jQuery trigger for 'lazy-load' is attempting to fire against a vanilla JS object rather than a jQuery-wrapped object (line 41 of the image loader). I've corrected this above as well.
Gave you tried using lazyload with picture / picturefill.js? I thinking that instead of faux'ing the src, I can do the srcset instead. But I'm also concerned some browsers might not like that idea. Perhaps you've seen this or similar? Picture + lazyload would be the ultimate, eh?
Also, what about expanding the size of the inView as the loading finishes? That is +300 in each direction, then +300 more, and so on. I guess 300 doesn't feel like much in an image heavy / scroll happy world. That said, perhaps 250 ms is too often? I mean, maybe there's a way to factor in scroll speed as well. No sense thinking about loading if we're flying right past it, eh?
Hi,
I can't get this to work at all, am I missing something obvious?
http://mi-linux.wlv.ac.uk/~in9352/lazy/
The JS is exactly as above, and the markup is pretty simple... where am I going wrong?
Cheers,
Alix