{"version":3,"file":"responsive-lazyload.umd.js","sources":["../source/scripts/responsive-lazyload.js"],"sourcesContent":["/**\n * Check if an element is visible at all in the viewport.\n *\n * It would be cool to use an IntersectionObserver here, but browser support\n * isn’t there yet: http://caniuse.com/#feat=intersectionobserver\n *\n * @param {Element} el the element to check\n * @return {Boolean} `true` if the element is visible at all; `false` if not\n */\nfunction isElementVisible(el) {\n /*\n * Checks if element (or an ancestor) is hidden via style properties.\n * See https://stackoverflow.com/a/21696585/463471\n */\n const isCurrentlyVisible = el.offsetParent !== null;\n\n // Check if any part of the element is vertically within the viewport.\n const position = el.getBoundingClientRect();\n const wH =\n window.innerHeight ||\n /* istanbul ignore next */ document.documentElement.clientHeight;\n const isWithinViewport =\n (position.top >= 0 && position.top <= wH) ||\n (position.bottom >= 0 && position.bottom <= wH);\n\n return isCurrentlyVisible && isWithinViewport;\n}\n\n/**\n * Prevents a function from firing too often.\n * @param {Function} func the function to throttle\n * @param {Number} limit the amount of milliseconds to wait between calls\n * @return {Function} function to check if the function should be called\n */\nfunction throttle(func, /* istanbul ignore next */ limit = 200) {\n let wait = false;\n\n return () => {\n if (!wait) {\n func.call();\n wait = true;\n setTimeout(() => {\n wait = false;\n }, limit);\n }\n };\n}\n\n/**\n * Check if an image is visible and trigger an event if so.\n * @param {Element} image the image to check\n * @param {Event} event an event to dispatch if the image is in the viewport\n * @return {Boolean} true if the image is in the viewport; false if not\n */\nconst maybeTriggerImageLoad = (image, event) => {\n if (!image.getAttribute('data-loaded') && isElementVisible(image)) {\n image.dispatchEvent(event);\n\n return true;\n }\n\n return false;\n};\n\n/**\n * Finds the image to be lazyloaded.\n * @param {Element} el `img` element to be lazyloaded or its container\n * @return {Element} the `img` element to be lazyloaded\n */\nconst findImageElement = el =>\n el.tagName.toLowerCase() === 'img' ? el : el.querySelector('img');\n\n/**\n * This almost seems too easy, but we simply swap in the correct srcset.\n * @param {Event} event the triggered event\n * @return {Void}\n */\nconst loadImage = event => {\n const image = event.target;\n\n // Swap in the srcset info and add an attribute to prevent duplicate loads.\n image.srcset = image.getAttribute('data-lazyload');\n image.setAttribute('data-loaded', true);\n};\n\n/**\n * Remove the loading class from the lazyload wrapper.\n * @param {Element} image the image being loaded\n * @param {String} loadingClass the class to remove\n * @return {Void}\n */\nconst removeLoadingClass = (image, loadingClass) => {\n let element = image;\n let shouldReturn = false;\n\n /*\n * Since there may be additional elements wrapping the image (e.g. a link),\n * we run a loop to check the image’s ancestors until we either find the\n * element with the loading class or hit the `body` element.\n */\n while (element.tagName.toLowerCase() !== 'body') {\n if (element.classList.contains(loadingClass)) {\n element.classList.remove(loadingClass);\n shouldReturn = true;\n } else {\n element = element.parentNode;\n }\n\n if (shouldReturn) {\n return;\n }\n }\n};\n\nconst checkForImagesToLazyLoad = (lazyLoadEvent, images) => {\n images.forEach(image => {\n maybeTriggerImageLoad(image, lazyLoadEvent);\n });\n};\n\n/**\n * Initializes the lazyloader and adds the relevant classes and handlers.\n * @param {String} options.containerClass the lazyloaded image wrapper\n * @param {String} options.loadingClass the class that signifies loading\n * @param {Function} options.callback a function to fire on image load\n * @return {Function} a function to load visible images\n */\nconst initialize = ({\n containerClass = 'js--lazyload',\n loadingClass = 'js--lazyload--loading',\n callback = e => e,\n}) => {\n // Find all the containers and add the loading class.\n const containers = document.getElementsByClassName(containerClass);\n\n [].forEach.call(containers, container => {\n container.classList.add(loadingClass);\n });\n\n // If we get here, `srcset` is supported and we can start processing things.\n const images = [].map.call(containers, findImageElement);\n\n // Create a custom event to trigger the event load.\n const lazyLoadEvent = new Event('lazyload-init');\n\n // Attach an onload handler to each image.\n images.forEach(image => {\n /*\n * Once the image is loaded, we want to remove the loading class so any\n * loading animations or other effects can be disabled.\n */\n image.addEventListener('load', event => {\n removeLoadingClass(event.target, loadingClass);\n callback(event);\n });\n\n /*\n * Set up a listener for the custom event that triggers the image load\n * handler (which loads the image).\n */\n image.addEventListener('lazyload-init', loadImage);\n\n /*\n * Check if the image is already in the viewport. If so, load it.\n */\n maybeTriggerImageLoad(image, lazyLoadEvent);\n });\n\n const loadVisibleImages = checkForImagesToLazyLoad.bind(\n null,\n lazyLoadEvent,\n images\n );\n\n /*\n * Add an event listener when the page is scrolled. To avoid bogging down the\n * page, we throttle this call to only run every 100ms.\n */\n const scrollHandler = throttle(loadVisibleImages, 100);\n window.addEventListener('scroll', scrollHandler);\n\n // Return a function to allow manual checks for images to lazy load.\n return loadVisibleImages;\n};\n\n/**\n * The public function to initialize lazyloading\n * @param {Object} config configuration options (see `initialize()`)\n * @return {Function} a function to manually check for images to lazy load\n */\nfunction lazyLoadImages(config = {}) {\n // If we have `srcset` support, initialize the lazyloader.\n /* istanbul ignore else: unreasonable to test browser support just for a no-op */\n if ('srcset' in document.createElement('img')) {\n return initialize(config);\n }\n\n // If there’s no support, return a no-op.\n /* istanbul ignore next: unreasonable to test browser support just for a no-op */\n return () => {\n /* no-op */\n };\n}\n\nexport default lazyLoadImages;\n"],"names":["isElementVisible","el","isCurrentlyVisible","offsetParent","position","getBoundingClientRect","wH","window","innerHeight","document","documentElement","clientHeight","isWithinViewport","top","bottom","throttle","func","limit","wait","call","maybeTriggerImageLoad","image","event","getAttribute","dispatchEvent","findImageElement","tagName","toLowerCase","querySelector","loadImage","target","srcset","setAttribute","removeLoadingClass","loadingClass","element","shouldReturn","classList","contains","remove","parentNode","checkForImagesToLazyLoad","lazyLoadEvent","images","forEach","initialize","containerClass","callback","e","containers","getElementsByClassName","add","map","Event","addEventListener","loadVisibleImages","bind","scrollHandler","lazyLoadImages","config","createElement"],"mappings":"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"}