{"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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"}