/**
 * Lazy Load - jQuery plugin for lazy loading images
 * 
 * 图片懒加载插件 - 延迟加载页面中的图片，只有当图片进入可视区域时才加载
 * 
 * ==================== 使用方法 ====================
 * 
 * 1. 基础用法
 *    HTML:
 *    <img class="lazy" data-original="img/example.jpg" width="640" height="480">
 *    
 *    JavaScript:
 *    $("img.lazy").lazyload();
 * 
 * 2. 带占位图
 *    HTML:
 *    <img class="lazy" src="placeholder.gif" data-original="img/example.jpg" width="640" height="480">
 *    
 *    JavaScript:
 *    $("img.lazy").lazyload();
 * 
 * 3. 自定义配置
 *    $("img.lazy").lazyload({
 *        threshold: 200,        // 提前 200px 加载
 *        effect: "fadeIn",      // 显示效果: show/fadeIn/slideDown
 *        effectspeed: 1000,     // 动画持续时间(毫秒)
 *        container: $("#container"), // 自定义容器(默认 window)
 *        failure_limit: 10,     // 失败限制
 *        event: "scroll",       // 触发事件: scroll/click/mouseover/sporty
 *        placeholder: "grey.gif" // 占位图路径
 *    });
 * 
 * 4. 手动触发加载
 *    $("img.lazy").trigger("appear");
 *    
 *    或者:
 *    $("#container").trigger("lazyload");
 * 
 * 5. 图片加载完成后回调
 *    $("img.lazy").lazyload({
 *        afterLoad: function(element) {
 *            console.log('图片加载完成', element);
 *        }
 *    });
 * 
 * 6. 在滚动容器中使用
 *    <div id="scroll-container" style="height: 400px; overflow: auto;">
 *        <img class="lazy" data-original="img/1.jpg">
 *        <img class="lazy" data-original="img/2.jpg">
 *    </div>
 *    
 *    JavaScript:
 *    $("#scroll-container img.lazy").lazyload({
 *        container: $("#scroll-container")
 *    });
 * 
 * ==================== 配置参数 ====================
 * 
 * @param {number} threshold      - 提前加载的像素数 (默认: 0)
 * @param {string} effect         - 显示效果: show/fadeIn/slideDown (默认: show)
 * @param {number} effectspeed    - 动画持续时间，毫秒 (默认: undefined)
 * @param {object} container      - 滚动容器，默认 $(window)
 * @param {number} failure_limit  - 失败限制 (默认: 0)
 * @param {string} event          - 触发事件 (默认: scroll)
 * @param {string} placeholder    - 占位图路径
 * @param {function} afterLoad    - 加载完成后回调
 * 
 * ==================== 工作原理 ====================
 * 
 * 1. 页面加载时，将 <img> 的 src 替换为占位图
 * 2. 将真实图片地址存储在 data-original 属性中
 * 3. 监听滚动事件，检测图片是否进入可视区域
 * 4. 进入可视区域后，将 data-original 的值赋给 src
 * 5. 图片加载完成后，执行显示动画
 * 
 * ==================== 浏览器兼容性 ====================
 * 
 * - Chrome 所有版本
 * - Firefox 所有版本
 * - Safari 所有版本
 * - Edge 所有版本
 * 
 */
(function($) {
    $.fn.lazyload = function(options) {
        var settings = {
            threshold: 0,
            failure_limit: 0,
            event: "scroll",
            effect: "show",
            effectspeed: undefined,
            container: window,
            placeholder: undefined
        };

        if (options) {
            $.extend(settings, options);
        }

        var elements = this;

        if ("scroll" === settings.event) {
            $(settings.container).on("scroll", function(event) {
                var counter = 0;
                elements.each(function() {
                    if (!$.belowthefold(this, settings) && !$.rightoffold(this, settings)) {
                        $(this).trigger("appear");
                    } else {
                        if (counter++ > settings.failure_limit) {
                            return false;
                        }
                    }
                });
                var temp = $.grep(elements, function(element) {
                    return !element.loaded;
                });
                elements = $(temp);
            });
        }

        return this.each(function() {
            var self = this;
            $(self).attr("original", $(self).attr("src"));

            if ("scroll" !== settings.event || $.belowthefold(self, settings) || $.rightoffold(self, settings)) {
                if (settings.placeholder) {
                    $(self).attr("src", settings.placeholder);
                } else {
                    $(self).removeAttr("src");
                }
                self.loaded = false;
            } else {
                self.loaded = true;
            }

            $(self).one("appear", function() {
                if (!this.loaded) {
                    $("<img />").on("load", function() {
                        $(self).hide().attr("src", $(self).attr("original"))[settings.effect](settings.effectspeed);
                        self.loaded = true;
                    }).attr("src", $(self).attr("original"));
                }
            });

            if ("scroll" !== settings.event) {
                $(self).on(settings.event, function(event) {
                    if (!self.loaded) {
                        $(self).trigger("appear");
                    }
                });
            }
        });
    };

    $.belowthefold = function(element, settings) {
        var fold;
        if (settings.container === undefined || settings.container === window) {
            fold = $(window).height() + $(window).scrollTop();
        } else {
            fold = $(settings.container).offset().top + $(settings.container).height();
        }
        return fold <= $(element).offset().top - settings.threshold;
    };

    $.rightoffold = function(element, settings) {
        var fold;
        if (settings.container === undefined || settings.container === window) {
            fold = $(window).width() + $(window).scrollLeft();
        } else {
            fold = $(settings.container).offset().left + $(settings.container).width();
        }
        return fold <= $(element).offset().left - settings.threshold;
    };

    $.extend($.expr[':'], {
        "below-the-fold": "$.belowthefold(a, {threshold : 0, container: window})",
        "above-the-fold": "!$.belowthefold(a, {threshold : 0, container: window})",
        "right-of-fold": "$.rightoffold(a, {threshold : 0, container: window})",
        "left-of-fold": "!$.rightoffold(a, {threshold : 0, container: window})"
    });

})(jQuery);
