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 0.2.0 to 1.0.0

wdio.conf-crossbrowsertesting.js

22

CHANGELOG.md

@@ -11,6 +11,22 @@ # Changelog

- Documentation
- Cross browser todos
- Tests
- Ongoing: Further documentation
## [1.0.0] - 2019-08-10
### Added
- Comment regarding asynchronous loading
- Webdriver.io testing
### Changed
- BREAKING CHANGE: You#ll need to also wrap the `<source>` HTML tags within the `<picture>` tags with `<noscript>`
### Fix
- Documents markup regarding codacy suggestions
- Corrected sample image measurements
- The images didn't load lazily in Safari, but directly, as reported with #GH-3
- Displaying the images on smaller viewports on the sample page
## [0.2.0] - 2019-05-22

@@ -17,0 +33,0 @@

155

loading-attribute-polyfill.js

@@ -20,3 +20,6 @@ /*

lazyImage: 'img[loading="lazy"]',
lazyIframe: 'iframe[loading="lazy"]'
lazyIframe: 'iframe[loading="lazy"]',
loadingSupported:
'loading' in HTMLImageElement.prototype &&
'loading' in HTMLIFrameElement.prototype
};

@@ -47,18 +50,12 @@

* Temporarily replace a expensive resource load with a simple one
* @param {Object} lazyItem Current item to be transformed for lazy loading.
* @param {string} tempData Temporary data to be inserted as a 'placeholder'.
* @param {String} lazyItem Current item to be transformed for lazy loading.
*/
function storeSourceForLater(lazyItem, tempData) {
// Store the actual source and srcset for later
lazyItem.dataset.lazySrc = lazyItem.getAttribute('src');
if (lazyItem.getAttribute('srcset')) {
lazyItem.dataset.lazySrcset = lazyItem.getAttribute('srcset');
}
// Set the item to point to a temporary replacement (data URI) and remove srcset
lazyItem.setAttribute('src', tempData);
lazyItem.removeAttribute('srcset');
// Now observe the item so that loading could start when it gets close to the viewport
intersectionObserver.observe(lazyItem);
function rewriteSourceForLater(lazyItem) {
// Store the actual source and srcset for later and point src to a temporary replacement (data URI)
return lazyItem
.replace(/(?:\r\n|\r|\n|\t| )srcset=/g, ' data-lazy-srcset=')
.replace(
/(?:\r\n|\r|\n|\t| )src=/g,
' src="' + temporaryImage + '" data-lazy-src='
);
}

@@ -68,45 +65,20 @@

* Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a simple one (data URI)
* @param {Object} lazyItem Current item to be transformed for lazy loading.
* @param {string} tempData Temporary data to be inserted as a 'placeholder'.
* @param {String} lazyItem Current item to be transformed for lazy loading.
*/
function placeholderSourceLoading(lazyItem, tempData) {
var placeholderSource = document.createElement('source');
placeholderSource.setAttribute('srcset', tempData);
placeholderSource.dataset.lazyRemove = true;
function placeholderSourceLoading(lazyItem) {
// Adding this <source> tag at the start of the picture tag means the browser will load it first
lazyItem.insertBefore(placeholderSource, lazyItem.firstChild);
var baseImage = lazyItem.querySelector('img');
if (baseImage) {
// On <picture> tags image needs to get observed (as the picture tag is smaller than the image most likely)
intersectionObserver.observe(baseImage);
}
return (
'<source srcset="' +
temporaryImage +
'" data-lazy-remove="true"></source>' +
lazyItem
);
}
/**
* Set up the lazy items so that they won't try to load after adding them to the document
* @param {Object} lazyArea Temporary created element for handling the <noscript> content
* @param {Object} noScriptTagParentNode Parent node of <noscript> HTML tag
* Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available
* @param {String} lazyItem Current item to be transformed for lazy loading.
*/
function prepareLazyContents(lazyArea, noScriptTagParentNode) {
var lazyItem = lazyArea.querySelector(
config.lazyImage + ',' + config.lazyIframe
);
// Check for IntersectionObserver support to not delay loading of the items content
if (typeof intersectionObserver === 'undefined') {
// Attach abandonned attribute 'lazyload' to the HTML tags on browsers w/o IntersectionObserver being available
lazyItem.setAttribute('lazyload', 1);
return;
}
storeSourceForLater(lazyItem, temporaryImage);
if (noScriptTagParentNode.tagName.toLowerCase() === 'picture') {
placeholderSourceLoading(noScriptTagParentNode, temporaryImage);
}
function addLazyloadAttribute(lazyItem) {
return lazyItem.replace(/(?:\r\n|\r|\n|\t| )src=/g, ' lazyload="1" src=');
}

@@ -119,12 +91,20 @@

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);
}
if (lazyItem.dataset.lazySrcset) {
lazyItem.setAttribute('srcset', lazyItem.dataset.lazySrcset);
delete lazyItem.dataset.lazySrcset;
srcsetItems.push(...lazyItem.parentNode.querySelectorAll('source'));
}
srcsetItems.push(lazyItem);
srcsetItems.forEach(function(item) {
if (item.dataset.lazySrcset) {
item.setAttribute('srcset', item.dataset.lazySrcset);
delete item.dataset.lazySrcset;
}
});
lazyItem.setAttribute('src', lazyItem.dataset.lazySrc);

@@ -177,12 +157,12 @@ delete lazyItem.dataset.lazySrc;

if (mql.matches) {
var lazyItems = document.querySelectorAll(
config.lazyImage +
'[data-lazy-src],' +
config.lazyIframe +
'[data-lazy-src]'
);
lazyItems.forEach(function(lazyItem) {
restoreSource(lazyItem);
});
document
.querySelectorAll(
config.lazyImage +
'[data-lazy-src],' +
config.lazyIframe +
'[data-lazy-src]'
)
.forEach(function(lazyItem) {
restoreSource(lazyItem);
});
}

@@ -203,2 +183,16 @@ });

// Feature detection for both image as well as iframe
if (!config.loadingSupported) {
// Check for IntersectionObserver support
if (typeof intersectionObserver !== 'undefined') {
if (noScriptTag.parentNode.tagName.toLowerCase() === 'picture') {
lazyAreaHtml = placeholderSourceLoading(lazyAreaHtml);
}
lazyAreaHtml = rewriteSourceForLater(lazyAreaHtml);
} else {
lazyAreaHtml = addLazyloadAttribute(lazyAreaHtml);
}
}
// Sticking them in the innerHTML of a new <div> tag to 'load' them

@@ -209,18 +203,19 @@ var lazyArea = document.createElement('div');

var noScriptTagParentNode = noScriptTag.parentNode;
// move all children out of the element
while (lazyArea.firstChild) {
if (
!config.loadingSupported &&
lazyArea.firstChild.tagName &&
(lazyArea.firstChild.tagName.toLowerCase() === 'img' ||
lazyArea.firstChild.tagName.toLowerCase() === 'iframe')
) {
// Observe the item so that loading could start when it gets close to the viewport
intersectionObserver.observe(lazyArea.firstChild);
}
// Feature detection for both image as well as iframe
if (
!(
'loading' in HTMLImageElement.prototype &&
'loading' in HTMLIFrameElement.prototype
)
) {
prepareLazyContents(lazyArea, noScriptTagParentNode);
noScriptTag.parentNode.insertBefore(lazyArea.firstChild, noScriptTag);
}
noScriptTagParentNode.replaceChild(
lazyArea.firstElementChild,
noScriptTag
);
// remove the empty element
noScriptTag.remove();
});

@@ -227,0 +222,0 @@

@@ -5,2 +5,2 @@ /*

*/
!function(e,t){"use strict";var a,r,n={rootMargin:"256px 0px",threshold:.01,lazyImage:'img[loading="lazy"]',lazyIframe:'iframe[loading="lazy"]'};"IntersectionObserver"in window&&(a=new IntersectionObserver(function(e,t){e.forEach(function(e){if(0!==e.intersectionRatio){var a=e.target;t.unobserve(a),c(a)}})},n)),r="requestAnimationFrame"in window?window.requestAnimationFrame:function(e){e()};var o="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";function i(e,t){var r=e.querySelector(n.lazyImage+","+n.lazyIframe);void 0!==a?(function(e,t){e.dataset.lazySrc=e.getAttribute("src"),e.getAttribute("srcset")&&(e.dataset.lazySrcset=e.getAttribute("srcset")),e.setAttribute("src",t),e.removeAttribute("srcset"),a.observe(e)}(r,o),"picture"===t.tagName.toLowerCase()&&function(e,t){var r=document.createElement("source");r.setAttribute("srcset",t),r.dataset.lazyRemove=!0,e.insertBefore(r,e.firstChild);var n=e.querySelector("img");n&&a.observe(n)}(t,o)):r.setAttribute("lazyload",1)}function c(e){var t,a;"picture"===e.parentNode.tagName.toLowerCase()&&(t=e.parentNode,(a=t.querySelector("source[data-lazy-remove]"))&&t.removeChild(a)),e.dataset.lazySrcset&&(e.setAttribute("srcset",e.dataset.lazySrcset),delete e.dataset.lazySrcset),e.setAttribute("src",e.dataset.lazySrc),delete e.dataset.lazySrc}function s(){document.querySelectorAll("noscript."+e).forEach(function(e){var t=e.textContent||e.innerHTML,a=document.createElement("div");a.innerHTML=t;var r=e.parentNode;"loading"in HTMLImageElement.prototype&&"loading"in HTMLIFrameElement.prototype||i(a,r),r.replaceChild(a.firstElementChild,e)}),window.matchMedia("print").addListener(function(e){e.matches&&document.querySelectorAll(n.lazyImage+"[data-lazy-src],"+n.lazyIframe+"[data-lazy-src]").forEach(function(e){c(e)})})}/comp|inter/.test(document.readyState)?r(s):"addEventListener"in document?document.addEventListener("DOMContentLoaded",function(){r(s)}):document.attachEvent("onreadystatechange",function(){"complete"===document.readyState&&s()})}("loading-lazy");
!function(e,t){"use strict";var r,a,n={rootMargin:"256px 0px",threshold:.01,lazyImage:'img[loading="lazy"]',lazyIframe:'iframe[loading="lazy"]',loadingSupported:"loading"in HTMLImageElement.prototype&&"loading"in HTMLIFrameElement.prototype};"IntersectionObserver"in window&&(r=new IntersectionObserver(function(e,t){e.forEach(function(e){if(0!==e.intersectionRatio){var r=e.target;t.unobserve(r),i(r)}})},n)),a="requestAnimationFrame"in window?window.requestAnimationFrame:function(e){e()};var o="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";function i(e){var t,r,a=[];"picture"===e.parentNode.tagName.toLowerCase()&&(t=e.parentNode,(r=t.querySelector("source[data-lazy-remove]"))&&t.removeChild(r),a.push(...e.parentNode.querySelectorAll("source"))),a.push(e),a.forEach(function(e){e.dataset.lazySrcset&&(e.setAttribute("srcset",e.dataset.lazySrcset),delete e.dataset.lazySrcset)}),e.setAttribute("src",e.dataset.lazySrc),delete e.dataset.lazySrc}function c(){document.querySelectorAll("noscript."+e).forEach(function(e){var t=e.textContent||e.innerHTML;n.loadingSupported||(void 0!==r?("picture"===e.parentNode.tagName.toLowerCase()&&(t='<source srcset="'+o+'" data-lazy-remove="true"></source>'+t),t=function(e){return e.replace(/(?:\r\n|\r|\n|\t| )srcset=/g," data-lazy-srcset=").replace(/(?:\r\n|\r|\n|\t| )src=/g,' src="'+o+'" data-lazy-src=')}(t)):t=function(e){return e.replace(/(?:\r\n|\r|\n|\t| )src=/g,' lazyload="1" src=')}(t));var a=document.createElement("div");for(a.innerHTML=t;a.firstChild;)n.loadingSupported||!a.firstChild.tagName||"img"!==a.firstChild.tagName.toLowerCase()&&"iframe"!==a.firstChild.tagName.toLowerCase()||r.observe(a.firstChild),e.parentNode.insertBefore(a.firstChild,e);e.remove()}),window.matchMedia("print").addListener(function(e){e.matches&&document.querySelectorAll(n.lazyImage+"[data-lazy-src],"+n.lazyIframe+"[data-lazy-src]").forEach(function(e){i(e)})})}/comp|inter/.test(document.readyState)?a(c):"addEventListener"in document?document.addEventListener("DOMContentLoaded",function(){a(c)}):document.attachEvent("onreadystatechange",function(){"complete"===document.readyState&&c()})}("loading-lazy");
{
"name": "loading-attribute-polyfill",
"version": "0.2.0",
"version": "1.0.0",
"description": "A minimal and dependency-free vanilla JavaScript polyfill for the awesome loading='lazy'-attribute.",

@@ -27,3 +27,9 @@ "main": "loading-attribute-polyfill.min.js",

"devDependencies": {
"@wdio/cli": "^5.8.5",
"@wdio/dot-reporter": "^5.7.8",
"@wdio/local-runner": "^5.8.6",
"@wdio/mocha-framework": "^5.8.1",
"@wdio/sync": "^5.8.6",
"prettier": "1.17.0",
"webdriverio": "^5.8.5",
"xo": "^0.24.0"

@@ -30,0 +36,0 @@ },

@@ -15,3 +15,3 @@ # loading="lazy" attribute polyfill

- Supports the standard loading="lazy" attribute on `image` and `iframe` elements
- Supports the standard `loading="lazy"` attribute on `image` and `iframe` elements
- Released under the MIT license

@@ -40,4 +40,6 @@ - Made in Germany

Afterwards you'll need to wrap all of your `<img>` and `<iframe>` HTML tags that you'd like to lazy load (and thatfor added a {{loading="lazy"}} attribute as well) by an `<iframe>` HTML tag:
You could even load the polyfill asynchronously: <https://jsbin.com/yitarajawe/edit?html,css>
Afterwards you'll need to wrap all of your `<img>` and `<iframe>` HTML tags that you'd like to lazy load (and thatfor added a `loading="lazy"` attribute as well) by an `<iframe>` HTML tag:
### Simple image

@@ -121,3 +123,3 @@

https://www.npmjs.com/package/intersection-observer
<https://www.npmjs.com/package/intersection-observer>

@@ -124,0 +126,0 @@ Nevertheless this polyfill would still work in those browsers without that other polyfill included, but [this small amount of users](<(https://caniuse.com/#feat=intersectionobserver)>) wouldn't totally benefit from the lazy loading functionality - we've at least got you partly covered by using the [Microsoft proprietary lazyloading resource hints](https://caniuse.com/#feat=lazyload).

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