diff --git a/.build/.eslintrc b/.build/.eslintrc index af23171..e8d6a97 100644 --- a/.build/.eslintrc +++ b/.build/.eslintrc @@ -58,8 +58,8 @@ "id-length": "error", "id-match": "error", "implicit-arrow-linebreak": "error", - "indent": "error", - "indent-legacy": "error", + "indent": ["error", 2], + "indent-legacy": "off", "init-declarations": "off", "jsx-quotes": "error", "key-spacing": "error", diff --git a/.editorconfig b/.editorconfig index cd8eb86..fd4acd1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ root = true [*] charset = utf-8 -indent_size = 4 +indent_size = 2 indent_style = space end_of_line = lf insert_final_newline = true diff --git a/README.md b/README.md index ef8feee..1f67c85 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ [![NPM](https://nodei.co/npm/@shinsenter/defer.js.png?downloads=true)](https://www.npmjs.com/package/@shinsenter/defer.js) - **Package**: [@shinsenter/defer.js](https://www.npmjs.com/package/@shinsenter/defer.js) -- **Version**: 2.4.0 +- **Version**: 2.4.1 - **Author**: Mai Nhut Tan - **Copyright**: 2021 AppSeeds - **License**: [MIT](https://raw.githubusercontent.com/shinsenter/defer.js/master/LICENSE) @@ -90,7 +90,7 @@ or load it from a CDN like below example. My Awesome Page - + @@ -111,7 +111,7 @@ instead of `defer.min.js`. ```html - + @@ -231,14 +231,14 @@ Before: ```html ``` After: ```html ``` **Example** @@ -249,7 +249,7 @@ This example uses `type="myjs"` instead of `type="deferjs"`: ```html @@ -345,7 +345,7 @@ you should load `IntersectionObserver` polyfill library right after the `defer.min.js` script tag as following example: ```html - + @@ -382,8 +382,8 @@ Lazy load background image of a `div` tag. ```html @@ -420,7 +420,7 @@ Advanced usage: Lazy load with [Intersection observer options](https://developer @@ -516,9 +516,9 @@ Then when you scroll to any `code` tag, enable code highlighting for it. var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0'; Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000); Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () { - Defer.dom('pre code', 0, 'ide-loaded', function (block) { - hljs.highlightBlock(block); - }); + Defer.dom('pre code', 0, 'ide-loaded', function (block) { + hljs.highlightBlock(block); + }); }); ``` @@ -702,7 +702,7 @@ The DOM Node interface [https://github.com/shinsenter/defer-laravel/](https://github.com/shinsenter/defer-laravel/) -Under development. +🚀 A Laravel package that focuses on minimizing payload size of HTML document and optimizing processing on the browser when rendering the web page. ## Support my activities @@ -710,7 +710,7 @@ Under development. [![Donate via Paypal](https://img.shields.io/badge/Donate-Paypal-blue)](https://www.paypal.me/shinsenter) [![Become a sponsor](https://img.shields.io/badge/Donate-Patreon-orange)](https://www.patreon.com/appseeds) [![Become a stargazer](https://img.shields.io/badge/Support-Stargazer-yellow)](https://github.com/shinsenter/defer.js/stargazers) -[![Report an issue](https://img.shields.io/badge/Support-Issues-red)](https://github.com/shinsenter/defer.js/issues/new) +[![Report an issue](https://img.shields.io/badge/Support-Issues-green)](https://github.com/shinsenter/defer.js/issues/new) * * * diff --git a/dist/defer.min.js b/dist/defer.min.js index 12090ee..3a194cc 100644 --- a/dist/defer.min.js +++ b/dist/defer.min.js @@ -1,2 +1,2 @@ /*@shinsenter/defer.js*/ -!function(r,i,t){var u,o=/^data-(.+)/,a='IntersectionObserver',c=/p/.test(i.readyState),s=[],f=s.slice,l='lazied',e='load',n='pageshow',d='forEach',h='hasAttribute',m='shift';function v(e){i.head.appendChild(e)}function p(e){return f.call(e.attributes)}function y(e,n,t,o){return o=(o=n?i.getElementById(n):o)||i.createElement(e),n&&(o.id=n),t&&(o.onload=t),o}function b(e,n){return f.call((n||i).querySelectorAll(e))}function I(t){b('source',t)[d](I),p(t)[d](function(e,n){(n=o.exec(e.name))&&(t[n[1]]=e.value)}),e in t&&t[e]()}function g(e){u(function(o){o=b(e||'[type=deferjs]'),function e(n,t){(n=o[m]())&&(n.parentNode.removeChild(n),(t=y(n.nodeName)).text=n.text,p(n)[d](function(e){'type'!=e.name&&(t[e.name]=e.value)}),t.src&&!t[h]('async')?(t.onload=t.onerror=e,v(t)):(v(t),e()))}()})}(u=function(e,n){c?t(e,n):s.push(e,n)}).all=g,u.js=function(n,t,e,o){u(function(e){(e=y('SCRIPT',t,o)).src=n,v(e)},e)},u.css=function(n,t,e,o){u(function(e){(e=y('LINK',t,o)).rel='stylesheet',e.href=n,v(e)},e)},u.dom=function(e,n,t,o,i){function c(e){o&&!1===o(e)||(I(e),t&&(e.className+=' '+t))}u(function(t){t=a in r&&new r[a](function(e){e[d](function(e,n){e.isIntersecting&&(n=e.target)&&(t.unobserve(n),c(n))})},i),b(e||'[data-src]')[d](function(e){e[h](l)||(e.setAttribute(l,''),t?t.observe(e):c(e))})},n)},u.reveal=I,r.Defer=u,r.addEventListener('on'+n in r?n:e,function(){for(g();s[0];c=1)t(s[m](),s[m]())})}(this,document,setTimeout); \ No newline at end of file +!function(r,i,t){var u,o=/^data-(.+)/,a='IntersectionObserver',c=/p/.test(i.readyState),s=[],f=s.slice,l='lazied',e='load',n='pageshow',d='forEach',h='hasAttribute',m='shift';function v(e){i.head.appendChild(e)}function p(e,n){f.call(e.attributes)[d](n)}function y(e,n,t,o){return o=(o=n?i.getElementById(n):o)||i.createElement(e),n&&(o.id=n),t&&(o.onload=t),o}function b(e,n){return f.call((n||i).querySelectorAll(e))}function I(t){b('source',t)[d](I),p(t,function(e,n){(n=o.exec(e.name))&&(t[n[1]]=e.value)}),e in t&&t[e]()}function g(e){u(function(o){o=b(e||'[type=deferjs]'),function e(n,t){(n=o[m]())&&(n.parentNode.removeChild(n),(t=y(n.nodeName)).text=n.text,p(n,function(e){'type'!=e.name&&(t[e.name]=e.value)}),t.src&&!t[h]('async')?(t.onload=t.onerror=e,v(t)):(v(t),e()))}()})}(u=function(e,n){c?t(e,n):s.push(e,n)}).all=g,u.js=function(n,t,e,o){u(function(e){(e=y('SCRIPT',t,o)).src=n,v(e)},e)},u.css=function(n,t,e,o){u(function(e){(e=y('LINK',t,o)).rel='stylesheet',e.href=n,v(e)},e)},u.dom=function(e,n,t,o,i){function c(e){o&&!1===o(e)||(I(e),t&&(e.className+=' '+t))}u(function(t){t=a in r&&new r[a](function(e){e[d](function(e,n){e.isIntersecting&&(n=e.target)&&(t.unobserve(n),c(n))})},i),b(e||'[data-src]')[d](function(e){e[h](l)||(e.setAttribute(l,''),t?t.observe(e):c(e))})},n)},u.reveal=I,r.Defer=u,r.addEventListener('on'+n in r?n:e,function(){for(g();s[0];t(s[m](),s[m]()))c=1})}(this,document,setTimeout); \ No newline at end of file diff --git a/dist/defer_plus.min.js b/dist/defer_plus.min.js index 893280c..a4a5aed 100644 --- a/dist/defer_plus.min.js +++ b/dist/defer_plus.min.js @@ -1,2 +1,2 @@ /*@shinsenter/defer.js*/ -!function(c,i,t){var u,o=/^data-(.+)/,f='IntersectionObserver',r=/p/.test(i.readyState),s=[],a=s.slice,d='lazied',e='load',n='pageshow',l='forEach',m='hasAttribute',h='shift';function p(e){i.head.appendChild(e)}function v(e){return a.call(e.attributes)}function y(e,n,t,o){return o=(o=n?i.getElementById(n):o)||i.createElement(e),n&&(o.id=n),t&&(o.onload=t),o}function b(e,n){return a.call((n||i).querySelectorAll(e))}function g(t){b('source',t)[l](g),v(t)[l](function(e,n){(n=o.exec(e.name))&&(t[n[1]]=e.value)}),e in t&&t[e]()}function I(e){u(function(o){o=b(e||'[type=deferjs]'),function e(n,t){(n=o[h]())&&(n.parentNode.removeChild(n),(t=y(n.nodeName)).text=n.text,v(n)[l](function(e){'type'!=e.name&&(t[e.name]=e.value)}),t.src&&!t[m]('async')?(t.onload=t.onerror=e,p(t)):(p(t),e()))}()})}(u=function(e,n){r?t(e,n):s.push(e,n)}).all=I,u.js=function(n,t,e,o){u(function(e){(e=y('SCRIPT',t,o)).src=n,p(e)},e)},u.css=function(n,t,e,o){u(function(e){(e=y('LINK',t,o)).rel='stylesheet',e.href=n,p(e)},e)},u.dom=function(e,n,t,o,i){function r(e){o&&!1===o(e)||(g(e),t&&(e.className+=' '+t))}u(function(t){t=f in c&&new c[f](function(e){e[l](function(e,n){e.isIntersecting&&(n=e.target)&&(t.unobserve(n),r(n))})},i),b(e||'[data-src]')[l](function(e){e[m](d)||(e.setAttribute(d,''),t?t.observe(e):r(e))})},n)},u.reveal=g,c.Defer=u,c.addEventListener('on'+n in c?n:e,function(){for(I();s[0];r=1)t(s[h](),s[h]())})}(this,document,setTimeout),function(e,n){e.defer=n=e.Defer,e.deferscript=n.js,e.deferstyle=n.css,e.deferimg=e.deferiframe=n.dom}(this); \ No newline at end of file +!function(c,i,t){var f,o=/^data-(.+)/,u='IntersectionObserver',r=/p/.test(i.readyState),s=[],a=s.slice,d='lazied',e='load',n='pageshow',l='forEach',m='hasAttribute',h='shift';function p(e){i.head.appendChild(e)}function v(e,n){a.call(e.attributes)[l](n)}function y(e,n,t,o){return o=(o=n?i.getElementById(n):o)||i.createElement(e),n&&(o.id=n),t&&(o.onload=t),o}function b(e,n){return a.call((n||i).querySelectorAll(e))}function g(t){b('source',t)[l](g),v(t,function(e,n){(n=o.exec(e.name))&&(t[n[1]]=e.value)}),e in t&&t[e]()}function I(e){f(function(o){o=b(e||'[type=deferjs]'),function e(n,t){(n=o[h]())&&(n.parentNode.removeChild(n),(t=y(n.nodeName)).text=n.text,v(n,function(e){'type'!=e.name&&(t[e.name]=e.value)}),t.src&&!t[m]('async')?(t.onload=t.onerror=e,p(t)):(p(t),e()))}()})}(f=function(e,n){r?t(e,n):s.push(e,n)}).all=I,f.js=function(n,t,e,o){f(function(e){(e=y('SCRIPT',t,o)).src=n,p(e)},e)},f.css=function(n,t,e,o){f(function(e){(e=y('LINK',t,o)).rel='stylesheet',e.href=n,p(e)},e)},f.dom=function(e,n,t,o,i){function r(e){o&&!1===o(e)||(g(e),t&&(e.className+=' '+t))}f(function(t){t=u in c&&new c[u](function(e){e[l](function(e,n){e.isIntersecting&&(n=e.target)&&(t.unobserve(n),r(n))})},i),b(e||'[data-src]')[l](function(e){e[m](d)||(e.setAttribute(d,''),t?t.observe(e):r(e))})},n)},f.reveal=g,c.Defer=f,c.addEventListener('on'+n in c?n:e,function(){for(I();s[0];t(s[h](),s[h]()))r=1})}(this,document,setTimeout),function(e,n){e.defer=n=e.Defer,e.deferscript=n.js,e.deferstyle=n.css,e.deferimg=e.deferiframe=n.dom}(this); \ No newline at end of file diff --git a/docs/about.md b/docs/about.md index 42ba295..0153f41 100644 --- a/docs/about.md +++ b/docs/about.md @@ -16,7 +16,7 @@ [![NPM](https://nodei.co/npm/@shinsenter/defer.js.png?downloads=true)](https://www.npmjs.com/package/@shinsenter/defer.js) - **Package**: [@shinsenter/defer.js](https://www.npmjs.com/package/@shinsenter/defer.js) -- **Version**: 2.4.0 +- **Version**: 2.4.1 - **Author**: Mai Nhut Tan - **Copyright**: 2021 AppSeeds - **License**: [MIT](https://raw.githubusercontent.com/shinsenter/defer.js/master/LICENSE) @@ -90,7 +90,7 @@ or load it from a CDN like below example. My Awesome Page - + @@ -111,7 +111,7 @@ instead of `defer.min.js`. ```html - + diff --git a/docs/apis.md b/docs/apis.md index 4b8bef9..189c29a 100644 --- a/docs/apis.md +++ b/docs/apis.md @@ -93,14 +93,14 @@ Before: ```html ``` After: ```html ``` **Example** @@ -111,7 +111,7 @@ This example uses `type="myjs"` instead of `type="deferjs"`: ```html @@ -207,7 +207,7 @@ you should load `IntersectionObserver` polyfill library right after the `defer.min.js` script tag as following example: ```html - + @@ -244,8 +244,8 @@ Lazy load background image of a `div` tag. ```html @@ -282,7 +282,7 @@ Advanced usage: Lazy load with [Intersection observer options](https://developer @@ -378,9 +378,9 @@ Then when you scroll to any `code` tag, enable code highlighting for it. var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0'; Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000); Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () { - Defer.dom('pre code', 0, 'ide-loaded', function (block) { - hljs.highlightBlock(block); - }); + Defer.dom('pre code', 0, 'ide-loaded', function (block) { + hljs.highlightBlock(block); + }); }); ``` diff --git a/docs/index.md b/docs/index.md index ef8feee..1f67c85 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ [![NPM](https://nodei.co/npm/@shinsenter/defer.js.png?downloads=true)](https://www.npmjs.com/package/@shinsenter/defer.js) - **Package**: [@shinsenter/defer.js](https://www.npmjs.com/package/@shinsenter/defer.js) -- **Version**: 2.4.0 +- **Version**: 2.4.1 - **Author**: Mai Nhut Tan - **Copyright**: 2021 AppSeeds - **License**: [MIT](https://raw.githubusercontent.com/shinsenter/defer.js/master/LICENSE) @@ -90,7 +90,7 @@ or load it from a CDN like below example. My Awesome Page - + @@ -111,7 +111,7 @@ instead of `defer.min.js`. ```html - + @@ -231,14 +231,14 @@ Before: ```html ``` After: ```html ``` **Example** @@ -249,7 +249,7 @@ This example uses `type="myjs"` instead of `type="deferjs"`: ```html @@ -345,7 +345,7 @@ you should load `IntersectionObserver` polyfill library right after the `defer.min.js` script tag as following example: ```html - + @@ -382,8 +382,8 @@ Lazy load background image of a `div` tag. ```html @@ -420,7 +420,7 @@ Advanced usage: Lazy load with [Intersection observer options](https://developer @@ -516,9 +516,9 @@ Then when you scroll to any `code` tag, enable code highlighting for it. var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0'; Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000); Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () { - Defer.dom('pre code', 0, 'ide-loaded', function (block) { - hljs.highlightBlock(block); - }); + Defer.dom('pre code', 0, 'ide-loaded', function (block) { + hljs.highlightBlock(block); + }); }); ``` @@ -702,7 +702,7 @@ The DOM Node interface [https://github.com/shinsenter/defer-laravel/](https://github.com/shinsenter/defer-laravel/) -Under development. +🚀 A Laravel package that focuses on minimizing payload size of HTML document and optimizing processing on the browser when rendering the web page. ## Support my activities @@ -710,7 +710,7 @@ Under development. [![Donate via Paypal](https://img.shields.io/badge/Donate-Paypal-blue)](https://www.paypal.me/shinsenter) [![Become a sponsor](https://img.shields.io/badge/Donate-Patreon-orange)](https://www.patreon.com/appseeds) [![Become a stargazer](https://img.shields.io/badge/Support-Stargazer-yellow)](https://github.com/shinsenter/defer.js/stargazers) -[![Report an issue](https://img.shields.io/badge/Support-Issues-red)](https://github.com/shinsenter/defer.js/issues/new) +[![Report an issue](https://img.shields.io/badge/Support-Issues-green)](https://github.com/shinsenter/defer.js/issues/new) * * * diff --git a/docs/links.md b/docs/links.md index 29f344c..c2dc1e0 100644 --- a/docs/links.md +++ b/docs/links.md @@ -18,7 +18,7 @@ [https://github.com/shinsenter/defer-laravel/](https://github.com/shinsenter/defer-laravel/) -Under development. +🚀 A Laravel package that focuses on minimizing payload size of HTML document and optimizing processing on the browser when rendering the web page. ## Support my activities @@ -26,7 +26,7 @@ Under development. [![Donate via Paypal](https://img.shields.io/badge/Donate-Paypal-blue)](https://www.paypal.me/shinsenter) [![Become a sponsor](https://img.shields.io/badge/Donate-Patreon-orange)](https://www.patreon.com/appseeds) [![Become a stargazer](https://img.shields.io/badge/Support-Stargazer-yellow)](https://github.com/shinsenter/defer.js/stargazers) -[![Report an issue](https://img.shields.io/badge/Support-Issues-red)](https://github.com/shinsenter/defer.js/issues/new) +[![Report an issue](https://img.shields.io/badge/Support-Issues-green)](https://github.com/shinsenter/defer.js/issues/new) * * * diff --git a/package-lock.json b/package-lock.json index 29c7fd1..e6c7f0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@shinsenter/defer.js", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@shinsenter/defer.js", - "version": "2.4.0", + "version": "2.4.1", "funding": [ { "type": "github", diff --git a/package.json b/package.json index bc52662..4b0ed5e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@shinsenter/defer.js", "title": "defer.js", - "version": "2.4.0", + "version": "2.4.1", "description": "🥇 A super small, super efficient library that helps you lazy load almost everything like images, video, audio, iframes as well as stylesheets, and JavaScript.", "homepage": "https://shinsenter.github.io/defer.js/", "license": "MIT", diff --git a/src/defer.js b/src/defer.js index 28f967f..e29ba58 100644 --- a/src/defer.js +++ b/src/defer.js @@ -43,626 +43,632 @@ /*@shinsenter/defer.js*/ (function (window, document, caller) { - /* - |-------------------------------------------------------------------------- - | Define shared variables, this helps to maximize the output minification - |-------------------------------------------------------------------------- - */ - - // The defer instance - var defer; - - // Constant values - var _dataRegExp = /^data-(.+)/; - var _IO = 'IntersectionObserver'; - - // State holders - var _domReady = (/p/).test(document.readyState); - var _queue = []; - var _toArray = _queue.slice; - - // Common attributes - var _lazied = 'lazied'; - var _load = 'load'; - var _pageshow = 'pageshow'; - - // Common texts - var _LINK = 'LINK'; - var _SCRIPT = 'SCRIPT'; - - // Method aliases - var _forEach = 'forEach'; - var _hasAttribute = 'hasAttribute'; - var _listen = 'addEventListener'; - var _setAttribute = 'setAttribute'; - var _shift = 'shift'; - - // CSS Selectors - var _selectorDeferJs = '[type=deferjs]'; - var _selectorMedia = '[data-src]'; - - /* - |-------------------------------------------------------------------------- - | Utility functions are shared within internal scope - |-------------------------------------------------------------------------- - */ - - function _appendToHead(node) { - document.head.appendChild(node); + /* + |-------------------------------------------------------------------------- + | Define shared variables, this helps to maximize the output minification + |-------------------------------------------------------------------------- + */ + + // The defer instance + var defer; + + // Constant values + var _dataRegExp = /^data-(.+)/; + var _IO = 'IntersectionObserver'; + + // State holders + var _domReady = (/p/).test(document.readyState); + var _queue = []; + var _toArray = _queue.slice; + + // Common attributes + var _lazied = 'lazied'; + var _load = 'load'; + var _pageshow = 'pageshow'; + + // Method aliases + var _forEach = 'forEach'; + var _hasAttribute = 'hasAttribute'; + var _listen = 'addEventListener'; + var _setAttribute = 'setAttribute'; + var _shift = 'shift'; + + // CSS Selectors + var _defaultScripts = '[type=deferjs]'; + var _defaultTargets = '[data-src]'; + + /* + |-------------------------------------------------------------------------- + | Utility functions are shared within internal scope + |-------------------------------------------------------------------------- + */ + + function _appendToHead(node) { + document.head.appendChild(node); + } + + function _attrLoop(node, callback) { + _toArray.call(node.attributes)[_forEach](callback); + } + + function _newNode(nodeName, id, callback, _node) { + _node = id ? document.getElementById(id) : _node; + + if (!_node) { + _node = document.createElement(nodeName); } - function _propArray(node) { - return _toArray.call(node.attributes); + if (id) { + _node.id = id; } - function _newNode(nodeName, id, callback, _node) { - _node = id ? document.getElementById(id) : _node; + if (callback) { + _node.onload = callback; + } - if (!_node) { - _node = document.createElement(nodeName); - } + return _node; + } - if (id) { - _node.id = id; - } + function _query(selector, parent) { + return _toArray.call((parent || document).querySelectorAll(selector)); + } - if (callback) { - _node.onload = callback; - } + function _reveal(node) { + // Reveal children source nodes + _query('source', node)[_forEach](_reveal); - return _node; - } + // Transform data-xxx attributes to normal attributes + _attrLoop(node, function (_attr, _found) { + _found = _dataRegExp.exec(_attr.name); + + if (_found) { + node[_found[1]] = _attr.value; + } + }); - function _query(selector, parent) { - return _toArray.call((parent || document).querySelectorAll(selector)); + // Call element's load() method if exists + if (_load in node) { + node[_load](); } + } - function _reveal(node) { - _query('source', node)[_forEach](_reveal); - _propArray(node)[_forEach](function (_property, _found) { - _found = _dataRegExp.exec(_property.name); + function _scripts(selector) { + // Defer action until page loaded + defer(function (_found) { + _found = _query(selector || _defaultScripts); - if (_found) { - node[_found[1]] = _property.value; - } - }); + function _next(_node, _clone) { + _node = _found[_shift](); - if (_load in node) { - node[_load](); - } - } + if (_node) { + // Remove the node from DOM tree + _node.parentNode.removeChild(_node); - function _deferScriptNodes(selector) { - defer(function (_found) { - _found = _query(selector || _selectorDeferJs); - - function _next(_node, _clone) { - _node = _found[_shift](); - - if (_node) { - // Remove the node from DOM tree - _node.parentNode.removeChild(_node); - - // Clone the node - _clone = _newNode(_node.nodeName); - _clone.text = _node.text; - _propArray(_node)[_forEach](function (_property) { - if (_property.name != 'type') { - _clone[_property.name] = _property.value; - } - }); - - // Execute the node - if (_clone.src && !_clone[_hasAttribute]('async')) { - _clone.onload = _clone.onerror = _next; - _appendToHead(_clone); - } else { - _appendToHead(_clone); - _next(); - } - } - } + // Clone the node + _clone = _newNode(_node.nodeName); + _clone.text = _node.text; + _attrLoop(_node, function (_attr) { + if (_attr.name != 'type') { + _clone[_attr.name] = _attr.value; + } + }); + + // Execute the node + if (_clone.src && !_clone[_hasAttribute]('async')) { + _clone.onload = _clone.onerror = _next; + _appendToHead(_clone); + } else { + _appendToHead(_clone); _next(); - }); - } - - /* - |-------------------------------------------------------------------------- - | Defines the defer function and utility functions will be publicly exposed - |-------------------------------------------------------------------------- - */ - - /** - * A definition for an ordinary function, - * used as a parameter to another function. - * - * @typedef - * @name function - * @returns {void} - */ - - /** - * The definition for a function that takes one parameter is a DOM {@link Node} element - * - * @typedef - * @name closure - * @param {Node} element - The DOM {@link Node} element - * @returns {void | bool} - */ - - /** - * The DOM Node interface - * - * @typedef - * @name Node - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node} - */ - - /** - * Used to delay execution of JavaScript - * which may adversely affect the loading of your web page. - * - * All JavaScript delayed by `Defer()` will only executed - * after the web page has completely loaded. - * - * @function Defer - * @since 2.0 - * @param {function} func - The function that will be deferred. - * @param {number} [delay=0] - The duration in miliseconds to delay the `func` function. - * @returns {void} - * - * @example - * Delay some heavy DOM manipulations in JavaScript. - * - * ```js - * Defer(function() { - * // Some JavaScript that may block page rendering - * // such as calling jQuery's fadeIn() feature - * jQuery('div').hide().fadeIn().show(); - * }); // <- script runs after the page has completely loaded - * ``` - * - * @example - * Delay the same JavaScript as above for 3000ms. - * - * ```js - * Defer(function() { - * jQuery('div').hide().fadeIn().show(); - * }, 3000); // <- Added 3000 = Delay for 3000ms - * ``` - */ - defer = function (func, delay) { - if (_domReady) { - caller(func, delay); - } else { - _queue.push(func, delay); + } } - }; - - /** - * This function is useful for lazy-loading script tags. - * - * All script tags with attribute ` - * - * ``` - * After: - * ```html - * - * - * ``` - * - * @example - * If you don't want the ` - * - * - * - * - * ``` - */ - defer.all = _deferScriptNodes; - - /** - * For lazy loading external JavaScript files. - * - * This function is useful when you don't want heavy JavaScript - * (especially the widgets of social networks, ad services) - * to affect your website loading speed. - * - * @function Defer.js - * @since 2.0 - * @param {string} src - URL to the js file that should be lazy loaded. - * @param {string} [id] - The ID will be assigned to the script tag to avoid downloading the same file multiple times. - * @param {number} [delay=0] - The duration in miliseconds to delay loading the js file. - * @param {closure} [callback] - The callback function will be executed if the js file is successfully loaded. - * @returns {void} - * - * @example - * Delay loading of Facebook SDK after 3000ms. - * - * ```js - * Defer.js('https://connect.facebook.net/en_US/sdk.js', 'fb-sdk', 3000); - * ``` - * - * @example - * Delay loading of AddThis SDK after 5000ms. - * - * ```js - * var addthis_id = 'ra-5c68e61cf456f1cb'; - * Defer.js('https://s7.addthis.com/js/300/addthis_widget.js#pubid=' + addthis_id, 'addthis-js', 5000); - * ``` - */ - defer.js = function (src, id, delay, callback) { - defer(function (_node) { - _node = _newNode(_SCRIPT, id, callback); - _node.src = src; - _appendToHead(_node); - }, delay); - }; - - /** - * For lazy loading external CSS files. - * - * This function is useful when you don't want heavy CSS - * (like Web Fonts) to affect your website loading speed. - * - * @function Defer.css - * @since 2.0 - * @param {string} src - URL to the css file that should be lazy loaded. - * @param {string} [id] - The ID will be assigned to the script tag to avoid downloading the same file multiple times. - * @param {number} [delay=0] - The duration in miliseconds to delay loading the css file. - * @param {closure} [callback] - The callback function will be executed if the css file is successfully loaded. - * @returns {void} - * - * @example - * Lazy load FontAwesome Webfont from its CDN. - * - * ```js - * Defer.css('https://pro.fontawesome.com/releases/v5.10.0/css/all.css', 'fa5-css'); - * ``` - * - * @example - * Delay loading animate.css from CDN for 1000ms. - * - * ```js - * Defer.css('https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css', 'animate-css', 1000); - * ``` - */ - defer.css = function (src, id, delay, callback) { - defer(function (_node) { - _node = _newNode(_LINK, id, callback); - _node.rel = 'stylesheet'; - _node.href = src; - _appendToHead(_node); - }, delay); - }; - - /** - * For lazy loading attributes of any element on the page. - * - * Basically, the `Defer.dom` function converts all `data-*` attributes - * into regular attributes (e.g. from `data-src` to `src`) - * when user scrolling to the position - * where the element appears within the browser's viewport. - * - * Most of modern browsers support - * [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) feature. - * - * To take advantage of native performance - * for older browsers that doesn't support this feature (such as IE9), - * you should load `IntersectionObserver` polyfill library - * right after the `defer.min.js` script tag as following example: - - * ```html - * - * - * - * - * - * ``` - * - * @function Defer.dom - * @since 2.0 - * @param {string} [selector=[data-src]] - A CSS selector that queries elements will be lazy loaded. - * @param {number} [delay=0] - The duration in miliseconds to delay the lazy loading for the elements. - * @param {string} [revealedClass] - A CSS class will be added automatically after when an element has been successfully revealed. - * @param {closure} [validator] - A function will be executed with element will be lazy loaded as its argument. - * If the function returns `false`, lazy loading for that element will be skipped. - * @param {object} [observeOptions] - [Intersection observer options](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) - * @returns {void} - * - * @example - * Basic usage: - * Lazy load all `` tags which have CSS class `lazy`. - * - * ```html - * - * - * - * - * Photo 1 - * Photo 2 - * Photo 3 - * ``` - * - * @example - * Basic usage: - * Lazy load background image of a `div` tag. - * - * ```html - * - * - * - * - * - * - *
- * - *
- * ``` - * - * @example - * Advanced usage: - * Delay lazy loading `` tags 200ms after the page has completely loaded. - * Then it will add a CSS class `loaded` to the fully lazy loaded image element. - * - * ```html - * - * - * - * - * Photo 1 - * Photo 2 - * Photo 3 - * ``` - * - * @example - * Advanced usage: Lazy load with [Intersection observer options](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) - * - * ```html - * - * - * - * - * Photo 1 - * Photo 2 - * Photo 3 - * ``` - * - * @example - * We can use CSS class that added to the lazy loaded element - * to add animation to the successfully loaded elements. - * - * ```html - * - * - * - * - * - * Photo 1 - * Photo 2 - * Photo 3 - * ``` - * - * @example - * This function can be used similarly for other tags - * such as ` - * - * - * - * - * Photo - * - * - * - * - * - * ``` - * - * @example - * Or even execute a piece of JavaScript - * when the user scrolls to the element `#scroll_reveal`. - * - * ```html - * - * - * - * - *
- * This is my content. - *
- * ``` - * - * @example - * Combine with other Defer functions. - * Delay loading highlightjs library for 1000ms. - * Then when you scroll to any `code` tag, enable code highlighting for it. - * - * ```js - * var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0'; - * Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000); - * Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () { - * Defer.dom('pre code', 0, 'ide-loaded', function (block) { - * hljs.highlightBlock(block); - * }); - * }); - * ``` - */ - defer.dom = function ( - selector, - delay, - revealedClass, - validator, - observeOptions - ) { - function _present(node) { - if (!validator || validator(node) !== false) { - _reveal(node); - - if (revealedClass) { - node.className += ' ' + revealedClass; - } - } + } + + _next(); + }); + } + + /* + |-------------------------------------------------------------------------- + | Defines the defer function and utility functions will be publicly exposed + |-------------------------------------------------------------------------- + */ + + /** + * A definition for an ordinary function, + * used as a parameter to another function. + * + * @typedef + * @name function + * @returns {void} + */ + + /** + * The definition for a function that takes one parameter is a DOM {@link Node} element + * + * @typedef + * @name closure + * @param {Node} element - The DOM {@link Node} element + * @returns {void | bool} + */ + + /** + * The DOM Node interface + * + * @typedef + * @name Node + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node} + */ + + /** + * Used to delay execution of JavaScript + * which may adversely affect the loading of your web page. + * + * All JavaScript delayed by `Defer()` will only executed + * after the web page has completely loaded. + * + * @function Defer + * @since 2.0 + * @param {function} func - The function that will be deferred. + * @param {number} [delay=0] - The duration in miliseconds to delay the `func` function. + * @returns {void} + * + * @example + * Delay some heavy DOM manipulations in JavaScript. + * + * ```js + * Defer(function() { + * // Some JavaScript that may block page rendering + * // such as calling jQuery's fadeIn() feature + * jQuery('div').hide().fadeIn().show(); + * }); // <- script runs after the page has completely loaded + * ``` + * + * @example + * Delay the same JavaScript as above for 3000ms. + * + * ```js + * Defer(function() { + * jQuery('div').hide().fadeIn().show(); + * }, 3000); // <- Added 3000 = Delay for 3000ms + * ``` + */ + defer = function (func, delay) { + if (_domReady) { + caller(func, delay); + } else { + _queue.push(func, delay); + } + }; + + /** + * This function is useful for lazy-loading script tags. + * + * All script tags with attribute ` + * + * ``` + * After: + * ```html + * + * + * ``` + * + * @example + * If you don't want the ` + * + * + * + * + * ``` + */ + defer.all = _scripts; + + /** + * For lazy loading external JavaScript files. + * + * This function is useful when you don't want heavy JavaScript + * (especially the widgets of social networks, ad services) + * to affect your website loading speed. + * + * @function Defer.js + * @since 2.0 + * @param {string} src - URL to the js file that should be lazy loaded. + * @param {string} [id] - The ID will be assigned to the script tag to avoid downloading the same file multiple times. + * @param {number} [delay=0] - The duration in miliseconds to delay loading the js file. + * @param {closure} [callback] - The callback function will be executed if the js file is successfully loaded. + * @returns {void} + * + * @example + * Delay loading of Facebook SDK after 3000ms. + * + * ```js + * Defer.js('https://connect.facebook.net/en_US/sdk.js', 'fb-sdk', 3000); + * ``` + * + * @example + * Delay loading of AddThis SDK after 5000ms. + * + * ```js + * var addthis_id = 'ra-5c68e61cf456f1cb'; + * Defer.js('https://s7.addthis.com/js/300/addthis_widget.js#pubid=' + addthis_id, 'addthis-js', 5000); + * ``` + */ + defer.js = function (src, id, delay, callback) { + defer(function (_node) { + _node = _newNode('SCRIPT', id, callback); + _node.src = src; + _appendToHead(_node); + }, delay); + }; + + /** + * For lazy loading external CSS files. + * + * This function is useful when you don't want heavy CSS + * (like Web Fonts) to affect your website loading speed. + * + * @function Defer.css + * @since 2.0 + * @param {string} src - URL to the css file that should be lazy loaded. + * @param {string} [id] - The ID will be assigned to the script tag to avoid downloading the same file multiple times. + * @param {number} [delay=0] - The duration in miliseconds to delay loading the css file. + * @param {closure} [callback] - The callback function will be executed if the css file is successfully loaded. + * @returns {void} + * + * @example + * Lazy load FontAwesome Webfont from its CDN. + * + * ```js + * Defer.css('https://pro.fontawesome.com/releases/v5.10.0/css/all.css', 'fa5-css'); + * ``` + * + * @example + * Delay loading animate.css from CDN for 1000ms. + * + * ```js + * Defer.css('https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css', 'animate-css', 1000); + * ``` + */ + defer.css = function (src, id, delay, callback) { + defer(function (_node) { + _node = _newNode('LINK', id, callback); + _node.rel = 'stylesheet'; + _node.href = src; + _appendToHead(_node); + }, delay); + }; + + /** + * For lazy loading attributes of any element on the page. + * + * Basically, the `Defer.dom` function converts all `data-*` attributes + * into regular attributes (e.g. from `data-src` to `src`) + * when user scrolling to the position + * where the element appears within the browser's viewport. + * + * Most of modern browsers support + * [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) feature. + * + * To take advantage of native performance + * for older browsers that doesn't support this feature (such as IE9), + * you should load `IntersectionObserver` polyfill library + * right after the `defer.min.js` script tag as following example: + + * ```html + * + * + * + * + * + * ``` + * + * @function Defer.dom + * @since 2.0 + * @param {string} [selector=[data-src]] - A CSS selector that queries elements will be lazy loaded. + * @param {number} [delay=0] - The duration in miliseconds to delay the lazy loading for the elements. + * @param {string} [revealedClass] - A CSS class will be added automatically after when an element has been successfully revealed. + * @param {closure} [validator] - A function will be executed with element will be lazy loaded as its argument. + * If the function returns `false`, lazy loading for that element will be skipped. + * @param {object} [observeOptions] - [Intersection observer options](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) + * @returns {void} + * + * @example + * Basic usage: + * Lazy load all `` tags which have CSS class `lazy`. + * + * ```html + * + * + * + * + * Photo 1 + * Photo 2 + * Photo 3 + * ``` + * + * @example + * Basic usage: + * Lazy load background image of a `div` tag. + * + * ```html + * + * + * + * + * + * + *
+ * + *
+ * ``` + * + * @example + * Advanced usage: + * Delay lazy loading `` tags 200ms after the page has completely loaded. + * Then it will add a CSS class `loaded` to the fully lazy loaded image element. + * + * ```html + * + * + * + * + * Photo 1 + * Photo 2 + * Photo 3 + * ``` + * + * @example + * Advanced usage: Lazy load with [Intersection observer options](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) + * + * ```html + * + * + * + * + * Photo 1 + * Photo 2 + * Photo 3 + * ``` + * + * @example + * We can use CSS class that added to the lazy loaded element + * to add animation to the successfully loaded elements. + * + * ```html + * + * + * + * + * + * Photo 1 + * Photo 2 + * Photo 3 + * ``` + * + * @example + * This function can be used similarly for other tags + * such as ` + * + * + * + * + * Photo + * + * + * + * + * + * ``` + * + * @example + * Or even execute a piece of JavaScript + * when the user scrolls to the element `#scroll_reveal`. + * + * ```html + * + * + * + * + *
+ * This is my content. + *
+ * ``` + * + * @example + * Combine with other Defer functions. + * Delay loading highlightjs library for 1000ms. + * Then when you scroll to any `code` tag, enable code highlighting for it. + * + * ```js + * var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0'; + * Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000); + * Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () { + * Defer.dom('pre code', 0, 'ide-loaded', function (block) { + * hljs.highlightBlock(block); + * }); + * }); + * ``` + */ + defer.dom = function ( + selector, + delay, + revealedClass, + validator, + observeOptions + ) { + function _present(node) { + if (!validator || validator(node) !== false) { + _reveal(node); + + if (revealedClass) { + node.className += ' ' + revealedClass; } + } + } - function _lazyload(_observer) { - if (_IO in window) { - _observer = new window[_IO](function (nodes) { - nodes[_forEach](function (object, _node) { - if (object.isIntersecting) { - _node = object.target; - - if (_node) { - _observer.unobserve(_node); - _present(_node); - } - } - }); - }, observeOptions); - } else { - _observer = false; + function _lazyload(_observer) { + if (_IO in window) { + _observer = new window[_IO](function (nodes) { + nodes[_forEach](function (object, _node) { + if (object.isIntersecting) { + _node = object.target; + + if (_node) { + _observer.unobserve(_node); + _present(_node); + } } - - _query(selector || _selectorMedia)[_forEach](function (node) { - if (!node[_hasAttribute](_lazied)) { - node[_setAttribute](_lazied, ''); - - if (_observer) { - _observer.observe(node); - } else { - _present(node); - } - } - }); + }); + }, observeOptions); + } else { + _observer = false; + } + + _query(selector || _defaultTargets)[_forEach](function (node) { + if (!node[_hasAttribute](_lazied)) { + node[_setAttribute](_lazied, ''); + + if (_observer) { + _observer.observe(node); + } else { + _present(node); + } } + }); + } - defer(_lazyload, delay); - }; - - /** - * Reveal an element which is lazyloaded by the library - * - * @function Defer.reveal - * @since 2.1 - * @param {Node} element - The DOM {@link Node} element - * @returns {void} - * - * @example - * ```js - * // Show single element - * var node = document.getElementById('my-video'); - * Defer.reveal(node); - * - * // Show multiple elements - * document.querySelectorAll('.multi-lazy').forEach(function(node) { - * Defer.reveal(node); - * }); - * - * // Or even shorter way - * document.querySelectorAll('.multi-lazy').forEach(Defer.reveal); - * ``` - */ - defer.reveal = _reveal; - - /* - |-------------------------------------------------------------------------- - | Main - |-------------------------------------------------------------------------- - */ - - // Expose Defer instance - window.Defer = defer; - - // Listens for the load event of the global context - // then starts execution of all deferred scripts - window[_listen]( - 'on' + _pageshow in window ? _pageshow : _load, - function () { - for (_deferScriptNodes(); _queue[0]; _domReady = 1) { - caller(_queue[_shift](), _queue[_shift]()); - } - } - ); + defer(_lazyload, delay); + }; + + /** + * Reveal an element which is lazyloaded by the library + * + * @function Defer.reveal + * @since 2.1 + * @param {Node} element - The DOM {@link Node} element + * @returns {void} + * + * @example + * ```js + * // Show single element + * var node = document.getElementById('my-video'); + * Defer.reveal(node); + * + * // Show multiple elements + * document.querySelectorAll('.multi-lazy').forEach(function(node) { + * Defer.reveal(node); + * }); + * + * // Or even shorter way + * document.querySelectorAll('.multi-lazy').forEach(Defer.reveal); + * ``` + */ + defer.reveal = _reveal; + + /* + |-------------------------------------------------------------------------- + | Main + |-------------------------------------------------------------------------- + */ + + // Expose Defer instance + window.Defer = defer; + + // Listens for the load event of the global context + // then starts execution of all deferred scripts + window[_listen]( + 'on' + _pageshow in window ? _pageshow : _load, + function () { + for ( + _scripts(); + _queue[0]; + caller(_queue[_shift](), _queue[_shift]()) + ) { + _domReady = 1; + } + } + ); })(this, document, setTimeout); diff --git a/src/fallback.js b/src/fallback.js index 9deebd2..d81e826 100644 --- a/src/fallback.js +++ b/src/fallback.js @@ -36,63 +36,63 @@ */ (function (window, defer) { - /** - * @deprecated Deprecated since version 2.0 - * @since 1.0 - * @function defer - * @param {function} func - * @param {number} [delay] - * @see {@link Defer|Defer} - */ - window.defer = defer = window.Defer; + /** + * @deprecated Deprecated since version 2.0 + * @since 1.0 + * @function defer + * @param {function} func + * @param {number} [delay] + * @see {@link Defer|Defer} + */ + window.defer = defer = window.Defer; - /** - * @deprecated Deprecated since version 2.0 - * @since 1.0 - * @function deferscript - * @param {string} src - * @param {string} [id] - * @param {number} [delay] - * @param {callback} [callback] - * @see {@link Defer.js|Defer.js} - */ - window.deferscript = defer.js; + /** + * @deprecated Deprecated since version 2.0 + * @since 1.0 + * @function deferscript + * @param {string} src + * @param {string} [id] + * @param {number} [delay] + * @param {callback} [callback] + * @see {@link Defer.js|Defer.js} + */ + window.deferscript = defer.js; - /** - * @deprecated Deprecated since version 2.0 - * @since 1.0 - * @function deferstyle - * @param {string} src - * @param {string} [id] - * @param {number} [delay] - * @param {callback} [callback] - * @see {@link Defer.css|Defer.css} - */ - window.deferstyle = defer.css; + /** + * @deprecated Deprecated since version 2.0 + * @since 1.0 + * @function deferstyle + * @param {string} src + * @param {string} [id] + * @param {number} [delay] + * @param {callback} [callback] + * @see {@link Defer.css|Defer.css} + */ + window.deferstyle = defer.css; - /** - * @deprecated Deprecated since version 2.0 - * @function deferimg - * @since 1.0 - * @param {string} [selector] - * @param {number} [delay] - * @param {string} [revealedClass] - * @param {callback} [validator] - * @param {object} [observeOptions] - * @see {@link Defer.dom|Defer.dom} - */ + /** + * @deprecated Deprecated since version 2.0 + * @function deferimg + * @since 1.0 + * @param {string} [selector] + * @param {number} [delay] + * @param {string} [revealedClass] + * @param {callback} [validator] + * @param {object} [observeOptions] + * @see {@link Defer.dom|Defer.dom} + */ - /** - * @deprecated Deprecated since version 2.0 - * @function deferiframe - * @since 1.0 - * @param {string} [selector] - * @param {number} [delay] - * @param {string} [revealedClass] - * @param {callback} [validator] - * @param {object} [observeOptions] - * @see {@link Defer.dom|Defer.dom} - */ - window.deferimg = window.deferiframe = defer.dom; + /** + * @deprecated Deprecated since version 2.0 + * @function deferiframe + * @since 1.0 + * @param {string} [selector] + * @param {number} [delay] + * @param {string} [revealedClass] + * @param {callback} [validator] + * @param {object} [observeOptions] + * @see {@link Defer.dom|Defer.dom} + */ + window.deferimg = window.deferiframe = defer.dom; })(this);