diff --git a/README.md b/README.md
index f67e6a1..93e55a1 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,9 @@ $defer = new \shinsenter\Defer();
$defer->append_defer_js = false;
$defer->default_defer_time = 10;
+// Add custom splash screen
+$defer->custom_splash_screen = '
Loading
';
+
// Page optimizations
$defer->enable_preloading = true;
$defer->enable_dns_prefetch = true;
diff --git a/assets/helpers.js b/assets/helpers.js
index 4f04310..22d862e 100644
--- a/assets/helpers.js
+++ b/assets/helpers.js
@@ -38,10 +38,14 @@
var PROJECT_NAME = 'defer.js';
var CLASS_PREFIX = 'defer-';
var CLASS_SUFFIX = 'deferjs';
- var DATA_PREFIX = 'data-';
+
+ var COPY_COMMON = 'font-size:14px;color:#fff;'+'padding:2px;border-radius:';
+ var COPY_TEXT = '%c ' + PROJECT_NAME + ' ';
+ var COPY_STYLE = COPY_COMMON + '4px;background:#2a313c';
var JQUERY = 'jQuery';
var NOOP = Function();
+ var DATA_PREFIX = 'data-';
var GET_ATTRIBUTE = 'getAttribute';
var IS_CHROME = typeof window.chrome == 'object' && window.navigator.userAgent.indexOf('Trident/') == -1;
@@ -73,30 +77,22 @@
t: 10
};
- var log = (console.log || NOOP)
- .bind(console);
- var defer = window.defer || NOOP;
- var deferimg = window.deferimg || NOOP;
+ var log = (console.log || NOOP).bind(console);
+ var defer = window.defer || NOOP;
+ var deferimg = window.deferimg || NOOP;
var deferiframe = window.deferiframe || NOOP;
var old_ready;
function copyright() {
- var text = '%c shinsenter %c ' + PROJECT_NAME + ' ';
- var common = 'font-size:16px;color:#fff;padding:4px;border-radius:';
- var style1 = common + '4px 0 0 4px;background:#2a313c';
- var style2 = common + '0 4px 4px 0;background:#e61e25';
-
if (IS_CHROME) {
- log(text, style1, style2);
+ log(COPY_TEXT, COPY_STYLE);
}
log([
- 'This page was optimized with ' + PROJECT_NAME,
+ 'Optimized by ' + PROJECT_NAME,
'(c) 2019 Mai Nhut Tan ',
- '',
'Github: ' + PROJECT_URL + PROJECT_NAME,
- 'PHP lib: ' + PROJECT_URL + 'defer.php',
- 'WordPress: https://wordpress.org/plugins/shins-pageload-magic/'
+ 'PHP lib: ' + PROJECT_URL + 'defer.php'
].join('\n'));
}
diff --git a/composer.lock b/composer.lock
index a5f548a..935afca 100644
--- a/composer.lock
+++ b/composer.lock
@@ -8,20 +8,21 @@
"packages": [
{
"name": "symfony/http-foundation",
- "version": "v4.2.7",
+ "version": "v4.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "6ebbe61f48069033225c9d3fa7eb5ed116d766d6"
+ "reference": "b7e4945dd9b277cd24e93566e4da0a87956392a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6ebbe61f48069033225c9d3fa7eb5ed116d766d6",
- "reference": "6ebbe61f48069033225c9d3fa7eb5ed116d766d6",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b7e4945dd9b277cd24e93566e4da0a87956392a9",
+ "reference": "b7e4945dd9b277cd24e93566e4da0a87956392a9",
"shasum": ""
},
"require": {
"php": "^7.1.3",
+ "symfony/mime": "^4.3",
"symfony/polyfill-mbstring": "~1.1"
},
"require-dev": {
@@ -31,7 +32,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.2-dev"
+ "dev-master": "4.3-dev"
}
},
"autoload": {
@@ -58,7 +59,128 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "time": "2019-04-17T14:56:00+00:00"
+ "time": "2019-06-06T10:05:02+00:00"
+ },
+ {
+ "name": "symfony/mime",
+ "version": "v4.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/mime.git",
+ "reference": "ec2c5565de60e03f33d4296a655e3273f0ad1f8b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/ec2c5565de60e03f33d4296a655e3273f0ad1f8b",
+ "reference": "ec2c5565de60e03f33d4296a655e3273f0ad1f8b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3",
+ "symfony/polyfill-intl-idn": "^1.10",
+ "symfony/polyfill-mbstring": "^1.0"
+ },
+ "require-dev": {
+ "egulias/email-validator": "^2.0",
+ "symfony/dependency-injection": "~3.4|^4.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Mime\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A library to manipulate MIME messages",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "mime",
+ "mime-type"
+ ],
+ "time": "2019-06-04T09:22:54+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-idn",
+ "version": "v1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-idn.git",
+ "reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c766e95bec706cdd89903b1eda8afab7d7a6b7af",
+ "reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/polyfill-mbstring": "^1.3",
+ "symfony/polyfill-php72": "^1.9"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Idn\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ },
+ {
+ "name": "Laurent Bassin",
+ "email": "laurent@bassin.info"
+ }
+ ],
+ "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "idn",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2019-03-04T13:44:35+00:00"
},
{
"name": "symfony/polyfill-mbstring",
@@ -118,6 +240,61 @@
"shim"
],
"time": "2019-02-06T07:57:58+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php72",
+ "version": "v1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php72.git",
+ "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c",
+ "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.11-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php72\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2019-02-06T07:57:58+00:00"
}
],
"packages-dev": [],
diff --git a/public/helpers.min.js b/public/helpers.min.js
index 10f5a76..f5a03ae 100644
--- a/public/helpers.min.js
+++ b/public/helpers.min.js
@@ -1 +1 @@
-!function(e,n,t,i){var o,r='https://github.com/shinsenter/',a='defer.js',s='defer-',u='deferjs',c='data-',d='jQuery',f=Function(),l='getAttribute',p='object'==typeof e.chrome&&-1==e.navigator.userAgent.indexOf('Trident/'),m=':not(['+c+'lazied]):not(['+c+'ignore])',g='['+c+'src]'+m,h='addEventListener',b='load',y=['img'+g,'picture'+m,'[data-style]'+m].join(','),v=['iframe'+g,'frame'+g,'audio'+m,'video'+m].join(','),j={c:s+'lazied',l:s+'loading',d:s+'loaded',h:n.getElementsByTagName('html').item(0),t:10},x=(t.log||f).bind(t),T=e.defer||f,z=e.deferimg||f,N=e.deferiframe||f;function k(){p&&x('%c shinsenter %c defer.js ','font-size:16px;color:#fff;padding:4px;border-radius:4px 0 0 4px;background:#2a313c','font-size:16px;color:#fff;padding:4px;border-radius:0 4px 4px 0;background:#e61e25'),x(['This page was optimized with '+a,'(c) 2019 Mai Nhut Tan ','','Github: '+r+a,'PHP lib: '+r+'defer.php','WordPress: https://wordpress.org/plugins/shins-pageload-magic/'].join('\n'))}function A(e,n){return e.split(' ').filter(function(e){return''!=e&&e!=n})}function w(e,n){var t=A(e.className,n);t.push(n),e.className=t.join(' ')}function M(e,n){e.className=A(e.className,n).join(' ')}function P(e){var n,t,i=e[l](c+'src');function o(){n&&(clearTimeout(n),n=null),M(e,j.l),w(e,j.d)}w(e,j.l),null!==(t=/(?:youtube(?:-nocookie)?\.com\/(?:[^/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/.exec(i))&&(e.style.background='transparent url(https://img.youtube.com/vi/'+t[1]+'/hqdefault.jpg) 50% 50% / cover no-repeat'),e.hasAttribute(c+'ignore')||i&&e.src==i||!i&&e[l](c+'style')?o():(e[h](b,o),n=setTimeout(o,3e3))}function C(){z(y,j.t,j.c,P,{rootMargin:'150%'}),N(v,j.t,j.c,P,{rootMargin:'200%'})}j.copyright=k,j.debounce=function(t,i,o,r){return function(){var e=this,n=arguments;o||clearTimeout(r),o&&r||(r=setTimeout(function(){r=null,t.apply(e,n)},i))}},j.defermedia=C,j.addClass=w,(j.removeClass=M)(j.h,'no-'+u),w(j.h,u),e.defer_helper=j,e[h](b,function(){!o&&d in e&&'fn'in e[d]&&(o=e[d].fn.ready,e[d].fn.ready=function(e){return T(function(){o(e)}),this})}),C(),k()}(this,document,console);
\ No newline at end of file
+!function(e,n,t,i){var o,r='https://github.com/shinsenter/',a='defer.js',u='defer-',c='deferjs',d='jQuery',s=Function(),f='data-',l='getAttribute',m='object'==typeof e.chrome&&-1==e.navigator.userAgent.indexOf('Trident/'),h=':not(['+f+'lazied]):not(['+f+'ignore])',p='['+f+'src]'+h,g='addEventListener',b='load',y=['img'+p,'picture'+h,'[data-style]'+h].join(','),v=['iframe'+p,'frame'+p,'audio'+h,'video'+h].join(','),j={c:u+'lazied',l:u+'loading',d:u+'loaded',h:n.getElementsByTagName('html').item(0),t:10},T=(t.log||s).bind(t),N=e.defer||s,x=e.deferimg||s,z=e.deferiframe||s;function A(){m&&T('%c defer.js ','font-size:14px;color:#fff;padding:2px;border-radius:4px;background:#2a313c'),T(['Optimized by '+a,'(c) 2019 Mai Nhut Tan ','Github: '+r+a,'PHP lib: '+r+'defer.php'].join('\n'))}function k(e,n){return e.split(' ').filter(function(e){return''!=e&&e!=n})}function M(e,n){var t=k(e.className,n);t.push(n),e.className=t.join(' ')}function C(e,n){e.className=k(e.className,n).join(' ')}function E(e){var n,t,i=e[l](f+'src');function o(){n&&(clearTimeout(n),n=null),C(e,j.l),M(e,j.d)}M(e,j.l),null!==(t=/(?:youtube(?:-nocookie)?\.com\/(?:[^/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/.exec(i))&&(e.style.background='transparent url(https://img.youtube.com/vi/'+t[1]+'/hqdefault.jpg) 50% 50% / cover no-repeat'),e.hasAttribute(f+'ignore')||i&&e.src==i||!i&&e[l](f+'style')?o():(e[g](b,o),n=setTimeout(o,3e3))}function O(){x(y,j.t,j.c,E,{rootMargin:'150%'}),z(v,j.t,j.c,E,{rootMargin:'200%'})}j.copyright=A,j.debounce=function(t,i,o,r){return function(){var e=this,n=arguments;o||clearTimeout(r),o&&r||(r=setTimeout(function(){r=null,t.apply(e,n)},i))}},j.defermedia=O,j.addClass=M,(j.removeClass=C)(j.h,'no-'+c),M(j.h,c),e.defer_helper=j,e[g](b,function(){!o&&d in e&&'fn'in e[d]&&(o=e[d].fn.ready,e[d].fn.ready=function(e){return N(function(){o(e)}),this})}),O(),A()}(this,document,console);
\ No newline at end of file
diff --git a/src/DeferInterface.php b/src/DeferInterface.php
index ee27779..c0b6967 100644
--- a/src/DeferInterface.php
+++ b/src/DeferInterface.php
@@ -58,6 +58,18 @@
]));
define('DEFER_MINIFY_HTML_IGNORE', 'not(parent::*[self::textarea or self::code or self::pre or self::script])');
+
+ // Splash screen
+
+ define('DEFER_SLASH_TEMPLATE', implode('', [
+ '',
+ '%s
',
+ ]));
+
+ define('DEFER_SLASH_HIDE_SCRIPT', implode('', [
+ '',
+ '',
+ ]));
}
abstract class DeferInterface
@@ -68,6 +80,10 @@ abstract class DeferInterface
const HELPERS_URL = DEFER_JS_ROOT . '/public/helpers.min.js';
const INLINE_CSS_URL = DEFER_JS_ROOT . '/public/styles.min.css';
+ // For splash screen
+ const SLASH_TEMPLATE = DEFER_SLASH_TEMPLATE;
+ const SLASH_HIDE_SCRIPT = DEFER_SLASH_HIDE_SCRIPT;
+
// Polyfill & library's fingerprint
const POLYFILL_URL = 'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver';
const FINGERPRINT_URL = 'https://raw.githubusercontent.com/shinsenter/defer.php/footprint/copyright.txt';
diff --git a/src/DeferOptimizer.php b/src/DeferOptimizer.php
index ea80552..44c1c09 100644
--- a/src/DeferOptimizer.php
+++ b/src/DeferOptimizer.php
@@ -51,6 +51,9 @@ protected function optimize()
$this->addMissingMeta();
$this->addFingerprint();
+ // Add custom splash screen
+ $this->addCustomSplashScreen();
+
// Minify
$this->minifyOutputHTML();
}
@@ -612,6 +615,23 @@ protected function optimizeBackgroundTags()
}
}
+ /**
+ * Added splash screen
+ *
+ * @since 1.0.15
+ */
+ protected function addCustomSplashScreen()
+ {
+ $splash = $this->custom_splash_screen;
+
+ if (empty($splash)) {
+ return;
+ }
+
+ $this->prependHtml($this->body, sprintf(static::SLASH_TEMPLATE, $splash));
+ $this->appendHtml($this->body, static::SLASH_HIDE_SCRIPT);
+ }
+
/*
|--------------------------------------------------------------------------
| Other helper functions
@@ -755,9 +775,15 @@ protected function getPreloadType($node)
if (is_a($node, DOMElement::class)) {
switch ($node->nodeName) {
case static::LINK_TAG:
+ if ($node->hasAttribute(static::ATTR_AS)) {
+ $as = $node->getAttribute(static::ATTR_AS);
+ break;
+ }
+
if (in_array($node->getAttribute(static::ATTR_REL), [static::REL_DNSPREFETCH, static::REL_PRECONNECT])) {
break;
}
+
$as = static::PRELOAD_STYLE;
break;
case static::STYLE_TAG:
diff --git a/src/DeferOptions.php b/src/DeferOptions.php
index 0f1bf24..259c707 100644
--- a/src/DeferOptions.php
+++ b/src/DeferOptions.php
@@ -30,6 +30,9 @@ trait DeferOptions
'append_defer_js' => false,
'default_defer_time' => 10,
+ // Splash screen
+ 'custom_splash_screen' => '',
+
// Page optimizations
'enable_preloading' => true,
'enable_dns_prefetch' => true,
diff --git a/src/DeferParser.php b/src/DeferParser.php
index 1b2fa2f..fcb5869 100644
--- a/src/DeferParser.php
+++ b/src/DeferParser.php
@@ -496,7 +496,7 @@ protected function createNode($tag, $content = null, $attributes = [])
if (is_array($content)) {
$attributes = $content;
$content = null;
- } elseif (is_string($content)) {
+ } elseif (in_array($tag, [static::SCRIPT_TAG]) && is_string($content)) {
$content = htmlspecialchars($content);
}
@@ -528,6 +528,43 @@ protected function removeNode(&$node)
return $this;
}
+ /**
+ * Prepend HTML
+ *
+ * @since 1.0.15
+ * @param DOMNode $node
+ * @param string $html
+ * @return self
+ */
+ protected function prependHtml(&$node, $html)
+ {
+ $tpl = $this->dom->createDocumentFragment();
+ $tpl->appendXML($html);
+
+ $the_anchor = $node->childNodes->item(0);
+ $node->insertBefore($tpl, $the_anchor);
+
+ return $node;
+ }
+
+ /**
+ * Append HTML
+ *
+ * @since 1.0.15
+ * @param DOMNode $node
+ * @param string $html
+ * @return self
+ */
+ protected function appendHtml(&$node, $html)
+ {
+ $tpl = $this->dom->createDocumentFragment();
+ $tpl->appendXML($html);
+
+ $node->appendChild($tpl);
+
+ return $node;
+ }
+
/**
* Add the resouce URL to the preload list
*