Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

loading-attribute-polyfill

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

loading-attribute-polyfill - npm Package Compare versions

Comparing version 2.0.0-beta.0 to 2.0.0-beta.1

.browserslistrc

1

bower.json

@@ -36,3 +36,2 @@ {

".huskyrc",
"config.codekit3",
"commitlint.config.js",

@@ -39,0 +38,0 @@ "wdio.conf-crossbrowsertesting.js"

@@ -9,2 +9,8 @@ # Changelog

## [2.0.0-beta.1] - 2021-03-04
### Changed
- BREAKING CHANGE: Even also generate JS modules from now on supported by [microbundle](https://npmjs.com/microbundle), added the relevant property entries within the `package.json` directing to those files, that are now stored within the `dist/` folder (see [migration guide](MIGRATION.md) [#19](https://github.com/mfranzke/loading-attribute-polyfill/issues/19), [#87](https://github.com/mfranzke/loading-attribute-polyfill/pull/87), [#39](https://github.com/mfranzke/loading-attribute-polyfill/pull/39))
## [2.0.0-beta.0] - 2021-03-04

@@ -11,0 +17,0 @@

@@ -13,252 +13,254 @@ /*

(function (noscriptClass, rootMargin) {
'use strict';
'use strict';
var config = {
// Start download if the item gets within 256px in the Y axis
rootMargin: rootMargin || '0px 0px 256px 0px',
threshold: 0.01,
lazyImage: 'img[loading="lazy"]',
lazyIframe: 'iframe[loading="lazy"]',
};
var config = {
// Start download if the item gets within 256px in the Y axis
rootMargin: '0px 0px 256px 0px',
threshold: 0.01,
lazyImage: 'img[loading="lazy"]',
lazyIframe: 'iframe[loading="lazy"]',
};
// Device/browser capabilities object
var capabilities = {
loading:
'loading' in HTMLImageElement.prototype &&
'loading' in HTMLIFrameElement.prototype,
scrolling: 'onscroll' in window,
};
// Device/browser capabilities object
var capabilities = {
loading:
'loading' in HTMLImageElement.prototype &&
'loading' in HTMLIFrameElement.prototype,
scrolling: 'onscroll' in window,
};
// Nodelist foreach polyfill / source: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#polyfill
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
// Nodelist foreach polyfill / source: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#polyfill
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
// Define according to browsers support of the IntersectionObserver feature (missing e.g. on IE11 or Safari 11)
var intersectionObserver;
// Define according to browsers support of the IntersectionObserver feature (missing e.g. on IE11 or Safari 11)
var intersectionObserver;
if ('IntersectionObserver' in window) {
intersectionObserver = new IntersectionObserver(onIntersection, config);
}
if ('IntersectionObserver' in window) {
intersectionObserver = new IntersectionObserver(onIntersection, config);
}
// On using a browser w/o requestAnimationFrame support (IE9, Opera Mini), just run the passed function
var rAFWrapper =
'requestAnimationFrame' in window
? window.requestAnimationFrame
: function (func) {
func();
};
// On using a browser w/o requestAnimationFrame support (IE9, Opera Mini), just run the passed function
var rAFWrapper =
'requestAnimationFrame' in window
? window.requestAnimationFrame
: function (func) {
func();
};
/**
* Put the source and srcset back where it belongs - now that the elements content is attached to the document, it will load now
* @param {Object} lazyItem Current item to be restored after lazy loading.
*/
function restoreSource(lazyItem) {
var srcsetItems = [];
/**
* Put the source and srcset back where it belongs - now that the elements content is attached to the document, it will load now
* @param {Object} lazyItem Current item to be restored after lazy loading.
*/
function restoreSource(lazyItem) {
var srcsetItems = [];
// Just in case the img is the decendent of a picture element, check for source tags
if (lazyItem.parentNode.tagName.toLowerCase() === 'picture') {
removePlaceholderSource(lazyItem.parentNode);
// Just in case the img is the decendent of a picture element, check for source tags
if (lazyItem.parentNode.tagName.toLowerCase() === 'picture') {
removePlaceholderSource(lazyItem.parentNode);
srcsetItems = Array.prototype.slice.call(
lazyItem.parentNode.querySelectorAll('source')
);
srcsetItems = Array.prototype.slice.call(
lazyItem.parentNode.querySelectorAll('source')
);
}
srcsetItems.push(lazyItem);
// Not using .dataset within those upfollowing lines of code for polyfill independent compatibility down to IE9
srcsetItems.forEach(function (item) {
if (item.hasAttribute('data-lazy-srcset')) {
item.setAttribute('srcset', item.getAttribute('data-lazy-srcset'));
item.removeAttribute('data-lazy-srcset'); // Not using delete .dataset here for compatibility down to IE9
}
});
srcsetItems.push(lazyItem);
lazyItem.setAttribute('src', lazyItem.getAttribute('data-lazy-src'));
lazyItem.removeAttribute('data-lazy-src'); // Not using delete .dataset here for compatibility down to IE9
}
// Not using .dataset within those upfollowing lines of code for polyfill independent compatibility down to IE9
srcsetItems.forEach(function (item) {
if (item.hasAttribute('data-lazy-srcset')) {
item.setAttribute('srcset', item.getAttribute('data-lazy-srcset'));
item.removeAttribute('data-lazy-srcset'); // Not using delete .dataset here for compatibility down to IE9
}
});
/**
* Remove the source tag preventing the loading of picture assets
* @param {Object} lazyItemPicture Current <picture> item to be restored after lazy loading.
*/
function removePlaceholderSource(lazyItemPicture) {
var placeholderSource = lazyItemPicture.querySelector(
'source[data-lazy-remove]'
);
lazyItem.setAttribute('src', lazyItem.getAttribute('data-lazy-src'));
lazyItem.removeAttribute('data-lazy-src'); // Not using delete .dataset here for compatibility down to IE9
if (placeholderSource) {
// Preferred .removeChild over .remove here for IE
lazyItemPicture.removeChild(placeholderSource);
}
}
/**
* Remove the source tag preventing the loading of picture assets
* @param {Object} lazyItemPicture Current <picture> item to be restored after lazy loading.
*/
function removePlaceholderSource(lazyItemPicture) {
var placeholderSource = lazyItemPicture.querySelector(
'source[data-lazy-remove]'
);
if (placeholderSource) {
lazyItemPicture.removeChild(placeholderSource); // Preferred .removeChild over .remove here for IE
/**
* Handle IntersectionObservers callback
* @param {Object} entries Target elements Intersection observed changes
* @param {Object} observer IntersectionObserver instance reference
*/
function onIntersection(entries, observer) {
entries.forEach(function (entry) {
// Mitigation for EDGE lacking support of .isIntersecting until v15, compare to e.g. https://github.com/w3c/IntersectionObserver/issues/211#issuecomment-309144669
if (entry.intersectionRatio === 0) {
return;
}
}
/**
* Handle IntersectionObservers callback
* @param {Object} entries Target elements Intersection observed changes
* @param {Object} observer IntersectionObserver instance reference
*/
function onIntersection(entries, observer) {
entries.forEach(function (entry) {
// Mitigation for EDGE lacking support of .isIntersecting until v15, compare to e.g. https://github.com/w3c/IntersectionObserver/issues/211#issuecomment-309144669
if (entry.intersectionRatio === 0) {
return;
}
// If the item is visible now, load it and stop watching it
var lazyItem = entry.target;
// If the item is visible now, load it and stop watching it
var lazyItem = entry.target;
observer.unobserve(lazyItem);
observer.unobserve(lazyItem);
restoreSource(lazyItem);
});
}
restoreSource(lazyItem);
});
/**
* Handle printing the page
*/
function onPrinting() {
if (typeof window.matchMedia === 'undefined') {
return;
}
/**
* Handle printing the page
*/
function onPrinting() {
if (typeof window.matchMedia === 'undefined') {
return;
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function (mql) {
if (mql.matches) {
document
.querySelectorAll(
config.lazyImage +
'[data-lazy-src],' +
config.lazyIframe +
'[data-lazy-src]'
)
.forEach(function (lazyItem) {
restoreSource(lazyItem);
});
}
});
}
var mediaQueryList = window.matchMedia('print');
/**
* Get and prepare the HTML code depending on feature detection for both image as well as iframe,
* and if not scrolling supported, because it's a Google or Bing Bot
* @param {String} lazyAreaHtml Noscript inner HTML code that src-urls need to get rewritten
*/
function getAndPrepareHTMLCode(noScriptTag) {
// The contents of a <noscript> tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;
mediaQueryList.addListener(function (mql) {
if (mql.matches) {
document
.querySelectorAll(
config.lazyImage +
'[data-lazy-src],' +
config.lazyIframe +
'[data-lazy-src]'
)
.forEach(function (lazyItem) {
restoreSource(lazyItem);
});
}
});
}
var getImageWidth = lazyAreaHtml.match(/width=['"](\d+)['"]/) || false;
var temporaryImageWidth = getImageWidth[1] || 1;
var getImageHeight = lazyAreaHtml.match(/height=['"](\d+)['"]/) || false;
var temporaryImageHeight = getImageHeight[1] || 1;
/**
* Get and prepare the HTML code depending on feature detection for both image as well as iframe,
* and if not scrolling supported, because it's a Google or Bing Bot
* @param {String} lazyAreaHtml Noscript inner HTML code that src-urls need to get rewritten
*/
function getAndPrepareHTMLCode(noScriptTag) {
// The contents of a <noscript> tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;
var temporaryImage =
'data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 ' +
temporaryImageWidth +
' ' +
temporaryImageHeight +
'%27%3E%3C/svg%3E';
var getImageWidth = lazyAreaHtml.match(/width=['"](\d+)['"]/) || false;
var temporaryImageWidth = getImageWidth[1] || 1;
var getImageHeight = lazyAreaHtml.match(/height=['"](\d+)['"]/) || false;
var temporaryImageHeight = getImageHeight[1] || 1;
if (!capabilities.loading && capabilities.scrolling) {
// Check for IntersectionObserver support
if (typeof intersectionObserver === 'undefined') {
// Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available
lazyAreaHtml = lazyAreaHtml.replace(
/(?:\r\n|\r|\n|\t| )src=/g,
' lazyload="1" src='
);
} else {
// Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a simple one (data URI)
lazyAreaHtml = lazyAreaHtml.replace(
'<source',
'<source srcset="' +
temporaryImage +
'" data-lazy-remove="true"></source>\n<source'
);
var temporaryImage =
'data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 ' +
temporaryImageWidth +
' ' +
temporaryImageHeight +
'%27%3E%3C/svg%3E';
if (!capabilities.loading && capabilities.scrolling) {
// Check for IntersectionObserver support
if (typeof intersectionObserver === 'undefined') {
// Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available
lazyAreaHtml = lazyAreaHtml.replace(
// 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)
lazyAreaHtml = lazyAreaHtml
.replace(/(?:\r\n|\r|\n|\t| )srcset=/g, ' data-lazy-srcset=')
.replace(
/(?:\r\n|\r|\n|\t| )src=/g,
' lazyload="1" src='
' src="' + temporaryImage + '" data-lazy-src='
);
} else {
// Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a simple one (data URI)
lazyAreaHtml = lazyAreaHtml.replace(
'<source',
'<source srcset="' +
temporaryImage +
'" data-lazy-remove="true"></source>\n<source'
);
// 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)
lazyAreaHtml = lazyAreaHtml
.replace(/(?:\r\n|\r|\n|\t| )srcset=/g, ' data-lazy-srcset=')
.replace(
/(?:\r\n|\r|\n|\t| )src=/g,
' src="' + temporaryImage + '" data-lazy-src='
);
}
}
return lazyAreaHtml;
}
/**
* Retrieve the elements from the 'lazy load' <noscript> tag and prepare them for display
* @param {Object} noScriptTag noscript HTML tag that should get initially transformed
*/
function prepareElement(noScriptTag) {
// Sticking the noscript HTML code in the innerHTML of a new <div> tag to 'load' it after creating that <div>
var lazyArea = document.createElement('div');
return lazyAreaHtml;
}
lazyArea.innerHTML = getAndPrepareHTMLCode(noScriptTag);
/**
* Retrieve the elements from the 'lazy load' <noscript> tag and prepare them for display
* @param {Object} noScriptTag noscript HTML tag that should get initially transformed
*/
function prepareElement(noScriptTag) {
// Sticking the noscript HTML code in the innerHTML of a new <div> tag to 'load' it after creating that <div>
var lazyArea = document.createElement('div');
// Move all children out of the element
while (lazyArea.firstChild) {
var actualChild = lazyArea.firstChild;
lazyArea.innerHTML = getAndPrepareHTMLCode(noScriptTag);
if (
!capabilities.loading &&
capabilities.scrolling &&
typeof intersectionObserver !== 'undefined' &&
actualChild.tagName &&
(actualChild.tagName.toLowerCase() === 'img' ||
actualChild.tagName.toLowerCase() === 'picture' ||
actualChild.tagName.toLowerCase() === 'iframe')
) {
var observedElement =
actualChild.tagName.toLowerCase() === 'picture'
? lazyArea.querySelector('img')
: actualChild;
// Observe the item so that loading could start when it gets close to the viewport
intersectionObserver.observe(observedElement);
}
// Move all children out of the element
while (lazyArea.firstChild) {
var actualChild = lazyArea.firstChild;
noScriptTag.parentNode.insertBefore(actualChild, noScriptTag);
if (
!capabilities.loading &&
capabilities.scrolling &&
typeof intersectionObserver !== 'undefined' &&
actualChild.tagName &&
(actualChild.tagName.toLowerCase() === 'img' ||
actualChild.tagName.toLowerCase() === 'picture' ||
actualChild.tagName.toLowerCase() === 'iframe')
) {
var observedElement =
actualChild.tagName.toLowerCase() === 'picture'
? lazyArea.querySelector('img')
: actualChild;
// Observe the item so that loading could start when it gets close to the viewport
intersectionObserver.observe(observedElement);
}
// Remove the empty element - not using .remove() here for IE11 compatibility
noScriptTag.parentNode.removeChild(noScriptTag); // Preferred .removeChild over .remove here for IE
noScriptTag.parentNode.insertBefore(actualChild, noScriptTag);
}
/**
* Get all the <noscript> tags on the page and setup the printing
*/
function prepareElements() {
//
var lazyLoadAreas = document.querySelectorAll('noscript.' + noscriptClass);
// Remove the empty element - not using .remove() here for IE11 compatibility
noScriptTag.parentNode.removeChild(noScriptTag);
}
lazyLoadAreas.forEach(function (element) {
prepareElement(element);
});
/**
* Get all the <noscript> tags on the page and setup the printing
*/
let prepareElements = () => {
var lazyLoadAreas = document.querySelectorAll('noscript.loading-lazy');
// Bind for someone printing the page
onPrinting();
}
lazyLoadAreas.forEach((element) => prepareElement(element));
// If the page has loaded already, run setup - if it hasn't, run as soon as it has.
// Use requestAnimationFrame as this will propably cause repaints
// document.readyState values: https://www.w3schools.com/jsref/prop_doc_readystate.asp
if (/comp|inter/.test(document.readyState)) {
// Bind for someone printing the page
onPrinting();
};
// If the page has loaded already, run setup - if it hasn't, run as soon as it has.
// Use requestAnimationFrame as this will propably cause repaints
// document.readyState values: https://www.w3schools.com/jsref/prop_doc_readystate.asp
if (/comp|inter/.test(document.readyState)) {
rAFWrapper(prepareElements);
} else if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function () {
rAFWrapper(prepareElements);
} else if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function () {
rAFWrapper(prepareElements);
});
} else {
document.attachEvent('onreadystatechange', function () {
if (document.readyState === 'complete') {
prepareElements();
}
});
}
})('loading-lazy', '256px 0px');
});
} else {
document.attachEvent('onreadystatechange', function () {
if (document.readyState === 'complete') {
prepareElements();
}
});
}
const loadingAttributePolyfill = {
prepareElement: prepareElement,
};
export default loadingAttributePolyfill;
# Migration guidelines
## 2.0.0 migration guide
## 2.0.0-beta.1 migration guide
We've switched from previously only providing the source and a minified version of the JS, to additionally provide the different relevant JavaScript formats especially regarding modules supported by [microbundle](https://npmjs.com/microbundle). Thatfor we even also changed the location of the generated files as well as pointed the relevant property entries within the `package.json` to those files. Please find all the relevant generated files in the `dist/` folder from now on.
## 2.0.0-beta.0 migration guide
You'll need to wrap the `<picture>` tag instead of the included HTML tags with `<noscript>`.

@@ -6,0 +10,0 @@

{
"name": "loading-attribute-polyfill",
"version": "2.0.0-beta.0",
"version": "2.0.0-beta.1",
"description": "Fast and lightweight dependency-free vanilla JavaScript polyfill for native lazy loading / the awesome loading='lazy'-attribute.",
"main": "loading-attribute-polyfill.min.js",
"source": "./loading-attribute-polyfill.js",
"main": "./dist/loading-attribute-polyfill.js",
"esmodule": "./dist/loading-attribute-polyfill.modern.js",
"module": "./dist/loading-attribute-polyfill.module.js",
"umd:main": "./dist/loading-attribute-polyfill.umd.js",
"repository": {

@@ -38,6 +42,7 @@ "type": "git",

"husky": "^5.1.2",
"microbundle": "^0.13.0",
"npm-run-all": "^4.1.5",
"prettier": "2.2.1",
"pretty-quick": "^3.1.0",
"webdriverio": "^6.1.12",
"webdriverio": "^6.12.1",
"xo": "^0.38.2"

@@ -49,2 +54,4 @@ },

"validate:html": "html-validate demo/index.html",
"build": "microbundle",
"dev": "microbundle watch",
"release:minor": "npm version minor -m 'build(release): new minor version' && git push && git push --tags && npm publish",

@@ -51,0 +58,0 @@ "release:patch": "npm version patch -m 'build(release): new patch version' && git push && git push --tags && npm publish",

@@ -141,4 +141,8 @@ # loading="lazy" attribute polyfill

Nothing really, just integrate it as shown within the "installation" section, and it ~~will~~ should work out of the box.
In case that you're dynamically adding HTML elements within the browser, you could call the following method with an included [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) object, like e.g.:
```JavaScript
loadingAttributePolyfill.prepareElement(document.querySelector('main noscript.loading-lazy'));
```
## Demo

@@ -145,0 +149,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc