diff --git a/README.md b/README.md index e22ef69..50a2bd3 100644 --- a/README.md +++ b/README.md @@ -52,20 +52,11 @@ ### Install with composer -Install the latest version - ```bash composer require shinsenter/defer.php ``` -Install older version (for PHP <7.1.3) - -```bash -composer require shinsenter/defer.php:^2.0 -``` - - ### Load the library into your program ```php @@ -77,11 +68,13 @@ require_once __DIR__ . '/vendor/autoload.php'; ``` -### Backward compatible +### Requirements + +This library requires PHP 5.6 or above so you need this version or the latest version of PHP installed on your system. -This library recommends that the server is running PHP version 7.3 or greater for better performance and support. +It recommends that the server is running PHP version 7.3+ or above for better performance and supports. -Library's options of v2.x version are not backward compatible with previous release's options. Please read the library manual for more details. +Library options from v2.x are not backward compatible with previous release's options. Please read [library manual](#options) for more details. ## Usages @@ -109,7 +102,7 @@ var_dump($result2); ``` -### Customize the options of the library +### Options ```php // Include the library @@ -132,7 +125,7 @@ $options = [ 'manually_add_deferjs' => false, // URL to defer.js javascript file. - // Default: https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.1.0/dist/defer_plus.min.js + // Default: https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.3.0/dist/defer_plus.min.js 'deferjs_src' => \AppSeeds\DeferConstant::SRC_DEFERJS_CDN, // URL to javascript contains fixes. @@ -375,16 +368,16 @@ Only few options of this library are applicable to AMP pages (minifying HTML con ### Defer.js -https://github.com/shinsenter/defer.js/ +[https://github.com/shinsenter/defer.js/](https://github.com/shinsenter/defer.js/) 🥇 A super small, super efficient library that helps you lazy load almost everything like images, video, audio, iframes as well as stylesheets, and JavaScript. ### Wordpress plugin -https://github.com/shinsenter/defer-wordpress/ +[https://github.com/shinsenter/defer-wordpress/](https://github.com/shinsenter/defer-wordpress/) -⚡️ A native, blazing fast lazy loader. ✅ Legacy browsers support (IE9+). 💯 SEO friendly. 🧩 Lazy load almost anything. +⚡️ A native, blazing fast lazy loader. ✅ Legacy browsers support (IE9+). 💯 SEO friendly. 🧩 Lazy-load everything. ### Laravel package diff --git a/assets/.eslintrc b/assets/.eslintrc index de046f8..d703907 100644 --- a/assets/.eslintrc +++ b/assets/.eslintrc @@ -1,257 +1,256 @@ { - "env": { - "browser": true, - "es6": false - }, - "extends": "eslint:recommended", - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 3 - }, - "rules": { - "accessor-pairs": "error", - "array-bracket-newline": "error", - "array-bracket-spacing": "error", - "array-callback-return": "error", - "array-element-newline": "off", - "arrow-body-style": "error", - "arrow-parens": "error", - "arrow-spacing": "error", - "block-scoped-var": "error", - "block-spacing": [ - "error", - "never" - ], - "callback-return": "error", - "camelcase": "off", - "capitalized-comments": "off", - "class-methods-use-this": "error", - "comma-dangle": "error", - "comma-spacing": "off", - "comma-style": "error", - "complexity": "error", - "computed-property-spacing": [ - "error", - "never" - ], - "consistent-return": "error", - "consistent-this": "off", - "curly": "error", - "default-case": "error", - "dot-location": "error", - "dot-notation": "error", - "eol-last": "off", - "eqeqeq": "off", - "func-call-spacing": "error", - "func-name-matching": "error", - "func-names": "off", - "func-style": "off", - "function-paren-newline": "error", - "generator-star-spacing": "error", - "global-require": "error", - "guard-for-in": "off", - "handle-callback-err": "error", - "id-blacklist": "error", - "id-length": "off", - "id-match": "error", - "implicit-arrow-linebreak": "error", - "indent": "error", - "indent-legacy": "error", - "init-declarations": "off", - "jsx-quotes": "error", - "key-spacing": "error", - "line-comment-position": "error", - "linebreak-style": [ - "error", - "unix" - ], - "lines-around-comment": "error", - "lines-around-directive": "error", - "lines-between-class-members": "error", - "max-classes-per-file": "error", - "max-depth": "error", - "max-len": "off", - "max-lines": "off", - "max-lines-per-function": "error", - "max-nested-callbacks": "error", - "max-params": "off", - "max-statements": "off", - "max-statements-per-line": "off", - "multiline-comment-style": "off", - "new-cap": "error", - "new-parens": "error", - "newline-after-var": "off", - "newline-before-return": "error", - "newline-per-chained-call": "error", - "no-alert": "error", - "no-array-constructor": "error", - "no-async-promise-executor": "error", - "no-await-in-loop": "error", - "no-bitwise": "error", - "no-buffer-constructor": "error", - "no-caller": "error", - "no-catch-shadow": "error", - "no-confusing-arrow": "error", - "no-continue": "error", - "no-console": "off", - "no-div-regex": "error", - "no-duplicate-imports": "error", - "no-else-return": "error", - "no-empty-function": "off", - "no-eq-null": "error", - "no-eval": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-label": "error", - "no-extra-parens": "error", - "no-floating-decimal": "error", - "no-implicit-coercion": "error", - "no-implicit-globals": "error", - "no-implied-eval": "error", - "no-inline-comments": "error", - "no-invalid-this": "error", - "no-iterator": "error", - "no-label-var": "error", - "no-labels": "error", - "no-lone-blocks": "error", - "no-lonely-if": "error", - "no-loop-func": "error", - "no-magic-numbers": "off", - "no-misleading-character-class": "error", - "no-mixed-operators": "off", - "no-mixed-requires": "error", - "no-multi-assign": "off", - "no-multi-spaces": "off", - "no-multi-str": "error", - "no-multiple-empty-lines": "error", - "no-native-reassign": "error", - "no-negated-condition": "error", - "no-negated-in-lhs": "error", - "no-nested-ternary": "error", - "no-new": "error", - "no-new-func": "off", - "no-new-object": "error", - "no-new-require": "error", - "no-new-wrappers": "error", - "no-octal-escape": "error", - "no-param-reassign": "off", - "no-path-concat": "error", - "no-plusplus": "off", - "no-process-env": "error", - "no-process-exit": "error", - "no-proto": "error", - "no-prototype-builtins": "error", - "no-restricted-globals": "error", - "no-restricted-imports": "error", - "no-restricted-modules": "error", - "no-restricted-properties": "error", - "no-restricted-syntax": "error", - "no-return-assign": "error", - "no-return-await": "error", - "no-script-url": "error", - "no-self-compare": "error", - "no-sequences": "off", - "no-shadow": "off", - "no-shadow-restricted-names": "error", - "no-spaced-func": "error", - "no-sync": "error", - "no-tabs": "error", - "no-template-curly-in-string": "error", - "no-ternary": "off", - "no-throw-literal": "error", - "no-trailing-spaces": "error", - "no-undef-init": "error", - "no-undefined": "error", - "no-underscore-dangle": "off", - "no-unmodified-loop-condition": "error", - "no-unneeded-ternary": "error", - "no-unused-expressions": "off", - "no-use-before-define": "error", - "no-useless-call": "off", - "no-useless-catch": "error", - "no-useless-computed-key": "error", - "no-useless-concat": "error", - "no-useless-constructor": "error", - "no-useless-rename": "error", - "no-useless-return": "error", - "no-var": "off", - "no-void": "error", - "no-warning-comments": "error", - "no-whitespace-before-property": "error", - "no-with": "error", - "nonblock-statement-body-position": "error", - "object-curly-newline": "error", - "object-curly-spacing": "error", - "object-property-newline": "error", - "object-shorthand": "error", - "one-var": "off", - "one-var-declaration-per-line": "error", - "operator-assignment": "error", - "operator-linebreak": "error", - "padded-blocks": "off", - "padding-line-between-statements": "error", - "prefer-arrow-callback": "off", - "prefer-const": "error", - "prefer-destructuring": "off", - "prefer-numeric-literals": "error", - "prefer-object-spread": "error", - "prefer-promise-reject-errors": "error", - "prefer-reflect": "off", - "prefer-rest-params": "off", - "prefer-spread": "error", - "prefer-template": "off", - "quote-props": "off", - "quotes": [ - "error", - "single" - ], - "radix": "error", - "require-atomic-updates": "error", - "require-await": "error", - "require-jsdoc": "off", - "require-unicode-regexp": "off", - "rest-spread-spacing": "error", - "semi": "off", - "semi-spacing": [ - "error", - { - "after": true, - "before": false - } - ], - "semi-style": "error", - "sort-imports": "error", - "sort-keys": "error", - "sort-vars": "off", - "space-before-blocks": "off", - "space-before-function-paren": "off", - "space-in-parens": [ - "error", - "never" - ], - "space-infix-ops": "off", - "space-unary-ops": "error", - "spaced-comment": "off", - "strict": [ - "error", - "never" - ], - "switch-colon-spacing": "error", - "symbol-description": "error", - "template-curly-spacing": "error", - "template-tag-spacing": "error", - "unicode-bom": [ - "error", - "never" - ], - "valid-jsdoc": "error", - "vars-on-top": "error", - "wrap-iife": "off", - "wrap-regex": "error", - "yield-star-spacing": "error", - "yoda": "off" - } -} \ No newline at end of file + "env": { + "browser": true, + "es6": false + }, + "extends": "eslint:recommended", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 3 + }, + "rules": { + "accessor-pairs": "error", + "array-bracket-newline": "error", + "array-bracket-spacing": "error", + "array-callback-return": "error", + "array-element-newline": "off", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "error", + "block-spacing": [ + "error", + "never" + ], + "callback-return": "error", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "error", + "comma-spacing": "off", + "comma-style": "error", + "complexity": "error", + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-return": "error", + "consistent-this": "off", + "curly": "error", + "default-case": "error", + "dot-location": "error", + "dot-notation": "error", + "eol-last": "off", + "eqeqeq": "off", + "func-call-spacing": "error", + "func-name-matching": "error", + "func-names": "off", + "func-style": "off", + "function-paren-newline": "error", + "generator-star-spacing": "error", + "global-require": "error", + "guard-for-in": "error", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "implicit-arrow-linebreak": "error", + "indent": "error", + "indent-legacy": "error", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "error", + "line-comment-position": "error", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "error", + "lines-around-directive": "error", + "lines-between-class-members": "error", + "max-classes-per-file": "error", + "max-depth": "error", + "max-len": "off", + "max-lines": "off", + "max-lines-per-function": "error", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-comment-style": "off", + "new-cap": "error", + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "error", + "newline-per-chained-call": "error", + "no-alert": "error", + "no-array-constructor": "error", + "no-async-promise-executor": "error", + "no-await-in-loop": "error", + "no-bitwise": "error", + "no-buffer-constructor": "error", + "no-caller": "error", + "no-catch-shadow": "error", + "no-confusing-arrow": "error", + "no-continue": "error", + "no-console": "off", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "error", + "no-empty-function": "off", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-label": "error", + "no-extra-parens": "error", + "no-floating-decimal": "error", + "no-implicit-coercion": "error", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-inline-comments": "error", + "no-invalid-this": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "error", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-misleading-character-class": "error", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "error", + "no-multiple-empty-lines": "error", + "no-native-reassign": "error", + "no-negated-condition": "error", + "no-negated-in-lhs": "error", + "no-nested-ternary": "error", + "no-new": "error", + "no-new-func": "off", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "error", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": "error", + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "off", + "no-shadow": "off", + "no-shadow-restricted-names": "error", + "no-spaced-func": "error", + "no-sync": "error", + "no-tabs": "error", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-undefined": "error", + "no-underscore-dangle": "off", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": "error", + "no-unused-expressions": "off", + "no-use-before-define": "error", + "no-useless-call": "error", + "no-useless-catch": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "error", + "no-useless-constructor": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-var": "off", + "no-void": "error", + "no-warning-comments": "error", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": "error", + "object-curly-newline": "error", + "object-curly-spacing": "error", + "object-property-newline": "error", + "object-shorthand": "error", + "one-var": "off", + "one-var-declaration-per-line": "error", + "operator-assignment": "error", + "operator-linebreak": "error", + "padded-blocks": "off", + "padding-line-between-statements": "error", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "prefer-destructuring": "off", + "prefer-numeric-literals": "error", + "prefer-object-spread": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "error", + "prefer-template": "off", + "quote-props": "error", + "quotes": [ + "error", + "single" + ], + "radix": "error", + "require-atomic-updates": "error", + "require-await": "error", + "require-jsdoc": "off", + "require-unicode-regexp": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "semi-style": "error", + "sort-imports": "error", + "sort-keys": "error", + "sort-vars": "off", + "space-before-blocks": "error", + "space-in-parens": [ + "error", + "never" + ], + "space-infix-ops": "off", + "space-unary-ops": "error", + "spaced-comment": "off", + "strict": [ + "error", + "never" + ], + "switch-colon-spacing": "error", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "error", + "vars-on-top": "error", + "wrap-iife": "off", + "wrap-regex": "error", + "yield-star-spacing": "error", + "yoda": "off" + } +} diff --git a/assets/.uglifyjs b/assets/.uglifyjs index c25c47f..071ae91 100644 --- a/assets/.uglifyjs +++ b/assets/.uglifyjs @@ -1,31 +1,33 @@ { - "compress": true, - "mangle": { - "eval": false, - "keep_fnames": false, - "reserved": [], - "toplevel": true - }, - "output": { - "ascii_only": true, - "beautify": false, - "braces": false, - "indent_level": 0, - "indent_start": 0, - "inline_script": true, - "keep_quoted_props": true, - "max_line_len": false, - "preamble": null, - "preserve_line": false, - "quote_keys": false, - "quote_style": 1, - "semicolons": true, - "shebang": true, - "source_map": null, - "width": 80, - "wrap_iife": false, - "comments": "/^@/", - "ie8": true, - "webkit": false - } -} \ No newline at end of file + "compress": {}, + "mangle": { + "eval": false, + "keep_fnames": false, + "reserved": [], + "toplevel": false + }, + "nameCache": {}, + "output": { + "ascii_only": true, + "beautify": false, + "braces": false, + "indent_level": 0, + "indent_start": 0, + "inline_script": true, + "keep_quoted_props": false, + "max_line_len": false, + "preamble": null, + "preserve_line": false, + "quote_keys": false, + "quote_style": 1, + "semicolons": true, + "shebang": true, + "source_map": null, + "width": 80, + "wrap_iife": false, + "comments": "/^@/", + "ie8": true, + "webkit": true + }, + "wrap": null +} diff --git a/assets/helpers.js b/assets/helpers.js index b843c6c..af655a8 100644 --- a/assets/helpers.js +++ b/assets/helpers.js @@ -37,41 +37,28 @@ |-------------------------------------------------------------------------- */ - // HTML element - var _domHtml = document.documentElement; - // Backup jQuery.ready var _jqueryReady; // Common texts - var _txtAttribute = 'Attribute'; - var _txtDataLayer = 'dataLayer'; - var _txtDataPrefix = 'data-'; - var _txtDeferClass = 'deferjs'; - var _txtDeferPrefix = 'defer-'; - var _txtLazied = 'lazied'; - var _txtMedia = 'media'; + var _dataLayer = 'dataLayer'; + var _deferClass = 'deferjs'; + var _deferPrefix = 'defer-'; + var _lazied = 'lazied'; + var _dataPrefix = 'data-'; + var _media = 'media'; + + // Common class names + var _classLazied = _deferPrefix + _lazied; + var _classLoaded = _deferPrefix + 'loaded'; + var _classLoading = _deferPrefix + 'loading'; // Common attributes var _attrClassName = 'className'; var _attrDataIgnore = 'data-ignore'; // Common CSS selectors - var _queryIgnore = ':not([' + _attrDataIgnore + ']):not([lazied])'; - var _queryTarget = - '[' + _txtDataPrefix + 'src]' + _queryIgnore + ',' + - '[' + _txtDataPrefix + 'srcset]' + _queryIgnore + ',' + - '[' + _txtDataPrefix + 'style]' + _queryIgnore; - - // Common class names - var _classLazied = _txtDeferPrefix + _txtLazied; - var _classLoaded = _txtDeferPrefix + 'loaded'; - var _classLoading = _txtDeferPrefix + 'loading'; - - // Common method names - var _addEventListener = 'addEventListener'; - var _getAttribute = 'get' + _txtAttribute; - var _hasAttribute = 'has' + _txtAttribute; + var _queryTarget = '.' + _classLoading + ':not([' + _attrDataIgnore + ']):not([lazied])'; /* |-------------------------------------------------------------------------- @@ -81,7 +68,7 @@ var defer = window.Defer; var _delay = window.DEFERJS_DELAY || 8; - var _options = window.DEFERJS_OPTIONS || {rootMargin: '150%'}; + var _options = window.DEFERJS_OPTIONS || {'rootMargin': '150%'}; /* |-------------------------------------------------------------------------- @@ -89,55 +76,19 @@ |-------------------------------------------------------------------------- */ - function _getClass(node, find) { - return node[_attrClassName]. - split(' '). - filter(function (name) { - return name != '' && name != find; - }); - } - - function _addClass(node, name, _tmp) { - _tmp = _getClass(node, name); - _tmp.push(name); - node[_attrClassName] = _tmp.join(' '); - } - - function _removeClass(node, name) { - node[_attrClassName] = _getClass(node, name).join(' '); + function _replaceClass(node, find, replace) { + node[_attrClassName] = (' ' + node[_attrClassName] + ' '). + replace(' ' + find + ' ', ' ' + replace + ' ').trim(); } function _lazyload() { - defer.dom(_queryTarget, 0, _classLazied, function (element, _loaded, _src, _placeholder) { - // Loading state - _addClass(element, _classLoading); - - function _onLoad() { - if (!_loaded) { - _loaded = true; - _removeClass(element, _classLoading); - _addClass(element, _classLoaded); - } - } - - // Add youtube placeholder - _src = element[_getAttribute](_txtDataPrefix + 'src'); - _placeholder = element[_getAttribute]('src'); - - // Update loaded state - if (element[_hasAttribute](_attrDataIgnore) || - _src == _placeholder || !_src) { - _onLoad(); - } else { - element[_addEventListener]('error', _onLoad); - element[_addEventListener]('load', _onLoad); - defer(_onLoad, 3000); - } + defer.dom(_queryTarget, 0, _classLazied, function (node) { + _replaceClass(node, _classLoading, _classLoaded); }, _options); [].slice.call(document.querySelectorAll('style[defer]')). - forEach(function(node){ - node[_txtMedia] = node[_getAttribute](_txtDataPrefix + _txtMedia) || 'all'; + forEach(function(node) { + node[_media] = node.getAttribute(_dataPrefix + _media) || 'all'; }); } @@ -152,8 +103,9 @@ } function _boot() { - _copyright(); defer(_lazyload, _delay); + _replaceClass(document.documentElement, 'no-' + _deferClass, _deferClass); + _copyright(); } /* @@ -162,14 +114,11 @@ |-------------------------------------------------------------------------- */ - // Remove no-deferjs class - _removeClass(_domHtml, 'no-' + _txtDeferClass); - // Check if missing defer feature if (!defer) {return;} // Fallback for older versions - window.defer_helper = {defermedia: _lazyload}; + window.defer_helper = {'defermedia': _lazyload}; /* |-------------------------------------------------------------------------- @@ -179,12 +128,18 @@ // Fix missing dataLayer (for Google Analytics) // See: https://developers.google.com/analytics/devguides/collection/analyticsjs - window.ga = window.ga || function () {(window.ga.q = window.ga.q || []).push(arguments)}; window.ga.l = Number(new Date()); - window[_txtDataLayer] = window[_txtDataLayer] || []; + window.ga = window.ga || function () {(window.ga.q = window.ga.q || []).push(arguments)}; window.ga.l = Number(Date()); + window[_dataLayer] = window[_dataLayer] || []; // Fake jQuery.ready, if jQuery loaded defer(function (jquery) { - if (!_jqueryReady && (jquery = window.jQuery) && jquery.fn) { + if (_jqueryReady) { + return; + } + + jquery = window.jQuery; + + if (jquery && jquery.fn) { _jqueryReady = jquery.fn.ready; jquery.fn.ready = function (callback) { defer(function () {_jqueryReady(callback)}, _delay); @@ -198,7 +153,7 @@ |-------------------------------------------------------------------------- */ - _addClass(_domHtml, _txtDeferClass); + _boot(); })(this, document, console); diff --git a/assets/styles.css b/assets/styles.css index 55e028a..54e7cd4 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -16,13 +16,13 @@ embed { } .defer-loaded { - background-color: transparent!important; + background-color: initial!important; } -.defer-faded .defer-lazied{ - transition: opacity 0.5s ease-in-out; +.defer-faded [lazied]{ + transition: opacity 0.3s; } .defer-faded .defer-loading:not([data-ignore]) { - opacity: 0.5 !important; + opacity: 0.1!important; } diff --git a/composer.json b/composer.json index 02f1e67..8b14568 100644 --- a/composer.json +++ b/composer.json @@ -102,5 +102,10 @@ "preferred-install": "dist", "optimize-autoloader": true, "sort-packages": true + }, + "extra": { + "branch-alias": { + + } } } diff --git a/composer.lock b/composer.lock index 335804e..6d938d0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c3c7c7055d77037fa299cb2260d36d3a", + "content-hash": "b8ddf962e513425f715e325e6dbf4274", "packages": [ { "name": "mrclay/jsmin-php", @@ -642,16 +642,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.4.5", + "version": "1.4.6", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f28d44c286812c714741478d968104c5e604a1d4" + "reference": "f27e06cd9675801df441b3656569b328e04aa37c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", - "reference": "f28d44c286812c714741478d968104c5e604a1d4", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", + "reference": "f27e06cd9675801df441b3656569b328e04aa37c", "shasum": "" }, "require": { @@ -659,7 +659,8 @@ "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", "autoload": { @@ -685,7 +686,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" }, "funding": [ { @@ -701,7 +702,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:04:11+00:00" + "time": "2021-03-25T17:01:18+00:00" }, { "name": "doctrine/annotations", @@ -1162,16 +1163,16 @@ }, { "name": "symfony/console", - "version": "v5.2.5", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79" + "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79", - "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79", + "url": "https://api.github.com/repos/symfony/console/zipball/35f039df40a3b335ebf310f244cb242b3a83ac8d", + "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d", "shasum": "" }, "require": { @@ -1239,7 +1240,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.5" + "source": "https://github.com/symfony/console/tree/v5.2.6" }, "funding": [ { @@ -1255,7 +1256,7 @@ "type": "tidelift" } ], - "time": "2021-03-06T13:42:15+00:00" + "time": "2021-03-28T09:42:18+00:00" }, { "name": "symfony/event-dispatcher", @@ -1423,16 +1424,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.4", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108" + "reference": "8c86a82f51658188119e62cff0a050a12d09836f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/710d364200997a5afde34d9fe57bd52f3cc1e108", - "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/8c86a82f51658188119e62cff0a050a12d09836f", + "reference": "8c86a82f51658188119e62cff0a050a12d09836f", "shasum": "" }, "require": { @@ -1465,7 +1466,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.4" + "source": "https://github.com/symfony/filesystem/tree/v5.2.6" }, "funding": [ { @@ -1481,7 +1482,7 @@ "type": "tidelift" } ], - "time": "2021-02-12T10:38:38+00:00" + "time": "2021-03-28T14:30:26+00:00" }, { "name": "symfony/finder", @@ -2137,16 +2138,16 @@ }, { "name": "symfony/string", - "version": "v5.2.4", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4e78d7d47061fa183639927ec40d607973699609" + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4e78d7d47061fa183639927ec40d607973699609", - "reference": "4e78d7d47061fa183639927ec40d607973699609", + "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", "shasum": "" }, "require": { @@ -2200,7 +2201,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.4" + "source": "https://github.com/symfony/string/tree/v5.2.6" }, "funding": [ { @@ -2216,7 +2217,7 @@ "type": "tidelift" } ], - "time": "2021-02-16T10:20:28+00:00" + "time": "2021-03-17T17:12:15+00:00" } ], "aliases": [], diff --git a/package-lock.json b/package-lock.json index 7e5dc58..39f95e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,20 +6,34 @@ "": { "license": "MIT", "dependencies": { - "@shinsenter/defer.js": "^2.1.0" + "@shinsenter/defer.js": "^2.3.0" } }, "node_modules/@shinsenter/defer.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@shinsenter/defer.js/-/defer.js-2.1.0.tgz", - "integrity": "sha512-Q0nnWr+nmSXzcsIiQ5sbLvLTYG30Hj3KusiodM+4jOfQdwgyzTjJeNVfokpWi1AW2Qw28cWX/PIXBlnqiTITMQ==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@shinsenter/defer.js/-/defer.js-2.3.0.tgz", + "integrity": "sha512-Hjhe2IPa6B1N01BMA0x5vbcNLSRxIgeUUPNUCnx+59aD/RHzjKoFp/MRjLMqQcVQ0jAfjCw8xczXgJkHpN4n6Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/shinsenter/defer.js/stargazers" + }, + { + "type": "paypal", + "url": "https://www.patreon.com/appseeds" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/shinsenter" + } + ] } }, "dependencies": { "@shinsenter/defer.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@shinsenter/defer.js/-/defer.js-2.1.0.tgz", - "integrity": "sha512-Q0nnWr+nmSXzcsIiQ5sbLvLTYG30Hj3KusiodM+4jOfQdwgyzTjJeNVfokpWi1AW2Qw28cWX/PIXBlnqiTITMQ==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@shinsenter/defer.js/-/defer.js-2.3.0.tgz", + "integrity": "sha512-Hjhe2IPa6B1N01BMA0x5vbcNLSRxIgeUUPNUCnx+59aD/RHzjKoFp/MRjLMqQcVQ0jAfjCw8xczXgJkHpN4n6Q==" } } } diff --git a/package.json b/package.json index 622cd87..1320dde 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "author": "Mai Nhut Tan ", "license": "MIT", "dependencies": { - "@shinsenter/defer.js": "^2.1.0" + "@shinsenter/defer.js": "^2.3.0" }, "scripts": { "cleanup": "rm -rf ./node_modules package-lock.json", diff --git a/public/helpers.min.js b/public/helpers.min.js index 3f10338..0c2d43c 100644 --- a/public/helpers.min.js +++ b/public/helpers.min.js @@ -1 +1 @@ -!function(n,e,t){var o,r=e.documentElement,i='Attribute',a='dataLayer',c='data-',d='deferjs',f='defer-',l='media',u='className',s='data-ignore',p=':not(['+s+']):not([lazied])',g='['+c+'src]'+p+',['+c+'srcset]'+p+',['+c+'style]'+p,h=f+'lazied',m=f+'loaded',y=f+'loading',E='addEventListener',j='get'+i,D='has'+i,S=n.Defer,b=n.DEFERJS_DELAY||8,A=n.DEFERJS_OPTIONS||{rootMargin:'150%'};function q(e,n){return e[u].split(' ').filter(function(e){return''!=e&&e!=n})}function z(e,n,t){(t=q(e,n)).push(n),e[u]=t.join(' ')}function L(e,n){e[u]=q(e,n).join(' ')}function N(){S.dom(g,0,h,function(e,n,t,o){function r(){n||(n=!0,L(e,y),z(e,m))}z(e,y),t=e[j](c+'src'),o=e[j]('src'),e[D](s)||t==o||!t?r():(e[E]('error',r),e[E]('load',r),S(r,3e3))},A),[].slice.call(e.querySelectorAll('style[defer]')).forEach(function(e){e[l]=e[j](c+l)||'all'})}L(r,'no-'+d),S&&(n.defer_helper={defermedia:N},n.ga=n.ga||function(){(n.ga.q=n.ga.q||[]).push(arguments)},n.ga.l=Number(new Date),n[a]=n[a]||[],S(function(e){!o&&(e=n.jQuery)&&e.fn&&(o=e.fn.ready,e.fn.ready=function(e){S(function(){o(e)},b)})}),z(r,d),t.log&&t.log(['Optimized by defer.php','(c) 2021 AppSeeds','Github: https://code.shin.company/defer.php'].join('\n')),S(N,b))}(this,document,console); \ No newline at end of file +!function(n,e,t){var a,o='dataLayer',d='deferjs',i='defer-',r='data-',c='media',f=i+'lazied',l=i+'loaded',u=i+'loading',p='className',g='.'+u+':not([data-ignore]):not([lazied])',m=n.Defer,s=n.DEFERJS_DELAY||8,h=n.DEFERJS_OPTIONS||{rootMargin:'150%'};function y(e,n,t){e[p]=(' '+e[p]+' ').replace(' '+n+' ',' '+t+' ').trim()}function E(){m.dom(g,0,f,function(e){y(e,u,l)},h),[].slice.call(e.querySelectorAll('style[defer]')).forEach(function(e){e[c]=e.getAttribute(r+c)||'all'})}m&&(n.defer_helper={defermedia:E},n.ga=n.ga||function(){(n.ga.q=n.ga.q||[]).push(arguments)},n.ga.l=Number(Date()),n[o]=n[o]||[],m(function(e){a||(e=n.jQuery)&&e.fn&&(a=e.fn.ready,e.fn.ready=function(e){m(function(){a(e)},s)})}),m(E,s),y(e.documentElement,'no-'+d,d),t.log&&t.log(['Optimized by defer.php','(c) 2021 AppSeeds','Github: https://code.shin.company/defer.php'].join('\n')))}(this,document,console); \ No newline at end of file diff --git a/public/lib/defer.min.js b/public/lib/defer.min.js index 7889a84..f39836e 100644 --- a/public/lib/defer.min.js +++ b/public/lib/defer.min.js @@ -1,2 +1,2 @@ /*@shinsenter/defer.js*/ -!function(u,i,t){var a,r,o=[],c=/p/.test(i.readyState),s='IntersectionObserver',f=/^data-(.+)/,e='pageshow',l='lazied',d='length',n='Attribute',h='SCRIPT',m='load',v='forEach',p='has'+n,y='nodeName',b='set'+n;function g(e,n,t,o){return o=(n?i.getElementById(n):r)||i.createElement(e||h),n&&(o.id=n),t&&(o.onload=t),o}function I(e){return[].slice.call(e.attributes)}function E(e){i.head.appendChild(e)}function N(e,n){return[].slice.call((n||i).querySelectorAll(e))}function x(e){a(function(o){o=N(e||'[type=deferjs]'),function e(n,t){(n=o.shift())&&(n.parentNode.removeChild(n),(t=function(e,n,t,o,i){for(n=g(e[y]),i=0,t=I(e);icleanup(); if ($this->options()->disable || !$this->isFullPageHtml($html)) { - $this->_html = $html; + $this->_html = trim($html); } else { $this->document = new DocumentNode('1.0', 'UTF-8'); $this->document->formatOutput = true; @@ -340,16 +340,15 @@ public function optionArray() */ /** - * Returns true if the data from $html is an normal HTML document + * Returns true if the data from $html is a normal HTML document * * @since 2.0.0 * @param string $html * @return bool */ - protected function isFullPageHtml($html) + private function isFullPageHtml($html) { - return strstr($html, '') !== false; + return preg_match('/<\!DOCTYPE.+/is', $html); } /** @@ -359,7 +358,7 @@ protected function isFullPageHtml($html) * @param string $html * @return string */ - protected function patchBefore(&$html) + private function patchBefore(&$html) { foreach ($this->_patchers as $fixer) { $html = $fixer->before($html, $this->options); @@ -375,7 +374,7 @@ protected function patchBefore(&$html) * @param string $html * @return string */ - protected function patchAfter(&$html) + private function patchAfter(&$html) { $patchers = array_reverse($this->_patchers); diff --git a/src/Elements/CommonDomTraits.php b/src/Elements/CommonDomTraits.php index 6763033..0c5778b 100644 --- a/src/Elements/CommonDomTraits.php +++ b/src/Elements/CommonDomTraits.php @@ -282,7 +282,7 @@ public function _empty() * @param mixed $name * @param mixed $addValue */ - protected function _pushAttrValue($name, $value, $addValue = false) + private function _pushAttrValue($name, $value, $addValue = false) { if ($this instanceof DOMElement) { $attr = $this->getAttribute($name); diff --git a/src/Elements/DocumentNode.php b/src/Elements/DocumentNode.php index a6938f1..88baea5 100644 --- a/src/Elements/DocumentNode.php +++ b/src/Elements/DocumentNode.php @@ -75,6 +75,7 @@ public function setHtml($html) $disableEntities = @libxml_disable_entity_loader(true); parent::loadHTML($html, $this->libxmlOptions); + @libxml_clear_errors(); @libxml_use_internal_errors($internalErrors); @libxml_disable_entity_loader($disableEntities); diff --git a/src/Elements/TextNode.php b/src/Elements/TextNode.php index dc69696..3f51cb1 100644 --- a/src/Elements/TextNode.php +++ b/src/Elements/TextNode.php @@ -40,7 +40,7 @@ public function normalize() * * @return void */ - protected function normalizeWhitespaces() + private function normalizeWhitespaces() { $parent = $this->parentNode; diff --git a/src/Helpers/DeferCache.php b/src/Helpers/DeferCache.php index ead7c59..a649660 100644 --- a/src/Helpers/DeferCache.php +++ b/src/Helpers/DeferCache.php @@ -204,7 +204,7 @@ public function setPath($path) $this->path = $path; } - protected function rmdir($dirPath) + private function rmdir($dirPath) { $files = $this->scan($dirPath); @@ -219,12 +219,12 @@ protected function rmdir($dirPath) @rmdir($dirPath); } - protected function exists($path) + private function exists($path) { return (bool) stream_resolve_include_path($path); } - protected function scan($path, $type = null) + private function scan($path, $type = null) { $list = []; $handle = @opendir($path); @@ -248,7 +248,7 @@ protected function scan($path, $type = null) return $list; } - protected function hashedPath($key) + private function hashedPath($key) { $hashed = $this->hash($key); $path = $this->path; @@ -268,7 +268,7 @@ protected function hashedPath($key) return $path; } - protected function hash($key) + private function hash($key) { return hash('adler32', $key); } diff --git a/src/Helpers/DeferConstant.php b/src/Helpers/DeferConstant.php index 0aedb12..37faa86 100644 --- a/src/Helpers/DeferConstant.php +++ b/src/Helpers/DeferConstant.php @@ -152,7 +152,7 @@ class DeferConstant // ------------------------------------------------------------------------- // Source files - const SRC_DEFERJS_CDN = 'https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.1.0/dist/defer_plus.min.js'; + const SRC_DEFERJS_CDN = 'https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.3.0/dist/defer_plus.min.js'; const SRC_POLYFILL_CDN = 'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver'; const SRC_DEFERJS_FALLBACK = DEFER_PHP_ROOT . '/public/lib/defer_plus.min.js'; const SCR_DEFERJS_CACHE = DEFER_PHP_ROOT . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR; diff --git a/src/Helpers/DeferOptimizer.php b/src/Helpers/DeferOptimizer.php index 63e908c..824840e 100644 --- a/src/Helpers/DeferOptimizer.php +++ b/src/Helpers/DeferOptimizer.php @@ -237,10 +237,14 @@ public static function optimizeElement(ElementNode &$node, DeferOptions &$option // Apply lazy-load $lazied = $resolver->lazyload(); - if (!empty($fallback) && $lazied) { - $fallback->detach(); - $node->follow($fallback); - $node->addClass(DeferConstant::CLASS_HAS_FALLBACK); + if ($lazied) { + $node->addClass(DeferConstant::CLASS_DEFER_LOADING); + + if (!empty($fallback)) { + $fallback->detach(); + $node->follow($fallback); + $node->addClass(DeferConstant::CLASS_HAS_FALLBACK); + } } } diff --git a/src/Helpers/DeferOptions.php b/src/Helpers/DeferOptions.php index 2a63c81..e0bc414 100644 --- a/src/Helpers/DeferOptions.php +++ b/src/Helpers/DeferOptions.php @@ -167,6 +167,33 @@ public function forAmp() return $this; } + /** + * Set options from request + * + * @param array $allows + * @return self + */ + public function mergeFromRequest($allows = []) + { + $flags = array_filter($this->defaultOptions(), function ($value) { + return is_bool($value); + }); + + if (empty($allows)) { + $allows = array_keys($flags); + } + + foreach ($allows as $key) { + if (isset($flags[$key], $_REQUEST[$key])) { + $flags[$key] = (bool) $_REQUEST[$key]; + } + } + + $this->setOption($flags); + + return $this; + } + /** * Get merged list of well known third-party pattern * @@ -214,7 +241,7 @@ public function getWellKnown3rd($useCache = true) * 'manually_add_deferjs' => false, * * // URL to defer.js javascript file. - * // Default: https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.1.0/dist/defer_plus.min.js + * // Default: https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.3.0/dist/defer_plus.min.js * 'deferjs_src' => \AppSeeds\DeferConstant::SRC_DEFERJS_CDN, * * // URL to javascript contains fixes. @@ -361,11 +388,11 @@ public function getWellKnown3rd($useCache = true) * 'ignore_lazyload_css_selectors' => [], * * @since 2.0.0 - * @return self + * @return array */ - protected function configureOptions() + private function defaultOptions() { - $this->resolver->setDefaults([ + return [ // Disable the library 'disable' => !empty($_REQUEST[DeferConstant::ARG_NODEFER]), @@ -431,7 +458,12 @@ protected function configureOptions() // Blacklists using CSS class names 'ignore_lazyload_css_class' => [], 'ignore_lazyload_css_selectors' => [], - ]); + ]; + } + + private function configureOptions() + { + $this->resolver->setDefaults($this->defaultOptions()); return $this; } diff --git a/src/Resolvers/DeferResolver.php b/src/Resolvers/DeferResolver.php index fb8a340..1925d23 100644 --- a/src/Resolvers/DeferResolver.php +++ b/src/Resolvers/DeferResolver.php @@ -295,7 +295,8 @@ public function resolveAttr($attr, $attributes = []) return $this->node->getAttribute($attr); } - $original = $this->attr_backups[$attr] = $this->node->getAttribute($attr); + $original = $this->node->getAttribute($attr); + $this->attr_backups[$attr] = DeferAssetUtil::normalizeUrl($original); if (is_array($attributes)) { $unified = $original; @@ -323,7 +324,7 @@ public function resolveAttr($attr, $attributes = []) return $unified; } - return $original; + return $this->attr_backups[$attr]; } /** diff --git a/src/Resolvers/MediaResolver.php b/src/Resolvers/MediaResolver.php index 6f103f7..426646d 100644 --- a/src/Resolvers/MediaResolver.php +++ b/src/Resolvers/MediaResolver.php @@ -179,10 +179,6 @@ public function lazyload() $this->createDataAttr('poster', $svg_placeholder); } - if ($standalone) { - $this->node->addClass(DeferConstant::CLASS_DEFER_LOADING); - } - // Browser-level image lazy-loading for the web if (!$this->node->hasAttribute(DeferConstant::ATTR_LOADING)) { $this->node->setAttribute(DeferConstant::ATTR_LOADING, 'lazy'); diff --git a/tests/v2/test.php b/tests/v2/test.php index c31c0ae..a342051 100644 --- a/tests/v2/test.php +++ b/tests/v2/test.php @@ -84,28 +84,7 @@ // Test set $list = [ - 'continentalcamera.html' => 'https://staging.continentalcamera.com/?nodefer=1', - 'leverages.html' => 'https://leverages.jp/?nodefer=1', - 'bike_detail_pc.html' => 'https://moto.webike.net/bike_detail/1538248/?nodefer=1&ua=pc', - 'bike_detail_sp.html' => 'https://moto.webike.net/bike_detail/1538248/?nodefer=1&ua=sp', - 'cibertareas.html' => 'https://cibertareas.info?nodefer=1', - 'detail_pc.html' => 'https://www.webike.net/sd/24008665/?nodefer=1&ua=pc', - 'detail_sp.html' => 'https://www.webike.net/sd/24008665/?nodefer=1&ua=sp', - 'moto_amp.html' => 'https://moto.webike.net/b-gentsuki/list/amp/?nodefer=1', - 'moto_report_amp.html' => 'https://moto.webike.net/moto_report/amp/', - 'moto_report.html' => 'https://moto.webike.net/moto_report/?nodefer=1', - 'moto_top_pc.html' => 'https://moto.webike.net/?nodefer=1&ua=pc', - 'moto_top_sp.html' => 'https://moto.webike.net/?nodefer=1&ua=sp', - 'news.html' => 'https://news.webike.net/2021/01/21/195689/?nodefer=1', - 'pastelshop.html' => 'https://pastelshop.fr/?nodefer=1', - 'shop_navi_pc.html' => 'https://moto.webike.net/shop-navi/shop/17619/?nodefer=1&ua=pc', - 'shop_navi_sp.html' => 'https://moto.webike.net/shop-navi/shop/17619/?nodefer=1&ua=sp', - 'shufflrr.html' => 'https://shufflrr.com/?nodefer=1', - 'summary_pc.html' => 'https://moto.webike.net/YAMAHA/251_400/XJ400/summary/?nodefer=1&ua=pc', - 'summary_sp.html' => 'https://moto.webike.net/YAMAHA/251_400/XJ400/summary/?nodefer=1&ua=sp', - 'tab_parts_pc.html' => 'https://www.webike.net/tab/parts/bm/1150/br/186/?nodefer=1&ua=pc', - 'tab_parts_sp.html' => 'https://www.webike.net/tab/parts/bm/1150/br/186/?nodefer=1&ua=sp', - 'woltlab.html' => 'https://community.woltlab.com/?nodefer=1', + // 'filename.html' => 'https://example.com/', ]; // Scan test files