/*

 * jQuery.appear

 * https://github.com/bas2k/jquery.appear/

 * http://code.google.com/p/jquery-appear/

 * http://bas2k.ru/

 *

 * Copyright (c) 2009 Michael Hixson

 * Copyright (c) 2012-2014 Alexander Brovikov

 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)

 */

(function($) {

    $.fn.appear = function(fn, options) {



        var settings = $.extend({



            //arbitrary data to pass to fn

            data: undefined,



            //call fn only on the first appear?

            one: true,



            // X & Y accuracy

            accX: 0,

            accY: 0



        }, options);



        return this.each(function() {



            var t = $(this);



            //whether the element is currently visible

            t.appeared = false;



            if (!fn) {



                //trigger the custom event

                t.trigger('appear', settings.data);

                return;

            }



            var w = $(window);



            //fires the appear event when appropriate

            var check = function() {



                //is the element hidden?

                if (!t.is(':visible')) {



                    //it became hidden

                    t.appeared = false;

                    return;

                }



                //is the element inside the visible window?

                var a = w.scrollLeft();

                var b = w.scrollTop();

                var o = t.offset();

                var x = o.left;

                var y = o.top;



                var ax = settings.accX;

                var ay = settings.accY;

                var th = t.height();

                var wh = w.height();

                var tw = t.width();

                var ww = w.width();



                if (y + th + ay >= b &&

                    y <= b + wh + ay &&

                    x + tw + ax >= a &&

                    x <= a + ww + ax) {



                    //trigger the custom event

                    if (!t.appeared) t.trigger('appear', settings.data);



                } else {



                    //it scrolled out of view

                    t.appeared = false;

                }

            };



            //create a modified fn with some additional logic

            var modifiedFn = function() {



                //mark the element as visible

                t.appeared = true;



                //is this supposed to happen only once?

                if (settings.one) {



                    //remove the check

                    w.unbind('scroll', check);

                    var i = $.inArray(check, $.fn.appear.checks);

                    if (i >= 0) $.fn.appear.checks.splice(i, 1);

                }



                //trigger the original fn

                fn.apply(this, arguments);

            };



            //bind the modified fn to the element

            if (settings.one) t.one('appear', settings.data, modifiedFn);

            else t.bind('appear', settings.data, modifiedFn);



            //check whenever the window scrolls

            w.scroll(check);



            //check whenever the dom changes

            $.fn.appear.checks.push(check);



            //check now

            (check)();

        });

    };



    //keep a queue of appearance checks

    $.extend($.fn.appear, {



        checks: [],

        timeout: null,



        //process the queue

        checkAll: function() {

            var length = $.fn.appear.checks.length;

            if (length > 0) while (length--) ($.fn.appear.checks[length])();

        },



        //check the queue asynchronously

        run: function() {

            if ($.fn.appear.timeout) clearTimeout($.fn.appear.timeout);

            $.fn.appear.timeout = setTimeout($.fn.appear.checkAll, 20);

        }

    });



    //run checks when these methods are called

    $.each(['append', 'prepend', 'after', 'before', 'attr',

        'removeAttr', 'addClass', 'removeClass', 'toggleClass',

        'remove', 'css', 'show', 'hide'], function(i, n) {

        var old = $.fn[n];

        if (old) {

            $.fn[n] = function() {

                var r = old.apply(this, arguments);

                $.fn.appear.run();

                return r;

            }

        }

    });



})(jQuery);
