/** Lazy Load XT v1.1.0 2016-01-12
 * http://ressio.github.io/lazy-load-xt
 * (C) 2016 RESS.io
 * Licensed under MIT
 * reformatted code by themeComplete
 */

( function( $, window, document ) {
	'use strict';

	// options
	var lazyLoadXT = 'lazyLoadXT',
		dataLazied = 'lazied',
		loadError = 'load error',
		classLazyHidden = 'lazy-hidden',
		docElement = document.documentElement || document.body,
		//  force load all images in Opera Mini and some mobile browsers without scroll event or getBoundingClientRect()
		forceLoad =
			window.onscroll === undefined ||
			!! window.operamini ||
			! docElement.getBoundingClientRect,
		options = {
			autoInit: true, // auto initialize in document ready
			selector: 'img[data-src]', // selector for lazyloading elements
			blankImage: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
			throttle: 99, // interval (ms) for changes check
			forceLoad: forceLoad, // force auto load all images

			loadEvent: 'pageshow', // check AJAX-loaded content in jQueryMobile
			updateEvent: 'load orientationchange resize scroll touchmove focus', // page-modified events
			forceEvent: 'lazyloadall', // force loading of all elements

			//onstart: null,
			oninit: { removeClass: 'lazy' }, // init handler
			onshow: { addClass: classLazyHidden }, // start loading handler
			onload: { removeClass: classLazyHidden, addClass: 'lazy-loaded' }, // load success handler
			onerror: { removeClass: classLazyHidden }, // error handler
			//oncomplete: null, // complete handler

			//scrollContainer: undefined,
			checkDuplicates: true
		},
		elementOptions = {
			srcAttr: 'data-src',
			edgeX: 0,
			edgeY: 0,
			visibleOnly: true
		},
		$window = $( window ),
		$isFunction = function( f ) {
			return typeof f === 'function';
		},
		$extend = $.extend,
		$data =
			$.data ||
			function( el, name ) {
				return $( el ).data( name );
			},
		elements = [],
		topLazy = 0,
		/*
         waitingMode=0 : no setTimeout
         waitingMode=1 : setTimeout, no deferred events
         waitingMode=2 : setTimeout, deferred events
         */
		waitingMode = 0;

	$[ lazyLoadXT ] = $extend( options, elementOptions, $[ lazyLoadXT ] );

	/**
	 * Return options.prop if obj.prop is undefined, otherwise return obj.prop
	 *
	 * @param {*} obj
	 * @param {*} prop
	 */
	function getOrDef( obj, prop ) {
		return obj[ prop ] === undefined ? options[ prop ] : obj[ prop ];
	}

	function scrollTop() {
		var scroll = window.pageYOffset;
		return scroll === undefined ? docElement.scrollTop : scroll;
	}

	/**
	 * Run check of lazy elements after timeout
	 */
	function timeoutLazyElements() {
		if ( waitingMode > 1 ) {
			waitingMode = 1;
			checkLazyElements();
			setTimeout( timeoutLazyElements, options.throttle );
		} else {
			waitingMode = 0;
		}
	}

	/**
	 * Queue check of lazy elements because of event e
	 *
	 * @param {Event} [e]
	 */
	function queueCheckLazyElements( e ) {
		if ( ! elements.length ) {
			return;
		}

		// fast check for scroll event without new visible elements
		if ( e && e.type === 'scroll' && e.currentTarget === window ) {
			if ( topLazy >= scrollTop() ) {
				return;
			}
		}

		if ( ! waitingMode ) {
			setTimeout( timeoutLazyElements, 0 );
		}
		waitingMode = 2;
	}

	/**
	 * Process function/object event handler
	 *
	 * @param {string} event suffix
	 * @param {jQuery} $el
	 */
	function triggerEvent( event, $el ) {
		var handler = options[ 'on' + event ];
		if ( handler ) {
			if ( $isFunction( handler ) ) {
				handler.call( $el[ 0 ] );
			} else {
				if ( handler.addClass ) {
					$el.addClass( handler.addClass );
				}
				if ( handler.removeClass ) {
					$el.removeClass( handler.removeClass );
				}
			}
		}

		$el.trigger( 'lazy' + event, [ $el ] );

		// queue next check as images may be resized after loading of actual file
		queueCheckLazyElements();
	}

	/**
	 * Trigger onload/onerror handler
	 *
	 * @param {Event} e
	 */
	function triggerLoadOrError( e ) {
		triggerEvent( e.type, $( e.currentTarget ).off( loadError, triggerLoadOrError ) );
	}

	/**
	 * Load visible elements
	 *
	 * @param {bool} [force] loading of all elements
	 */
	function checkLazyElements( force ) {
		var viewportTop, viewportHeight, viewportWidth, i, length;

		var $el, el, objData, removeNode, visible, topEdge;

		var elPos, edgeX, edgeY;

		var srcAttr, src;

		if ( ! elements.length ) {
			return;
		}

		force = force || options.forceLoad;

		topLazy = Infinity;

		viewportTop = scrollTop();
		viewportHeight = window.innerHeight || docElement.clientHeight;
		viewportWidth = window.innerWidth || docElement.clientWidth;

		for ( i = 0, length = elements.length; i < length; i += 1 ) {
			$el = elements[ i ];
			el = $el[ 0 ];
			objData = $el[ lazyLoadXT ];
			removeNode = false;
			visible = force || $data( el, dataLazied ) < 0;

			// remove items that are not in DOM
			if ( ! $.contains( docElement, el ) ) {
				removeNode = true;
			} else if ( force || ! objData.visibleOnly || el.offsetWidth || el.offsetHeight ) {
				if ( ! visible ) {
					elPos = el.getBoundingClientRect();
					edgeX = objData.edgeX;
					edgeY = objData.edgeY;

					topEdge = elPos.top + viewportTop - edgeY - viewportHeight;

					visible = topEdge <= viewportTop && elPos.bottom > -edgeY && elPos.left <= viewportWidth + edgeX && elPos.right > -edgeX;
				}

				if ( visible ) {
					$el.on( loadError, triggerLoadOrError );

					triggerEvent( 'show', $el );

					srcAttr = objData.srcAttr;
					src = $isFunction( srcAttr ) ? srcAttr( $el ) : el.getAttribute( srcAttr );

					if ( src ) {
						el.src = src;
					}

					removeNode = true;
				} else if ( topEdge < topLazy ) {
					topLazy = topEdge;
				}
			}

			if ( removeNode ) {
				$data( el, dataLazied, 0 );
				elements.splice( i, 1 );
				i = i - 1;
				length = length - 1;
			}
		}

		if ( ! length ) {
			triggerEvent( 'complete', $( docElement ) );
		}
	}

	/**
	 * Add new elements to lazy-load list:
	 * $(elements).lazyLoadXT() or $(window).lazyLoadXT()
	 *
	 * @param {Object} [overrides] override global options
	 */
	$.fn[ lazyLoadXT ] = function( overrides ) {
		var blankImage;
		var checkDuplicates;
		var scrollContainer;
		var forceShow;
		var elementOptionsOverrides = {};

		overrides = overrides || {};

		blankImage = getOrDef( overrides, 'blankImage' );
		checkDuplicates = getOrDef( overrides, 'checkDuplicates' );
		scrollContainer = getOrDef( overrides, 'scrollContainer' );
		forceShow = getOrDef( overrides, 'show' );

		// empty overrides.scrollContainer is supported by both jQuery and Zepto
		$( scrollContainer ).on( 'scroll', queueCheckLazyElements );

		Object.keys( elementOptions ).forEach( function( prop ) {
			elementOptionsOverrides[ prop ] = getOrDef( overrides, prop );
		} );

		return this.each( function( index, el ) {
			var duplicate;
			var $el;
			if ( el === window ) {
				$( options.selector ).lazyLoadXT( overrides );
			} else {
				duplicate = checkDuplicates && $data( el, dataLazied );
				$el = $( el ).data( dataLazied, forceShow ? -1 : 1 );

				// prevent duplicates
				if ( duplicate ) {
					queueCheckLazyElements();
					return;
				}

				if ( blankImage && el.tagName === 'IMG' && ! el.src ) {
					el.src = blankImage;
				}

				// clone elementOptionsOverrides object
				$el[ lazyLoadXT ] = $extend( {}, elementOptionsOverrides );

				triggerEvent( 'init', $el );

				elements.push( $el );
				queueCheckLazyElements();
			}
		} );
	};

	/**
	 * Initialize list of hidden elements
	 */
	function initLazyElements() {
		$window.lazyLoadXT();
	}

	/**
	 * Loading of all elements
	 */
	function forceLoadAll() {
		checkLazyElements( true );
	}

	/**
	 * Initialization
	 */
	// document ready
	$( function() {
		triggerEvent( 'start', $window );

		$window.on( options.updateEvent, queueCheckLazyElements ).on( options.forceEvent, forceLoadAll );

		$( document ).on( options.updateEvent, queueCheckLazyElements );

		if ( options.autoInit ) {
			$window.on( options.loadEvent, initLazyElements );
			initLazyElements(); // standard initialization
		}
	} );
}( window.jQuery || window.Zepto || window.$, window, document ) );

( function( $ ) {
	'use strict';

	var options = $.lazyLoadXT;

	options.selector += ',video,iframe[data-src]';
	options.videoPoster = 'data-poster';

	$( document ).on( 'lazyshow', 'video', function( e, $el ) {
		var srcAttr = $el.lazyLoadXT.srcAttr,
			isFuncSrcAttr = typeof srcAttr === 'function',
			changed = false;

		$el.attr( 'poster', $el.attr( options.videoPoster ) );
		$el.children( 'source,track' ).each( function( index, el ) {
			var $child = $( el ),
				src = isFuncSrcAttr ? srcAttr( $child ) : $child.attr( srcAttr );
			if ( src ) {
				$child.attr( 'src', src );
				changed = true;
			}
		} );

		// reload video
		if ( changed ) {
			this.load();
		}
	} );
}( window.jQuery || window.Zepto || window.$ ) );
