(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : typeof define === 'function' && define.amd ? define(['jquery'], factory) : (factory(global.jQuery)); }(this, (function ($) { 'use strict'; $ = $ && $.hasOwnProperty('default') ? $['default'] : $; /** * @author Mudit Ameta * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT */ // expose isInViewport as a custom pseudo-selector $.extend($.expr.pseudos || $.expr[':'], { // if $.expr.createPseudo is available, use it 'in-viewport': $.expr.createPseudo ? $.expr.createPseudo(function (argsString) { return function (currElement) { return isInViewport(currElement, getSelectorArgs(argsString)); }; }) : function (currObj, index, meta) { return isInViewport(currObj, getSelectorArgs(meta[3])); } }); // expose isInViewport as a function too // this lets folks pass around actual objects as options (like custom viewport) // and doesn't tie 'em down to strings. It also prevents isInViewport from // having to look up and wrap the dom element corresponding to the viewport selector $.fn.isInViewport = function(options) { return this.filter(function (i, el) { return isInViewport(el, options); }) }; $.fn.run = run; // lets you chain any arbitrary function or an array of functions and returns a jquery object function run(args) { var this$1 = this; if (arguments.length === 1 && typeof args === 'function') { args = [args]; } if (!(args instanceof Array)) { throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') } args.forEach(function (arg) { if (typeof arg !== 'function') { console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions'); console.warn('isInViewport: Ignoring non-function values in array and moving on'); } else { [].slice.call(this$1).forEach(function (t) { return arg.call($(t)); }); } }); return this } // gets the width of the scrollbar function getScrollbarWidth(viewport) { // append a div that has 100% width to get true width of viewport var el = $('<div></div>').css({ width: '100%' }); viewport.append(el); // subtract true width from the viewport width which is inclusive // of scrollbar by default var scrollBarWidth = viewport.width() - el.width(); // remove our element from DOM el.remove(); return scrollBarWidth } // Returns true if DOM element `element` is in viewport function isInViewport(element, options) { var ref = element.getBoundingClientRect(); var top = ref.top; var bottom = ref.bottom; var left = ref.left; var right = ref.right; var settings = $.extend({ tolerance: 0, viewport: window }, options); var isVisibleFlag = false; var $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport); if (!$viewport.length) { console.warn('isInViewport: The viewport selector you have provided matches no element on page.'); console.warn('isInViewport: Defaulting to viewport as window'); $viewport = $(window); } var $viewportHeight = $viewport.height(); var $viewportWidth = $viewport.width(); var typeofViewport = $viewport[0].toString(); // if the viewport is other than window recalculate the top, // bottom,left and right wrt the new viewport // the [object DOMWindow] check is for window object type in PhantomJS if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') { // use getBoundingClientRect() instead of $.Offset() // since the original top/bottom positions are calculated relative to browser viewport and not document var viewportRect = $viewport[0].getBoundingClientRect(); // recalculate these relative to viewport top = top - viewportRect.top; bottom = bottom - viewportRect.top; left = left - viewportRect.left; right = right - viewportRect.left; // get the scrollbar width from cache or calculate it isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport); // remove the width of the scrollbar from the viewport width $viewportWidth -= isInViewport.scrollBarWidth; } // handle falsy, non-number and non-integer tolerance value // same as checking using isNaN and then setting to 0 // bitwise operators deserve some love too you know settings.tolerance = ~~Math.round(parseFloat(settings.tolerance)); if (settings.tolerance < 0) { settings.tolerance = $viewportHeight + settings.tolerance; // viewport height - tol } // the element is NOT in viewport iff it is completely out of // viewport laterally or if it is completely out of the tolerance // region. Therefore, if it is partially in view then it is considered // to be in the viewport and hence true is returned. Because we have adjusted // the left/right positions relative to the viewport, we should check the // element's right against the viewport's 0 (left side), and the element's // left against the viewport's width to see if it is outside of the viewport. if (right <= 0 || left >= $viewportWidth) { return isVisibleFlag } // if the element is bound to some tolerance isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight; return isVisibleFlag } // get the selector args from the args string proved by Sizzle function getSelectorArgs(argsString) { if (argsString) { var args = argsString.split(','); // when user only gives viewport and no tolerance if (args.length === 1 && isNaN(args[0])) { args[1] = args[0]; args[0] = void 0; } return { tolerance: args[0] ? args[0].trim() : void 0, viewport: args[1] ? $(args[1].trim()) : void 0 } } return {} } }))); //# sourceMappingURL=isInViewport.js.map