Merge branch 'release/1.7.28'

This commit is contained in:
Andy Miller
2022-01-24 11:40:47 -07:00
17 changed files with 677 additions and 195 deletions

View File

@@ -1,8 +1,20 @@
# v1.7.28
## 01/24/2022
1. [](#new)
* Added links and modules support to `HtmlBlock` class
* Added module support for twig script tag: `{% script module 'theme://js/module.mjs' %}`
* Added twig tag for links: `{% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}`
* Added `HtmlBlock` support for `{% style %}`, `{% script %}` and `{% link %}` tags
* Support for page-level `redirect_default_route` frontmatter header override
3. [](#bugfix)
* Fixed XSS check not detecting escaped `&#58`
# v1.7.27.1
## 01/12/2022
3. [](#bugfix)
* Fixed a typo in CSS Asset pipeline that was erroneously joining files with `;`
* Fixed a typo in CSS Asset pipeline that was erroneously joining files with `;`
# v1.7.27
## 01/12/2022

276
composer.lock generated
View File

@@ -548,16 +548,16 @@
},
{
"name": "filp/whoops",
"version": "2.14.4",
"version": "2.14.5",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "f056f1fe935d9ed86e698905a957334029899895"
"reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895",
"reference": "f056f1fe935d9ed86e698905a957334029899895",
"url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc",
"reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc",
"shasum": ""
},
"require": {
@@ -607,7 +607,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.14.4"
"source": "https://github.com/filp/whoops/tree/2.14.5"
},
"funding": [
{
@@ -615,7 +615,7 @@
"type": "github"
}
],
"time": "2021-10-03T12:00:00+00:00"
"time": "2022-01-07T12:00:00+00:00"
},
{
"name": "getgrav/cache",
@@ -840,16 +840,16 @@
},
{
"name": "itsgoingd/clockwork",
"version": "v5.1.2",
"version": "v5.1.3",
"source": {
"type": "git",
"url": "https://github.com/itsgoingd/clockwork.git",
"reference": "4f46a69b123635ba2910a3ca8d100edfadc924e1"
"reference": "e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/4f46a69b123635ba2910a3ca8d100edfadc924e1",
"reference": "4f46a69b123635ba2910a3ca8d100edfadc924e1",
"url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8",
"reference": "e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8",
"shasum": ""
},
"require": {
@@ -897,7 +897,7 @@
],
"support": {
"issues": "https://github.com/itsgoingd/clockwork/issues",
"source": "https://github.com/itsgoingd/clockwork/tree/v5.1.2"
"source": "https://github.com/itsgoingd/clockwork/tree/v5.1.3"
},
"funding": [
{
@@ -905,7 +905,7 @@
"type": "github"
}
],
"time": "2021-12-07T18:24:19+00:00"
"time": "2021-12-24T12:24:20+00:00"
},
{
"name": "league/climate",
@@ -2191,16 +2191,16 @@
},
{
"name": "symfony/console",
"version": "v4.4.34",
"version": "v4.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "329b3a75cc6b16d435ba1b1a41df54a53382a3f0"
"reference": "621379b62bb19af213b569b60013200b11dd576f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/329b3a75cc6b16d435ba1b1a41df54a53382a3f0",
"reference": "329b3a75cc6b16d435ba1b1a41df54a53382a3f0",
"url": "https://api.github.com/repos/symfony/console/zipball/621379b62bb19af213b569b60013200b11dd576f",
"reference": "621379b62bb19af213b569b60013200b11dd576f",
"shasum": ""
},
"require": {
@@ -2261,7 +2261,7 @@
"description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/v4.4.34"
"source": "https://github.com/symfony/console/tree/v4.4.36"
},
"funding": [
{
@@ -2277,7 +2277,7 @@
"type": "tidelift"
}
],
"time": "2021-11-04T12:23:33+00:00"
"time": "2021-12-15T10:33:10+00:00"
},
{
"name": "symfony/contracts",
@@ -2459,16 +2459,16 @@
},
{
"name": "symfony/http-client",
"version": "v4.4.35",
"version": "v4.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "6ed0c02fdc21a76966f19b9000de18e688d9ca68"
"reference": "35e2cd1862b9ec2b46ebf050fbb13e285944b6a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/6ed0c02fdc21a76966f19b9000de18e688d9ca68",
"reference": "6ed0c02fdc21a76966f19b9000de18e688d9ca68",
"url": "https://api.github.com/repos/symfony/http-client/zipball/35e2cd1862b9ec2b46ebf050fbb13e285944b6a3",
"reference": "35e2cd1862b9ec2b46ebf050fbb13e285944b6a3",
"shasum": ""
},
"require": {
@@ -2520,7 +2520,7 @@
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-client/tree/v4.4.35"
"source": "https://github.com/symfony/http-client/tree/v4.4.36"
},
"funding": [
{
@@ -2536,25 +2536,28 @@
"type": "tidelift"
}
],
"time": "2021-11-22T21:43:45+00:00"
"time": "2021-12-29T09:28:53+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
@@ -2599,7 +2602,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
},
"funding": [
{
@@ -2615,25 +2618,28 @@
"type": "tidelift"
}
],
"time": "2021-02-19T12:13:01+00:00"
"time": "2021-10-20T20:35:02+00:00"
},
{
"name": "symfony/polyfill-iconv",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933"
"reference": "f1aed619e28cb077fc83fac8c4c0383578356e40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933",
"reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40",
"reference": "f1aed619e28cb077fc83fac8c4c0383578356e40",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-iconv": "*"
},
"suggest": {
"ext-iconv": "For best performance"
},
@@ -2679,7 +2685,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.24.0"
},
"funding": [
{
@@ -2695,25 +2701,28 @@
"type": "tidelift"
}
],
"time": "2021-05-27T09:27:20+00:00"
"time": "2022-01-04T09:04:05+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.23.1",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
@@ -2759,7 +2768,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
},
"funding": [
{
@@ -2775,11 +2784,11 @@
"type": "tidelift"
}
],
"time": "2021-05-27T12:26:48+00:00"
"time": "2021-11-30T18:21:41+00:00"
},
{
"name": "symfony/polyfill-php74",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php74.git",
@@ -2839,7 +2848,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php74/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-php74/tree/v1.24.0"
},
"funding": [
{
@@ -2859,16 +2868,16 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.23.1",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
"shasum": ""
},
"require": {
@@ -2922,7 +2931,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0"
},
"funding": [
{
@@ -2938,20 +2947,20 @@
"type": "tidelift"
}
],
"time": "2021-07-28T13:41:28+00:00"
"time": "2021-09-13T13:58:33+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.23.0",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "e66119f3de95efc359483f810c4c3e6436279436"
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436",
"reference": "e66119f3de95efc359483f810c4c3e6436279436",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
"reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
"shasum": ""
},
"require": {
@@ -3001,7 +3010,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0"
},
"funding": [
{
@@ -3017,20 +3026,20 @@
"type": "tidelift"
}
],
"time": "2021-05-21T13:25:03+00:00"
"time": "2021-09-13T13:58:11+00:00"
},
{
"name": "symfony/process",
"version": "v4.4.35",
"version": "v4.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "c2098705326addae6e6742151dfade47ac71da1b"
"reference": "a35d6b8f82e2272504f23a267de49b8717ca0028"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/c2098705326addae6e6742151dfade47ac71da1b",
"reference": "c2098705326addae6e6742151dfade47ac71da1b",
"url": "https://api.github.com/repos/symfony/process/zipball/a35d6b8f82e2272504f23a267de49b8717ca0028",
"reference": "a35d6b8f82e2272504f23a267de49b8717ca0028",
"shasum": ""
},
"require": {
@@ -3063,7 +3072,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v4.4.35"
"source": "https://github.com/symfony/process/tree/v4.4.36"
},
"funding": [
{
@@ -3079,20 +3088,20 @@
"type": "tidelift"
}
],
"time": "2021-11-22T22:36:24+00:00"
"time": "2021-12-19T16:27:15+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v4.4.34",
"version": "v4.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "2d0c056b2faaa3d785bdbd5adecc593a5be9c16e"
"reference": "02685c62fcbc4262235cc72a54fbd45ab719ce3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/2d0c056b2faaa3d785bdbd5adecc593a5be9c16e",
"reference": "2d0c056b2faaa3d785bdbd5adecc593a5be9c16e",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/02685c62fcbc4262235cc72a54fbd45ab719ce3c",
"reference": "02685c62fcbc4262235cc72a54fbd45ab719ce3c",
"shasum": ""
},
"require": {
@@ -3152,7 +3161,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v4.4.34"
"source": "https://github.com/symfony/var-dumper/tree/v4.4.36"
},
"funding": [
{
@@ -3168,20 +3177,20 @@
"type": "tidelift"
}
],
"time": "2021-11-12T10:50:54+00:00"
"time": "2021-12-29T09:28:53+00:00"
},
{
"name": "symfony/yaml",
"version": "v4.4.34",
"version": "v4.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "2c309e258adeb9970229042be39b360d34986fad"
"reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/2c309e258adeb9970229042be39b360d34986fad",
"reference": "2c309e258adeb9970229042be39b360d34986fad",
"url": "https://api.github.com/repos/symfony/yaml/zipball/a19f7c44ba665fa9d9d415cc4493361381b93f9b",
"reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b",
"shasum": ""
},
"require": {
@@ -3223,7 +3232,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v4.4.34"
"source": "https://github.com/symfony/yaml/tree/v4.4.36"
},
"funding": [
{
@@ -3239,7 +3248,7 @@
"type": "tidelift"
}
],
"time": "2021-11-18T18:49:23+00:00"
"time": "2021-11-25T16:40:00+00:00"
},
{
"name": "twig/twig",
@@ -3442,23 +3451,23 @@
},
{
"name": "codeception/codeception",
"version": "4.1.23",
"version": "4.1.28",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "27d18cd5d5a1d77d3f1b01ea776238676faf5dcc"
"reference": "e9bc22a3819f9d356068c0e372193ebcc9b06014"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/27d18cd5d5a1d77d3f1b01ea776238676faf5dcc",
"reference": "27d18cd5d5a1d77d3f1b01ea776238676faf5dcc",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/e9bc22a3819f9d356068c0e372193ebcc9b06014",
"reference": "e9bc22a3819f9d356068c0e372193ebcc9b06014",
"shasum": ""
},
"require": {
"behat/gherkin": "^4.4.0",
"codeception/lib-asserts": "^1.0",
"codeception/lib-asserts": "^1.0 | 2.0.*@dev",
"codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.1.1 | ^9.0",
"codeception/stub": "^2.0 | ^3.0",
"codeception/stub": "^2.0 | ^3.0 | ^4.0",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
@@ -3471,11 +3480,11 @@
"symfony/yaml": ">=2.7 <6.0"
},
"require-dev": {
"codeception/module-asserts": "1.*@dev",
"codeception/module-cli": "1.*@dev",
"codeception/module-db": "1.*@dev",
"codeception/module-filesystem": "1.*@dev",
"codeception/module-phpbrowser": "1.*@dev",
"codeception/module-asserts": "^1.0 | 2.0.*@dev",
"codeception/module-cli": "^1.0 | 2.0.*@dev",
"codeception/module-db": "^1.0 | 2.0.*@dev",
"codeception/module-filesystem": "^1.0 | 2.0.*@dev",
"codeception/module-phpbrowser": "^1.0 | 2.0.*@dev",
"codeception/specify": "~0.3",
"codeception/util-universalframework": "*@dev",
"monolog/monolog": "~1.8",
@@ -3528,7 +3537,7 @@
],
"support": {
"issues": "https://github.com/Codeception/Codeception/issues",
"source": "https://github.com/Codeception/Codeception/tree/4.1.23"
"source": "https://github.com/Codeception/Codeception/tree/4.1.28"
},
"funding": [
{
@@ -3536,7 +3545,7 @@
"type": "open_collective"
}
],
"time": "2021-12-11T18:05:26+00:00"
"time": "2022-01-05T16:41:25+00:00"
},
{
"name": "codeception/lib-asserts",
@@ -4198,9 +4207,6 @@
"require": {
"php": "^7.1 || ^8.0"
},
"replace": {
"myclabs/deep-copy": "self.version"
},
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
@@ -4518,16 +4524,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.5.1",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae"
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"shasum": ""
},
"require": {
@@ -4562,9 +4568,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
},
"time": "2021-10-02T14:08:47+00:00"
"time": "2022-01-04T19:58:01+00:00"
},
{
"name": "phpspec/prophecy",
@@ -4635,16 +4641,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.2.0",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee"
"reference": "1dd8f3e40bf7aa30031a75c65cece99220a161b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1dd8f3e40bf7aa30031a75c65cece99220a161b8",
"reference": "1dd8f3e40bf7aa30031a75c65cece99220a161b8",
"shasum": ""
},
"require": {
@@ -4660,7 +4666,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.4-dev"
}
},
"autoload": {
@@ -4675,7 +4681,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.2.0"
"source": "https://github.com/phpstan/phpstan/tree/1.4.2"
},
"funding": [
{
@@ -4695,7 +4701,7 @@
"type": "tidelift"
}
],
"time": "2021-11-18T14:09:01+00:00"
"time": "2022-01-18T16:09:11+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -5067,16 +5073,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.10",
"version": "9.5.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a"
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256",
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256",
"shasum": ""
},
"require": {
@@ -5154,11 +5160,11 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12"
},
"funding": [
{
"url": "https://phpunit.de/donate.html",
"url": "https://phpunit.de/sponsors.html",
"type": "custom"
},
{
@@ -5166,7 +5172,7 @@
"type": "github"
}
],
"time": "2021-09-25T07:38:51+00:00"
"time": "2022-01-21T05:54:47+00:00"
},
{
"name": "psr/http-client",
@@ -6186,16 +6192,16 @@
},
{
"name": "symfony/browser-kit",
"version": "v5.4.0",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "d250db364a35ba5d60626b2a6f10f2eaf2073bde"
"reference": "1fb93b0aab42392aa0a742db205173b49afaf80f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/d250db364a35ba5d60626b2a6f10f2eaf2073bde",
"reference": "d250db364a35ba5d60626b2a6f10f2eaf2073bde",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/1fb93b0aab42392aa0a742db205173b49afaf80f",
"reference": "1fb93b0aab42392aa0a742db205173b49afaf80f",
"shasum": ""
},
"require": {
@@ -6238,7 +6244,7 @@
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/browser-kit/tree/v5.4.0"
"source": "https://github.com/symfony/browser-kit/tree/v5.4.2"
},
"funding": [
{
@@ -6254,20 +6260,20 @@
"type": "tidelift"
}
],
"time": "2021-10-26T22:29:18+00:00"
"time": "2021-12-16T21:58:21+00:00"
},
{
"name": "symfony/css-selector",
"version": "v5.4.0",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "44b933f98bb4b5220d10bed9ce5662f8c2d13dcc"
"reference": "cfcbee910e159df402603502fe387e8b677c22fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/44b933f98bb4b5220d10bed9ce5662f8c2d13dcc",
"reference": "44b933f98bb4b5220d10bed9ce5662f8c2d13dcc",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/cfcbee910e159df402603502fe387e8b677c22fd",
"reference": "cfcbee910e159df402603502fe387e8b677c22fd",
"shasum": ""
},
"require": {
@@ -6304,7 +6310,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v5.4.0"
"source": "https://github.com/symfony/css-selector/tree/v5.4.2"
},
"funding": [
{
@@ -6320,7 +6326,7 @@
"type": "tidelift"
}
],
"time": "2021-09-09T08:06:01+00:00"
"time": "2021-12-16T21:58:21+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -6391,16 +6397,16 @@
},
{
"name": "symfony/dom-crawler",
"version": "v5.4.0",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "5b06626e940a3ad54e573511d64d4e00dc8d0fd8"
"reference": "bb3bc3699779fc6d9646270789026a7e2cec7ec7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5b06626e940a3ad54e573511d64d4e00dc8d0fd8",
"reference": "5b06626e940a3ad54e573511d64d4e00dc8d0fd8",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb3bc3699779fc6d9646270789026a7e2cec7ec7",
"reference": "bb3bc3699779fc6d9646270789026a7e2cec7ec7",
"shasum": ""
},
"require": {
@@ -6446,7 +6452,7 @@
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v5.4.0"
"source": "https://github.com/symfony/dom-crawler/tree/v5.4.2"
},
"funding": [
{
@@ -6462,20 +6468,20 @@
"type": "tidelift"
}
],
"time": "2021-11-23T10:19:22+00:00"
"time": "2021-12-28T17:15:56+00:00"
},
{
"name": "symfony/finder",
"version": "v5.4.0",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590"
"reference": "e77046c252be48c48a40816187ed527703c8f76c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/d2f29dac98e96a98be467627bd49c2efb1bc2590",
"reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590",
"url": "https://api.github.com/repos/symfony/finder/zipball/e77046c252be48c48a40816187ed527703c8f76c",
"reference": "e77046c252be48c48a40816187ed527703c8f76c",
"shasum": ""
},
"require": {
@@ -6509,7 +6515,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v5.4.0"
"source": "https://github.com/symfony/finder/tree/v5.4.2"
},
"funding": [
{
@@ -6525,7 +6531,7 @@
"type": "tidelift"
}
],
"time": "2021-11-28T15:25:38+00:00"
"time": "2021-12-15T11:06:13+00:00"
},
{
"name": "theseer/tokenizer",
@@ -6654,5 +6660,5 @@
"platform-overrides": {
"php": "7.3.6"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.2.0"
}

View File

@@ -320,6 +320,18 @@ form:
fields:
header.redirect_default_route:
type: toggle
toggleable: true
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP
config-highlight@: system.pages.redirect_default_route
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
header.routes.default:
type: text
toggleable: true

View File

@@ -9,7 +9,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.27.1');
define('GRAV_VERSION', '1.7.28');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);

View File

@@ -267,4 +267,17 @@ abstract class BaseAsset extends PropertyObject
{
return '';
}
/**
* Finds relative JS urls() and rewrites the URL with an absolute one
*
* @param string $file the css source file
* @param string $dir local relative path to the css file
* @param bool $local is this a local or remote asset
* @return string
*/
protected function jsRewrite($file, $dir, $local)
{
return '';
}
}

View File

@@ -279,11 +279,11 @@ class Pipeline extends PropertyObject
return $file;
}
/**
/**
* Finds relative JS urls() and rewrites the URL with an absolute one
*
* @param string $file the css source file
* @param string $dir , $local relative path to the css file
* @param string $dir local relative path to the css file
* @param bool $local is this a local or remote asset
* @return string
*/

View File

@@ -214,7 +214,7 @@ class Security
'on_events' => '#(<[^>]+[[a-z\x00-\x20\"\'\/])([\s\/]on|\sxmlns)[a-z].*=>?#iUu',
// Match javascript:, livescript:, vbscript:, mocha:, feed: and data: protocols
'invalid_protocols' => '#(' . implode('|', array_map('preg_quote', $invalid_protocols, ['#'])) . '):\S.*?#iUu',
'invalid_protocols' => '#(' . implode('|', array_map('preg_quote', $invalid_protocols, ['#'])) . ')(:|\&\#58)\S.*?#iUu',
// Match -moz-bindings
'moz_binding' => '#-moz-binding[a-z\x00-\x20]*:#u',

View File

@@ -99,7 +99,8 @@ class PagesServiceProvider implements ServiceProviderInterface
/** @var Language $language */
$language = $grav['language'];
$redirectCode = (int)$config->get('system.pages.redirect_default_route', 0);
$redirect_default_route = $page->header()->redirect_default_route ?? $config->get('system.pages.redirect_default_route', 0);
$redirectCode = (int) $redirect_default_route;
// Language-specific redirection scenarios
if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) {

View File

@@ -22,6 +22,7 @@ use Grav\Common\Page\Media;
use Grav\Common\Scheduler\Cron;
use Grav\Common\Security;
use Grav\Common\Twig\TokenParser\TwigTokenParserCache;
use Grav\Common\Twig\TokenParser\TwigTokenParserLink;
use Grav\Common\Twig\TokenParser\TwigTokenParserRender;
use Grav\Common\Twig\TokenParser\TwigTokenParserScript;
use Grav\Common\Twig\TokenParser\TwigTokenParserStyle;
@@ -252,6 +253,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigTokenParserTryCatch(),
new TwigTokenParserScript(),
new TwigTokenParserStyle(),
new TwigTokenParserLink(),
new TwigTokenParserMarkdown(),
new TwigTokenParserSwitch(),
new TwigTokenParserCache(),

View File

@@ -0,0 +1,114 @@
<?php
/**
* @package Grav\Common\Twig
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Twig\Node;
use LogicException;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Node;
use Twig\Node\NodeCaptureInterface;
/**
* Class TwigNodeLink
* @package Grav\Common\Twig\Node
*/
class TwigNodeLink extends Node implements NodeCaptureInterface
{
/** @var string */
protected $tagName = 'link';
/**
* TwigNodeLink constructor.
* @param string|null $rel
* @param AbstractExpression|null $file
* @param AbstractExpression|null $group
* @param AbstractExpression|null $priority
* @param AbstractExpression|null $attributes
* @param int $lineno
* @param string|null $tag
*/
public function __construct(?string $rel, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null)
{
$nodes = ['file' => $file, 'group' => $group, 'priority' => $priority, 'attributes' => $attributes];
$nodes = array_filter($nodes);
parent::__construct($nodes, ['rel' => $rel], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Compiler $compiler A Twig Compiler instance
* @return void
* @throws LogicException
*/
public function compile(Compiler $compiler): void
{
$compiler->addDebugInfo($this);
if (!$this->hasNode('file')) {
return;
}
$compiler->write('$attributes = [\'rel\' => \'' . $this->getAttribute('rel') . '\'];' . "\n");
if ($this->hasNode('attributes')) {
$compiler
->write('$attributes += ')
->subcompile($this->getNode('attributes'))
->raw(';' . PHP_EOL)
->write('if (!is_array($attributes)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');" . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
}
if ($this->hasNode('group')) {
$compiler
->write('$group = ')
->subcompile($this->getNode('group'))
->raw(';' . PHP_EOL)
->write('if (!is_string($group)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');" . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
} else {
$compiler->write('$group = \'head\';' . PHP_EOL);
}
if ($this->hasNode('priority')) {
$compiler
->write('$priority = (int)(')
->subcompile($this->getNode('priority'))
->raw(');' . PHP_EOL);
} else {
$compiler->write('$priority = 10;' . PHP_EOL);
}
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];" . PHP_EOL);
$compiler->write("\$block = \$context['block'] ?? null;" . PHP_EOL);
$compiler
->write('$file = (string)(')
->subcompile($this->getNode('file'))
->raw(');' . PHP_EOL);
// Assets support.
$compiler->write('$assets->addLink($file, [\'group\' => $group, \'priority\' => $priority] + $attributes);' . PHP_EOL);
// HtmlBlock support.
$compiler
->write('if ($block instanceof \Grav\Framework\ContentBlock\HtmlBlock) {' . PHP_EOL)
->indent()
->write('$block->addLink([\'href\'=> $file] + $attributes, $priority, $group);' . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
}
}

View File

@@ -27,6 +27,7 @@ class TwigNodeScript extends Node implements NodeCaptureInterface
/**
* TwigNodeScript constructor.
* @param Node|null $body
* @param string|null $type
* @param AbstractExpression|null $file
* @param AbstractExpression|null $group
* @param AbstractExpression|null $priority
@@ -34,12 +35,12 @@ class TwigNodeScript extends Node implements NodeCaptureInterface
* @param int $lineno
* @param string|null $tag
*/
public function __construct(?Node $body, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null)
public function __construct(?Node $body, ?string $type, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null)
{
$nodes = ['body' => $body, 'file' => $file, 'group' => $group, 'priority' => $priority, 'attributes' => $attributes];
$nodes = array_filter($nodes);
parent::__construct($nodes, [], $lineno, $tag);
parent::__construct($nodes, ['type' => $type], $lineno, $tag);
}
/**
@@ -53,52 +54,89 @@ class TwigNodeScript extends Node implements NodeCaptureInterface
{
$compiler->addDebugInfo($this);
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];\n");
if ($this->hasNode('attributes')) {
$compiler
->write('$attributes = ')
->subcompile($this->getNode('attributes'))
->raw(";\n")
->write("if (!is_array(\$attributes)) {\n")
->raw(';' . PHP_EOL)
->write('if (!is_array($attributes)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');\n")
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');" . PHP_EOL)
->outdent()
->write("}\n");
->write('}' . PHP_EOL);
} else {
$compiler->write('$attributes = [];' . "\n");
$compiler->write('$attributes = [];' . PHP_EOL);
}
if ($this->hasNode('group')) {
$compiler
->write("\$attributes['group'] = ")
->write('$group = ')
->subcompile($this->getNode('group'))
->raw(";\n")
->write("if (!is_string(\$attributes['group'])) {\n")
->raw(';' . PHP_EOL)
->write('if (!is_string($group)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');\n")
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');" . PHP_EOL)
->outdent()
->write("}\n");
->write('}' . PHP_EOL);
} else {
$compiler->write('$group = \'head\';' . PHP_EOL);
}
if ($this->hasNode('priority')) {
$compiler
->write("\$attributes['priority'] = (int)(")
->write('$priority = (int)(')
->subcompile($this->getNode('priority'))
->raw(");\n");
->raw(');' . PHP_EOL);
} else {
$compiler->write('$priority = 10;' . PHP_EOL);
}
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];" . PHP_EOL);
$compiler->write("\$block = \$context['block'] ?? null;" . PHP_EOL);
if ($this->hasNode('file')) {
// JS file.
$compiler
->write('$assets->addJs(')
->write('$file = (string)(')
->subcompile($this->getNode('file'))
->raw(", \$attributes);\n");
} else {
->raw(');' . PHP_EOL);
$method = $this->getAttribute('type') === 'module' ? 'addJsModule' : 'addJs';
// Assets support.
$compiler->write('$assets->' . $method . '($file, [\'group\' => $group, \'priority\' => $priority] + $attributes);' . PHP_EOL);
$method = $this->getAttribute('type') === 'module' ? 'addModule' : 'addScript';
// HtmlBlock support.
$compiler
->write("ob_start();\n")
->write('if ($block instanceof \Grav\Framework\ContentBlock\HtmlBlock) {' . PHP_EOL)
->indent()
->write('$block->' . $method . '([\'src\'=> $file] + $attributes, $priority, $group);' . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
} else {
// Inline script.
$compiler
->write('ob_start();' . PHP_EOL)
->subcompile($this->getNode('body'))
->write('$content = ob_get_clean();' . "\n")
->write("\$assets->addInlineJs(\$content, \$attributes);\n");
->write('$content = ob_get_clean();' . PHP_EOL);
$method = $this->getAttribute('type') === 'module' ? 'addInlineJsModule' : 'addInlineJs';
// Assets support.
$compiler->write('$assets->' . $method . '($content, [\'group\' => $group, \'priority\' => $priority] + $attributes);' . PHP_EOL);
$method = $this->getAttribute('type') === 'module' ? 'addInlineModule' : 'addInlineScript';
// HtmlBlock support.
$compiler
->write('if ($block instanceof \Grav\Framework\ContentBlock\HtmlBlock) {' . PHP_EOL)
->indent()
->write('$block->' . $method . '([\'content\'=> $content] + $attributes, $priority, $group);' . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
}
}
}

View File

@@ -41,6 +41,7 @@ class TwigNodeStyle extends Node implements NodeCaptureInterface
parent::__construct($nodes, [], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
@@ -52,52 +53,81 @@ class TwigNodeStyle extends Node implements NodeCaptureInterface
{
$compiler->addDebugInfo($this);
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];\n");
if ($this->hasNode('attributes')) {
$compiler
->write('$attributes = ')
->subcompile($this->getNode('attributes'))
->raw(";\n")
->write("if (!is_array(\$attributes)) {\n")
->raw(';' . PHP_EOL)
->write('if (!is_array($attributes)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');\n")
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');" . PHP_EOL)
->outdent()
->write("}\n");
->write('}' . PHP_EOL);
} else {
$compiler->write('$attributes = [];' . "\n");
$compiler->write('$attributes = [];' . PHP_EOL);
}
if ($this->hasNode('group')) {
$compiler
->write("\$attributes['group'] = ")
->write('$group = ')
->subcompile($this->getNode('group'))
->raw(";\n")
->write("if (!is_string(\$attributes['group'])) {\n")
->raw(';' . PHP_EOL)
->write('if (!is_string($group)) {' . PHP_EOL)
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');\n")
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');" . PHP_EOL)
->outdent()
->write("}\n");
->write('}' . PHP_EOL);
} else {
$compiler->write('$group = \'head\';' . PHP_EOL);
}
if ($this->hasNode('priority')) {
$compiler
->write("\$attributes['priority'] = (int)(")
->write('$priority = (int)(')
->subcompile($this->getNode('priority'))
->raw(");\n");
->raw(');' . PHP_EOL);
} else {
$compiler->write('$priority = 10;' . PHP_EOL);
}
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];" . PHP_EOL);
$compiler->write("\$block = \$context['block'] ?? null;" . PHP_EOL);
if ($this->hasNode('file')) {
// CSS file.
$compiler
->write('$assets->addCss(')
->write('$file = (string)(')
->subcompile($this->getNode('file'))
->raw(", \$attributes);\n");
} else {
->raw(');' . PHP_EOL);
// Assets support.
$compiler->write('$assets->addCss($file, [\'group\' => $group, \'priority\' => $priority] + $attributes);' . PHP_EOL);
// HtmlBlock support.
$compiler
->write("ob_start();\n")
->write('if ($block instanceof \Grav\Framework\ContentBlock\HtmlBlock) {' . PHP_EOL)
->indent()
->write('$block->addStyle([\'href\'=> $file] + $attributes, $priority, $group);' . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
} else {
// Inline style.
$compiler
->write('ob_start();' . PHP_EOL)
->subcompile($this->getNode('body'))
->write('$content = ob_get_clean();' . "\n")
->write("\$assets->addInlineCss(\$content, \$attributes);\n");
->write('$content = ob_get_clean();' . PHP_EOL);
// Assets support.
$compiler->write('$assets->addInlineCss($content, [\'group\' => $group, \'priority\' => $priority] + $attributes);' . PHP_EOL);
// HtmlBlock support.
$compiler
->write('if ($block instanceof \Grav\Framework\ContentBlock\HtmlBlock) {' . PHP_EOL)
->indent()
->write('$block->addInlineStyle([\'content\'=> $content] + $attributes, $priority, $group);' . PHP_EOL)
->outdent()
->write('}' . PHP_EOL);
}
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* @package Grav\Common\Twig
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Twig\TokenParser;
use Grav\Common\Twig\Node\TwigNodeLink;
use Twig\Error\SyntaxError;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
/**
* Adds a link to the document. First parameter is always value of `rel` without quotes.
*
* {% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}
* {% link modulepreload 'plugin://grav-plugin/build/js/vendor.js' %}
*/
class TwigTokenParserLink extends AbstractTokenParser
{
protected $rel = [
'alternate',
'author',
'dns-prefetch',
'help',
'icon',
'license',
'next',
'pingback',
'preconnect',
'prefetch',
'preload',
'prerender',
'prev',
'search',
'stylesheet',
];
/**
* Parses a token and returns a node.
*
* @param Token $token
* @return TwigNodeLink
* @throws SyntaxError
*/
public function parse(Token $token)
{
$lineno = $token->getLine();
[$rel, $file, $group, $priority, $attributes] = $this->parseArguments($token);
return new TwigNodeLink($rel, $file, $group, $priority, $attributes, $lineno, $this->getTag());
}
/**
* @param Token $token
* @return array
*/
protected function parseArguments(Token $token): array
{
$stream = $this->parser->getStream();
$rel = null;
if ($stream->test(Token::NAME_TYPE, $this->rel)) {
$rel = $stream->getCurrent()->getValue();
$stream->next();
}
$file = null;
if (!$stream->test(Token::NAME_TYPE) && !$stream->test(Token::BLOCK_END_TYPE)) {
$file = $this->parser->getExpressionParser()->parseExpression();
}
$group = null;
if ($stream->nextIf(Token::NAME_TYPE, 'at')) {
$group = $this->parser->getExpressionParser()->parseExpression();
}
$priority = null;
if ($stream->nextIf(Token::NAME_TYPE, 'priority')) {
$stream->expect(Token::PUNCTUATION_TYPE, ':');
$priority = $this->parser->getExpressionParser()->parseExpression();
}
$attributes = null;
if ($stream->nextIf(Token::NAME_TYPE, 'with')) {
$attributes = $this->parser->getExpressionParser()->parseExpression();
}
$stream->expect(Token::BLOCK_END_TYPE);
return [$rel, $file, $group, $priority, $attributes];
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag(): string
{
return 'link';
}
}

View File

@@ -15,14 +15,20 @@ use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
/**
* Adds a script to head/bottom/custom location in the document.
* Adds a script to head/bottom/custom group location in the document.
*
* {% script 'theme://js/something.js' at 'bottom' priority: 20 with { defer: true, async: true } %}
* {% script 'theme://js/something.js' at 'bottom' priority: 20 with { position: 'pipeline', loading: 'async defer' } %}
* {% script module 'theme://js/module.mjs' at 'head' %}
*
* {% script 'theme://js/something.js' at 'bottom' priority: 20 with { loading: 'inline' } %}
* {% script at 'bottom' priority: 20 %}
* alert('Warning!');
* alert('Warning!');
* {% endscript %}
*
* {% script module 'theme://js/module.mjs' at 'bottom' with { loading: 'inline' } %}
* {% script module at 'bottom' %}
* ...
* {% endscript %}
*/
class TwigTokenParserScript extends AbstractTokenParser
{
@@ -38,7 +44,7 @@ class TwigTokenParserScript extends AbstractTokenParser
$lineno = $token->getLine();
$stream = $this->parser->getStream();
[$file, $group, $priority, $attributes] = $this->parseArguments($token);
[$type, $file, $group, $priority, $attributes] = $this->parseArguments($token);
$content = null;
if ($file === null) {
@@ -46,7 +52,7 @@ class TwigTokenParserScript extends AbstractTokenParser
$stream->expect(Token::BLOCK_END_TYPE);
}
return new TwigNodeScript($content, $file, $group, $priority, $attributes, $lineno, $this->getTag());
return new TwigNodeScript($content, $type, $file, $group, $priority, $attributes, $lineno, $this->getTag());
}
/**
@@ -73,6 +79,12 @@ class TwigTokenParserScript extends AbstractTokenParser
} while (true);
}
$type = null;
if ($stream->test(Token::NAME_TYPE, 'module')) {
$type = $stream->getCurrent()->getValue();
$stream->next();
}
$file = null;
if (!$stream->test(Token::NAME_TYPE) && !$stream->test(Token::OPERATOR_TYPE, 'in') && !$stream->test(Token::BLOCK_END_TYPE)) {
$file = $this->parser->getExpressionParser()->parseExpression();
@@ -96,7 +108,7 @@ class TwigTokenParserScript extends AbstractTokenParser
$stream->expect(Token::BLOCK_END_TYPE);
return [$file, $group, $priority, $attributes];
return [$type, $file, $group, $priority, $attributes];
}
/**

View File

@@ -29,6 +29,8 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
/** @var array */
protected $scripts = [];
/** @var array */
protected $links = [];
/** @var array */
protected $html = [];
/**
@@ -40,6 +42,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$this->sortAssets($assets['styles']);
$this->sortAssets($assets['scripts']);
$this->sortAssets($assets['links']);
$this->sortAssets($assets['html']);
return $assets;
@@ -73,6 +76,15 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
return $this->getAssetsInLocation('scripts', $location);
}
/**
* @param string $location
* @return array
*/
public function getLinks($location = 'head')
{
return $this->getAssetsInLocation('links', $location);
}
/**
* @param string $location
* @return array
@@ -98,6 +110,9 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
if ($this->scripts) {
$array['scripts'] = $this->scripts;
}
if ($this->links) {
$array['links'] = $this->links;
}
if ($this->html) {
$array['html'] = $this->html;
}
@@ -117,6 +132,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$this->frameworks = isset($serialized['frameworks']) ? (array) $serialized['frameworks'] : [];
$this->styles = isset($serialized['styles']) ? (array) $serialized['styles'] : [];
$this->scripts = isset($serialized['scripts']) ? (array) $serialized['scripts'] : [];
$this->links = isset($serialized['links']) ? (array) $serialized['links'] : [];
$this->html = isset($serialized['html']) ? (array) $serialized['html'] : [];
}
@@ -229,8 +245,9 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$src = $element['src'];
$type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';
$defer = isset($element['defer']);
$async = isset($element['async']);
$loading = !empty($element['loading']) ? (string) $element['loading'] : null;
$defer = !empty($element['defer']);
$async = !empty($element['async']);
$handle = !empty($element['handle']) ? (string) $element['handle'] : '';
$this->scripts[$location][md5($src) . sha1($src)] = [
@@ -238,6 +255,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
':priority' => (int) $priority,
'src' => $src,
'type' => $type,
'loading' => $loading,
'defer' => $defer,
'async' => $async,
'handle' => $handle
@@ -266,12 +284,80 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';
$loading = !empty($element['loading']) ? (string) $element['loading'] : null;
$this->scripts[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
'type' => $type,
'loading' => $loading
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addModule($element, $priority = 0, $location = 'head')
{
if (!is_array($element)) {
$element = ['src' => (string) $element];
}
$element['type'] = 'module';
return $this->addScript($element, $priority, $location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addInlineModule($element, $priority = 0, $location = 'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
$element['type'] = 'module';
return $this->addInlineScript($element, $priority, $location);
}
/**
* @param array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addLink($element, $priority = 0, $location = 'head')
{
if (!is_array($element) || empty($element['rel']) || empty($element['href'])) {
return false;
}
if (!isset($this->links[$location])) {
$this->links[$location] = [];
}
$rel = (string) $element['rel'];
$href = (string) $element['href'];
unset($element['rel'], $element['href']);
$this->links[$location][md5($href) . sha1($href)] = [
':type' => 'file',
':priority' => (int) $priority,
'href' => $href,
'rel' => $rel,
'element' => $element,
];
return true;
@@ -309,6 +395,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
'frameworks' => $this->frameworks,
'styles' => $this->styles,
'scripts' => $this->scripts,
'links' => $this->links,
'html' => $this->html
];
@@ -333,6 +420,14 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
}
}
foreach ($blockAssets['links'] as $location => $links) {
if (!isset($assets['links'][$location])) {
$assets['links'][$location] = $links;
} elseif ($links) {
$assets['links'][$location] += $links;
}
}
foreach ($blockAssets['html'] as $location => $htmls) {
if (!isset($assets['html'][$location])) {
$assets['html'][$location] = $htmls;
@@ -391,7 +486,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
*/
protected function sortAssets(array &$array)
{
foreach ($array as $location => &$items) {
foreach ($array as &$items) {
$this->sortAssetsInLocation($items);
}
}

View File

@@ -37,6 +37,13 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function getScripts($location = 'head');
/**
* @param string $location
* @return array
*/
public function getLinks($location = 'head');
/**
* @param string $location
* @return array
@@ -76,7 +83,6 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function addScript($element, $priority = 0, $location = 'head');
/**
* @param string|array $element
* @param int $priority
@@ -85,6 +91,35 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function addInlineScript($element, $priority = 0, $location = 'head');
/**
* Shortcut for writing addScript(['type' => 'module', 'src' => ...]).
*
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addModule($element, $priority = 0, $location = 'head');
/**
* Shortcut for writing addInlineScript(['type' => 'module', 'content' => ...]).
*
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addInlineModule($element, $priority = 0, $location = 'head');
/**
* @param array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addLink($element, $priority = 0, $location = 'head');
/**
* @param string $html
* @param int $priority

View File

@@ -130,6 +130,9 @@ parameters:
-
message: '#Call to deprecated method getLegacyFiles\(\)#'
path: '*/system/src/Grav/Common/Session.php'
-
message: '#Call to deprecated method \w+\(\) of class Grav\\Common\\Flex\\Types\\Users\\UserObject#'
path: '*/system/src/Grav/Common/Flex/Types/Users/UserObject.php'
-
message: '#Call to deprecated method \w+\(\) of class Grav\\Framework\\Flex\\FlexObject#'
path: '*/system/src/Grav/Framework/Flex/FlexObject.php'