{"version":3,"file":"loading-attribute-polyfill.umd.js","sources":["../src/loading-attribute-polyfill.js"],"sourcesContent":["/*\n * Loading attribute polyfill - https://github.com/mfranzke/loading-attribute-polyfill\n * @license Copyright(c) 2019 by Maximilian Franzke\n * Credits for the initial kickstarter / script to @Sora2455, and supported by @cbirdsong, @eklingen, @DaPo, @nextgenthemes, @diogoterremoto, @dracos, @Flimm, @TomS-, @vinyfc93, @JordanDysart and @denyshutsal - many thanks for that !\n */\n/*\n * A minimal and dependency-free vanilla JavaScript loading attribute polyfill.\n * Supports standard's functionality and tests for native support upfront.\n * Elsewhere the functionality gets emulated with the support of noscript wrapper tags.\n * Use an IntersectionObserver polyfill in case of IE11 support necessary.\n */\n\nimport './loading-attribute-polyfill.css';\n\nconst config = {\n\tintersectionObserver: {\n\t\t// Start download if the item gets within 256px in the Y axis\n\t\trootMargin: '0px 0px 256px 0px',\n\t\tthreshold: 0.01,\n\t},\n\tlazyImage: 'img[loading=\"lazy\"]',\n\tlazyIframe: 'iframe[loading=\"lazy\"]',\n};\n\n// Device/browser capabilities object\nconst capabilities = {\n\tloading: {\n\t\timage: 'loading' in HTMLImageElement.prototype,\n\t\tiframe: 'loading' in HTMLIFrameElement.prototype,\n\t},\n\tscrolling: 'onscroll' in window,\n};\n\n// Nodelist foreach polyfill / source: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#polyfill\nif (window.NodeList && !NodeList.prototype.forEach) {\n\tNodeList.prototype.forEach = Array.prototype.forEach;\n}\n\n// Define according to browsers support of the IntersectionObserver feature (missing e.g. on IE11 or Safari 11)\nlet intersectionObserver;\n\nif ('IntersectionObserver' in window) {\n\tintersectionObserver = new IntersectionObserver(\n\t\tonIntersection,\n\t\tconfig.intersectionObserver\n\t);\n}\n\n/**\n * Put the source and srcset back where it belongs - now that the elements content is attached to the document, it will load now\n * @param {Object} lazyItem Current item to be restored after lazy loading.\n */\nfunction restoreSource(lazyItem) {\n\tlet srcsetItems = [];\n\n\t// Just in case the img is the decendent of a picture element, check for source tags\n\tif (lazyItem.parentNode.tagName.toLowerCase() === 'picture') {\n\t\tremovePlaceholderSource(lazyItem.parentNode);\n\n\t\tsrcsetItems = Array.prototype.slice.call(\n\t\t\tlazyItem.parentNode.querySelectorAll('source')\n\t\t);\n\t}\n\n\tsrcsetItems.push(lazyItem);\n\n\t// Not using .dataset within those upfollowing lines of code for polyfill independent compatibility down to IE9\n\tsrcsetItems.forEach((item) => {\n\t\t/* eslint-disable unicorn/prefer-dom-node-dataset */\n\t\tif (item.hasAttribute('data-lazy-srcset')) {\n\t\t\titem.setAttribute('srcset', item.getAttribute('data-lazy-srcset'));\n\t\t\titem.removeAttribute('data-lazy-srcset'); // Not using delete .dataset here for compatibility down to IE9\n\t\t}\n\t\t/* eslint-enable unicorn/prefer-dom-node-dataset */\n\t});\n\n\t/* eslint-disable unicorn/prefer-dom-node-dataset */\n\tlazyItem.setAttribute('src', lazyItem.getAttribute('data-lazy-src'));\n\tlazyItem.removeAttribute('data-lazy-src'); // Not using delete .dataset here for compatibility down to IE9\n\t/* eslint-enable unicorn/prefer-dom-node-dataset */\n}\n\n/**\n * Remove the source tag preventing the loading of picture assets\n * @param {Object} lazyItemPicture Current <picture> item to be restored after lazy loading.\n */\nfunction removePlaceholderSource(lazyItemPicture) {\n\tconst placeholderSource = lazyItemPicture.querySelector(\n\t\t'source[data-lazy-remove]'\n\t);\n\n\tif (placeholderSource) {\n\t\t// Preferred .removeChild over .remove here for IE\n\t\tlazyItemPicture.removeChild(placeholderSource);\n\t}\n}\n\n/**\n * Handle IntersectionObservers callback\n * @param {Object} entries Target elements Intersection observed changes\n * @param {Object} observer IntersectionObserver instance reference\n */\nfunction onIntersection(entries, observer) {\n\tentries.forEach((entry) => {\n\t\t// Mitigation for EDGE lacking support of .isIntersecting until v15, compare to e.g. https://github.com/w3c/IntersectionObserver/issues/211#issuecomment-309144669\n\t\tif (entry.intersectionRatio === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the item is visible now, load it and stop watching it\n\t\tconst lazyItem = entry.target;\n\n\t\tobserver.unobserve(lazyItem);\n\n\t\trestoreSource(lazyItem);\n\t});\n}\n\n/**\n * Handle printing the page\n */\nfunction onPrinting() {\n\tif (typeof window.matchMedia === 'undefined') {\n\t\treturn;\n\t}\n\n\tconst mediaQueryList = window.matchMedia('print');\n\n\tmediaQueryList.addListener((mql) => {\n\t\tif (mql.matches) {\n\t\t\tdocument\n\t\t\t\t.querySelectorAll(\n\t\t\t\t\tconfig.lazyImage +\n\t\t\t\t\t\t'[data-lazy-src],' +\n\t\t\t\t\t\tconfig.lazyIframe +\n\t\t\t\t\t\t'[data-lazy-src]'\n\t\t\t\t)\n\t\t\t\t.forEach((lazyItem) => {\n\t\t\t\t\trestoreSource(lazyItem);\n\t\t\t\t});\n\t\t}\n\t});\n}\n\n/**\n * Get and prepare the HTML code depending on feature detection for both image as well as iframe,\n * and if not scrolling supported, because it's a Google or Bing Bot\n * @param {String} lazyAreaHtml Noscript inner HTML code that src-urls need to get rewritten\n */\nfunction getAndPrepareHTMLCode(noScriptTag) {\n\t// The contents of a <noscript> tag are treated as text to JavaScript\n\tlet lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;\n\n\tconst getImageWidth = lazyAreaHtml.match(/width=['\"](\\d+)['\"]/) || false;\n\tconst temporaryImageWidth = getImageWidth[1] || 1;\n\tconst getImageHeight = lazyAreaHtml.match(/height=['\"](\\d+)['\"]/) || false;\n\tconst temporaryImageHeight = getImageHeight[1] || 1;\n\n\tconst temporaryImage =\n\t\t'data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 ' +\n\t\ttemporaryImageWidth +\n\t\t' ' +\n\t\ttemporaryImageHeight +\n\t\t'%27%3E%3C/svg%3E';\n\n\t// Test for whether it's image or iframe content, their support by the browser and regarding the scrolling capability\n\tif (\n\t\t((/<img/gim.test(lazyAreaHtml) && !capabilities.loading.image) ||\n\t\t\t(/<iframe/gim.test(lazyAreaHtml) && !capabilities.loading.iframe)) &&\n\t\tcapabilities.scrolling\n\t) {\n\t\t// Check for IntersectionObserver support\n\t\tif (typeof intersectionObserver === 'undefined') {\n\t\t\t// Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available\n\t\t\tlazyAreaHtml = lazyAreaHtml.replace(\n\t\t\t\t/(?:\\r\\n|\\r|\\n|\\t| )src=/g,\n\t\t\t\t' lazyload=\"1\" src='\n\t\t\t);\n\t\t} else {\n\t\t\t// Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a simple one (data URI)\n\t\t\tlazyAreaHtml = lazyAreaHtml.replace(\n\t\t\t\t'<source',\n\t\t\t\t'<source srcset=\"' +\n\t\t\t\t\ttemporaryImage +\n\t\t\t\t\t'\" data-lazy-remove=\"true\"></source>\\n<source'\n\t\t\t);\n\n\t\t\t// Temporarily replace a expensive resource load with a simple one by storing the actual source and srcset for later and point src to a temporary replacement (data URI)\n\t\t\tlazyAreaHtml = lazyAreaHtml\n\t\t\t\t.replace(/(?:\\r\\n|\\r|\\n|\\t| )srcset=/g, ' data-lazy-srcset=')\n\t\t\t\t.replace(\n\t\t\t\t\t/(?:\\r\\n|\\r|\\n|\\t| )src=/g,\n\t\t\t\t\t' src=\"' + temporaryImage + '\" data-lazy-src='\n\t\t\t\t);\n\t\t}\n\t}\n\n\treturn lazyAreaHtml;\n}\n\n/**\n * Retrieve the elements from the 'lazy load' <noscript> tag and prepare them for display\n * @param {Object} noScriptTag noscript HTML tag that should get initially transformed\n */\nfunction prepareElement(noScriptTag) {\n\t// Sticking the noscript HTML code in the innerHTML of a new <div> tag to 'load' it after creating that <div>\n\tconst lazyArea = document.createElement('div');\n\n\tlazyArea.innerHTML = getAndPrepareHTMLCode(noScriptTag);\n\n\t// Move all children out of the element\n\twhile (lazyArea.firstChild) {\n\t\tconst actualChild = lazyArea.firstChild;\n\n\t\tif (\n\t\t\tcapabilities.scrolling &&\n\t\t\ttypeof intersectionObserver !== 'undefined' &&\n\t\t\tactualChild.tagName &&\n\t\t\t(((actualChild.tagName.toLowerCase() === 'img' ||\n\t\t\t\tactualChild.tagName.toLowerCase() === 'picture') &&\n\t\t\t\t!capabilities.loading.image) ||\n\t\t\t\t(actualChild.tagName.toLowerCase() === 'iframe' &&\n\t\t\t\t\t!capabilities.loading.iframe))\n\t\t) {\n\t\t\tconst observedElement =\n\t\t\t\tactualChild.tagName.toLowerCase() === 'picture'\n\t\t\t\t\t? lazyArea.querySelector('img')\n\t\t\t\t\t: actualChild;\n\t\t\t// Observe the item so that loading could start when it gets close to the viewport\n\t\t\tintersectionObserver.observe(observedElement);\n\t\t}\n\n\t\tnoScriptTag.parentNode.insertBefore(actualChild, noScriptTag);\n\t}\n\n\t// Remove the empty element - not using .remove() here for IE11 compatibility\n\tnoScriptTag.parentNode.removeChild(noScriptTag);\n}\n\n/**\n * Get all the <noscript> tags on the page, prepare each and any one of them and setup the printing\n */\nconst prepareElements = () => {\n\tconst lazyLoadAreas = document.querySelectorAll('noscript.loading-lazy');\n\n\tlazyLoadAreas.forEach((element) => prepareElement(element));\n\n\t// Bind for someone printing the page\n\tonPrinting();\n};\n\n// If the page has loaded already, run setup - if it hasn't, run as soon as it has.\n// document.readyState values: https://www.w3schools.com/jsref/prop_doc_readystate.asp\nif (/comp|inter/.test(document.readyState)) {\n\tprepareElements();\n} else if ('addEventListener' in document) {\n\tdocument.addEventListener('DOMContentLoaded', () => {\n\t\tprepareElements();\n\t});\n} else {\n\tdocument.attachEvent('onreadystatechange', () => {\n\t\tif (document.readyState === 'complete') {\n\t\t\tprepareElements();\n\t\t}\n\t});\n}\n\nconst loadingAttributePolyfill = {\n\tprepareElement,\n};\n\nexport default loadingAttributePolyfill;\n"],"names":["intersectionObserver","capabilities","HTMLImageElement","prototype","HTMLIFrameElement","window","restoreSource","lazyItem","lazyItemPicture","placeholderSource","srcsetItems","parentNode","tagName","toLowerCase","querySelector","removeChild","Array","slice","call","querySelectorAll","push","forEach","item","hasAttribute","setAttribute","getAttribute","removeAttribute","prepareElement","noScriptTag","lazyArea","document","createElement","innerHTML","lazyAreaHtml","textContent","temporaryImage","match","test","replace","getAndPrepareHTMLCode","firstChild","actualChild","observedElement","observe","insertBefore","NodeList","IntersectionObserver","entries","observer","entry","intersectionRatio","target","unobserve","rootMargin","threshold","prepareElements","element","matchMedia","addListener","mql","matches","config","readyState","addEventListener","attachEvent"],"mappings":"2OAcA,IAyBIA,EAdEC,EAEG,YAAaC,iBAAiBC,UAFjCF,EAGI,YAAaG,kBAAkBD,UAHnCF,EAKM,aAAcI,OAsB1B,SAASC,EAAcC,GACtB,IAiCgCC,EAC1BC,EAlCFC,EAAc,GAGgC,YAA9CH,EAASI,WAAWC,QAAQC,iBA+B1BJ,GAD0BD,EA7BPD,EAASI,YA8BQG,cACzC,8BAKAN,EAAgBO,YAAYN,GAlC5BC,EAAcM,MAAMb,UAAUc,MAAMC,KACnCX,EAASI,WAAWQ,iBAAiB,YAIvCT,EAAYU,KAAKb,GAGjBG,EAAYW,QAAQ,SAACC,GAEhBA,EAAKC,aAAa,sBACrBD,EAAKE,aAAa,SAAUF,EAAKG,aAAa,qBAC9CH,EAAKI,gBAAgB,uBAMvBnB,EAASiB,aAAa,MAAOjB,EAASkB,aAAa,kBACnDlB,EAASmB,gBAAgB,iBA8H1B,SAASC,EAAeC,GAEvB,IAAMC,EAAWC,SAASC,cAAc,OAKxC,IAHAF,EAASG,UA3DV,SAA+BJ,GAE9B,IAAIK,EAAeL,EAAYM,aAAeN,EAAYI,UAOpDG,EACL,qFANqBF,EAAaG,MAAM,yBAA0B,GACzB,IAAM,GAO/C,MANsBH,EAAaG,MAAM,0BAA2B,GACzB,IAAM,GAOjD,mBAkCD,OA9BG,UAAUC,KAAKJ,KAAkBhC,GACjC,aAAaoC,KAAKJ,KAAkBhC,IACtCA,IAKCgC,OAFmC,IAAzBjC,EAEKiC,EAAaK,QAC3B,2BACA,uBAIDL,EAAeA,EAAaK,QAC3B,UACA,mBACCH,EACA,iDAKAG,QAAQ,8BAA+B,sBACvCA,QACA,2BACA,SAAWH,EAAiB,qBAKzBF,EAWcM,CAAsBX,GAGpCC,EAASW,YAAY,CAC3B,IAAMC,EAAcZ,EAASW,WAE7B,GACCvC,QACgC,IAAzBD,GACPyC,EAAY7B,WAC6B,QAAtC6B,EAAY7B,QAAQC,eACgB,YAAtC4B,EAAY7B,QAAQC,iBACnBZ,GACsC,WAAtCwC,EAAY7B,QAAQC,gBACnBZ,GACF,CACD,IAAMyC,EACiC,YAAtCD,EAAY7B,QAAQC,cACjBgB,EAASf,cAAc,OACvB2B,EAEJzC,EAAqB2C,QAAQD,GAG9Bd,EAAYjB,WAAWiC,aAAaH,EAAab,GAIlDA,EAAYjB,WAAWI,YAAYa,GA1MhCvB,OAAOwC,WAAaA,SAAS1C,UAAUkB,UAC1CwB,SAAS1C,UAAUkB,QAAUL,MAAMb,UAAUkB,SAM1C,yBAA0BhB,SAC7BL,EAAuB,IAAI8C,qBA4D5B,SAAwBC,EAASC,GAChCD,EAAQ1B,QAAQ,SAAC4B,GAEhB,GAAgC,IAA5BA,EAAMC,kBAAV,CAKA,IAAM3C,EAAW0C,EAAME,OAEvBH,EAASI,UAAU7C,GAEnBD,EAAcC,OAnGO,CAErB8C,WAAY,oBACZC,UAAW,OAgOb,IAAMC,EAAkB,WACDzB,SAASX,iBAAiB,yBAElCE,QAAQ,SAACmC,UAAY7B,EAAe6B,UA3HjB,IAAtBnD,OAAOoD,YAIKpD,OAAOoD,WAAW,SAE1BC,YAAY,SAACC,GACvBA,EAAIC,SACP9B,SACEX,iBACA0C,4EAKAxC,QAAQ,SAACd,GACTD,EAAcC,cAmHf,aAAa8B,KAAKP,SAASgC,YAC9BP,IACU,qBAAsBzB,SAChCA,SAASiC,iBAAiB,mBAAoB,WAC7CR,MAGDzB,SAASkC,YAAY,qBAAsB,WACd,aAAxBlC,SAASgC,YACZP,MAK8B,CAChC5B,eAAAA"}