mirror of
https://github.com/getgrav/grav.git
synced 2026-07-05 21:48:30 +02:00
Merge branch 'release/1.1.9'
This commit is contained in:
68
CHANGELOG.md
68
CHANGELOG.md
@@ -1,3 +1,71 @@
|
||||
# v1.1.9
|
||||
## 12/13/2016
|
||||
|
||||
1. [](#new)
|
||||
* RC released as stable
|
||||
1. [](#improved)
|
||||
* Better error handling in cache clear
|
||||
* YAML syntax fixes for the future compatibility
|
||||
* Added new parameter `remove` for `onBeforeCacheClear` event
|
||||
* Add support for calling Media object as function to get medium by filename
|
||||
1. [](#bugfix)
|
||||
* Added checks before accessing admin reference during `Page::blueprints()` call. Allows to access `page.blueprints` from Twig in the frontend
|
||||
|
||||
# v1.1.9-rc.3
|
||||
## 12/07/2016
|
||||
|
||||
1. [](#new)
|
||||
* Add `ignore_empty` property to be used on array fields, if positive only save options with a value
|
||||
* Use new `permissions` field in user account
|
||||
* Add `range(int start, int end, int step)` twig function to generate an array of numbers between start and end, inclusive
|
||||
* New retina Media image derivatives array support (``) [#1147](https://github.com/getgrav/grav/pull/1147)
|
||||
* Added stream support for images (``)
|
||||
* Added stream support for links (`[Download PDF](user://data/pdf/my.pdf)`)
|
||||
* Added new `onBeforeCacheClear` event to add custom paths to cache clearing process
|
||||
1. [](#improved)
|
||||
* Added alias `selfupdate` to the `self-upgrade` `bin/gpm` CLI command
|
||||
* Synced `webserver-configs/htaccess.txt` with `.htaccess`
|
||||
* Use permissions field in group details.
|
||||
* Updated vendor libraries
|
||||
* Added a warning on GPM update to update Grav first if needed [#1194](https://github.com/getgrav/grav/pull/1194)
|
||||
1. [](#bugfix)
|
||||
* Fix page collections problem with `@page.modular` [#1178](https://github.com/getgrav/grav/pull/1178)
|
||||
* Fix issue with using a multiple taxonomy filter of which one had no results, thanks to @hughbris [#1184](https://github.com/getgrav/grav/issues/1184)
|
||||
* Fix saving permissions in group
|
||||
* Fixed issue with redirect of a page getting moved to a different location
|
||||
|
||||
# v1.1.9-rc.2
|
||||
## 11/26/2016
|
||||
|
||||
1. [](#new)
|
||||
* Added two new sort order options for pages: `publish_date` and `unpublish_date` [#1173](https://github.com/getgrav/grav/pull/1173))
|
||||
1. [](#improved)
|
||||
* Multisite: Create image cache folder if it doesn't exist
|
||||
* Add 2 new language values for French [#1174](https://github.com/getgrav/grav/issues/1174)
|
||||
1. [](#bugfix)
|
||||
* Fixed issue when we have a meta file without corresponding media [#1179](https://github.com/getgrav/grav/issues/1179)
|
||||
* Update class namespace for Admin class [#874](https://github.com/getgrav/grav-plugin-admin/issues/874)
|
||||
|
||||
# v1.1.9-rc.1
|
||||
## 11/09/2016
|
||||
|
||||
1. [](#new)
|
||||
* Added a `CompiledJsonFile` object to better handle Json files.
|
||||
* Added Base32 encode/decode class
|
||||
* Added a new `User::find()` method
|
||||
1. [](#improved)
|
||||
* Moved `messages` object into core Grav from login plugin
|
||||
* Added `getTaxonomyItemKeys` to the Taxonomy object [#1124](https://github.com/getgrav/grav/issues/1124)
|
||||
* Added a `redirect_me` Twig function [#1124](https://github.com/getgrav/grav/issues/1124)
|
||||
* Added a Caddyfile for newer Caddy versions [#1115](https://github.com/getgrav/grav/issues/1115)
|
||||
* Allow to override sorting flags for page header-based or default ordering. If the `intl` PHP extension is loaded, only these flags are available: https://secure.php.net/manual/en/collator.asort.php. Otherwise, you can use the PHP standard sorting flags (https://secure.php.net/manual/en/array.constants.php) [#1169](https://github.com/getgrav/grav/issues/1169)
|
||||
1. [](#bugfix)
|
||||
* Fixed an issue with site redirects/routes, not processing with extension (.html, .json, etc.)
|
||||
* Don't truncate HTML if content length is less than summary size [#1125](https://github.com/getgrav/grav/issues/1125)
|
||||
* Return max available number when calling random() on a collection passing an int > available items [#1135](https://github.com/getgrav/grav/issues/1135)
|
||||
* Use correct ratio when applying image filters to image alternatives [#1147](https://github.com/getgrav/grav/issues/1147)
|
||||
* Fixed URI path in multi-site when query parameters were used in front page
|
||||
|
||||
# v1.1.8
|
||||
## 10/22/2016
|
||||
|
||||
|
||||
285
composer.lock
generated
285
composer.lock
generated
@@ -53,16 +53,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.6.0",
|
||||
"version": "v1.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
|
||||
"reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
|
||||
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3",
|
||||
"reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -119,7 +119,7 @@
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2015-12-31 16:37:02"
|
||||
"time": "2016-10-29 11:16:17"
|
||||
},
|
||||
{
|
||||
"name": "donatj/phpuseragentparser",
|
||||
@@ -178,12 +178,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/erusev/parsedown.git",
|
||||
"reference": "cbc4b3f6126e484acc033ec4edf3886f319a0c0f"
|
||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cbc4b3f6126e484acc033ec4edf3886f319a0c0f",
|
||||
"reference": "cbc4b3f6126e484acc033ec4edf3886f319a0c0f",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -212,7 +212,7 @@
|
||||
"markdown",
|
||||
"parser"
|
||||
],
|
||||
"time": "2016-10-09 10:04:16"
|
||||
"time": "2016-11-02 15:56:58"
|
||||
},
|
||||
{
|
||||
"name": "erusev/parsedown-extra",
|
||||
@@ -466,16 +466,16 @@
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/minify",
|
||||
"version": "1.3.38",
|
||||
"version": "1.3.42",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matthiasmullie/minify.git",
|
||||
"reference": "de4bcf23b6a3291bd828ce800aab834304eb50c5"
|
||||
"reference": "b473affbb76ae6ec4e46d368b5081b5bfcdd3ed2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/de4bcf23b6a3291bd828ce800aab834304eb50c5",
|
||||
"reference": "de4bcf23b6a3291bd828ce800aab834304eb50c5",
|
||||
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/b473affbb76ae6ec4e46d368b5081b5bfcdd3ed2",
|
||||
"reference": "b473affbb76ae6ec4e46d368b5081b5bfcdd3ed2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -484,6 +484,7 @@
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "~1.0",
|
||||
"matthiasmullie/scrapbook": "~1.0",
|
||||
"phpunit/phpunit": "~4.8"
|
||||
},
|
||||
@@ -518,7 +519,7 @@
|
||||
"minifier",
|
||||
"minify"
|
||||
],
|
||||
"time": "2016-10-13 11:49:22"
|
||||
"time": "2016-11-23 10:16:14"
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/path-converter",
|
||||
@@ -632,16 +633,16 @@
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.21.0",
|
||||
"version": "1.22.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952"
|
||||
"reference": "bad29cb8d18ab0315e6c477751418a82c850d558"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952",
|
||||
"reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558",
|
||||
"reference": "bad29cb8d18ab0315e6c477751418a82c850d558",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -652,7 +653,7 @@
|
||||
"psr/log-implementation": "1.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "^2.4.9",
|
||||
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
|
||||
"doctrine/couchdb": "~1.0@dev",
|
||||
"graylog2/gelf-php": "~1.0",
|
||||
"jakub-onderka/php-parallel-lint": "0.9",
|
||||
@@ -706,7 +707,7 @@
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2016-07-29 03:23:52"
|
||||
"time": "2016-11-26 00:15:39"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
@@ -899,16 +900,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.12",
|
||||
"version": "v2.8.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4"
|
||||
"reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/d7a5a88178f94dcc29531ea4028ea614e35452d4",
|
||||
"reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/a871ba00e0f604dceac64c56c27f99fbeaf4854e",
|
||||
"reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -956,7 +957,7 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-09-28 00:10:16"
|
||||
"time": "2016-11-15 23:02:12"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
@@ -1017,16 +1018,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.8.12",
|
||||
"version": "v2.8.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "889983a79a043dfda68f38c38b6dba092dd49cd8"
|
||||
"reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8",
|
||||
"reference": "889983a79a043dfda68f38c38b6dba092dd49cd8",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/25c576abd4e0f212e678fe8b2bd9a9a98c7ea934",
|
||||
"reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1073,20 +1074,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-07-28 16:56:28"
|
||||
"time": "2016-10-13 01:43:15"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-iconv",
|
||||
"version": "v1.2.0",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||
"reference": "b287e8554b1ffd9b5b20b5df940d906930ff4a10"
|
||||
"reference": "cba36f3616d9866b3e52662e88da5c090fac1e97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/b287e8554b1ffd9b5b20b5df940d906930ff4a10",
|
||||
"reference": "b287e8554b1ffd9b5b20b5df940d906930ff4a10",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/cba36f3616d9866b3e52662e88da5c090fac1e97",
|
||||
"reference": "cba36f3616d9866b3e52662e88da5c090fac1e97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1098,7 +1099,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1132,20 +1133,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2016-05-18 14:26:46"
|
||||
"time": "2016-11-14 01:06:16"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.2.0",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "dff51f72b0706335131b00a7f49606168c582594"
|
||||
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
|
||||
"reference": "dff51f72b0706335131b00a7f49606168c582594",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
|
||||
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1157,7 +1158,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1191,20 +1192,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2016-05-18 14:26:46"
|
||||
"time": "2016-11-14 01:06:16"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v2.8.12",
|
||||
"version": "v2.8.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "08761341cc4a3b2d9d9578364f7c655b178254aa"
|
||||
"reference": "195c6238ec319cde9204b2d7f271654ceb69b71b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/08761341cc4a3b2d9d9578364f7c655b178254aa",
|
||||
"reference": "08761341cc4a3b2d9d9578364f7c655b178254aa",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/195c6238ec319cde9204b2d7f271654ceb69b71b",
|
||||
"reference": "195c6238ec319cde9204b2d7f271654ceb69b71b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1254,20 +1255,20 @@
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2016-09-29 14:06:15"
|
||||
"time": "2016-11-03 07:52:58"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.8.12",
|
||||
"version": "v2.8.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c"
|
||||
"reference": "befb26a3713c97af90d25dd12e75621ef14d91ff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/e7540734bad981fe59f8ef14b6fc194ae9df8d9c",
|
||||
"reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/befb26a3713c97af90d25dd12e75621ef14d91ff",
|
||||
"reference": "befb26a3713c97af90d25dd12e75621ef14d91ff",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1303,20 +1304,20 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-09-02 01:57:56"
|
||||
"time": "2016-11-14 16:15:57"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.26.1",
|
||||
"version": "v1.28.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "a09d8ee17ac1cfea29ed60c83960ad685c6a898d"
|
||||
"reference": "b22ce0eb070e41f7cba65d78fe216de29726459c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a09d8ee17ac1cfea29ed60c83960ad685c6a898d",
|
||||
"reference": "a09d8ee17ac1cfea29ed60c83960ad685c6a898d",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/b22ce0eb070e41f7cba65d78fe216de29726459c",
|
||||
"reference": "b22ce0eb070e41f7cba65d78fe216de29726459c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1324,12 +1325,12 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/debug": "~2.7",
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
"symfony/phpunit-bridge": "~3.2@dev"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.26-dev"
|
||||
"dev-master": "1.28-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1364,22 +1365,22 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2016-10-05 18:57:41"
|
||||
"time": "2016-11-23 18:41:40"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "behat/gherkin",
|
||||
"version": "v4.4.4",
|
||||
"version": "v4.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Behat/Gherkin.git",
|
||||
"reference": "cf8cc94647101e02a33d690245896d83d880aea1"
|
||||
"reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Behat/Gherkin/zipball/cf8cc94647101e02a33d690245896d83d880aea1",
|
||||
"reference": "cf8cc94647101e02a33d690245896d83d880aea1",
|
||||
"url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74",
|
||||
"reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1425,20 +1426,20 @@
|
||||
"gherkin",
|
||||
"parser"
|
||||
],
|
||||
"time": "2016-09-18 12:16:14"
|
||||
"time": "2016-10-30 11:50:56"
|
||||
},
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "2.2.5",
|
||||
"version": "2.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "b4729341e469d0f174f3cade85718ff5bf8dd751"
|
||||
"reference": "86770e89d266557c20dd0b1de5390e706f4770c1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/b4729341e469d0f174f3cade85718ff5bf8dd751",
|
||||
"reference": "b4729341e469d0f174f3cade85718ff5bf8dd751",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/86770e89d266557c20dd0b1de5390e706f4770c1",
|
||||
"reference": "86770e89d266557c20dd0b1de5390e706f4770c1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1456,7 +1457,7 @@
|
||||
"symfony/browser-kit": ">=2.7 <4.0",
|
||||
"symfony/console": ">=2.7 <4.0",
|
||||
"symfony/css-selector": ">=2.7 <4.0",
|
||||
"symfony/dom-crawler": ">=2.7 <4.0",
|
||||
"symfony/dom-crawler": ">=2.7.5 <4.0",
|
||||
"symfony/event-dispatcher": ">=2.7 <4.0",
|
||||
"symfony/finder": ">=2.7 <4.0",
|
||||
"symfony/yaml": ">=2.7 <4.0"
|
||||
@@ -1472,7 +1473,8 @@
|
||||
"pda/pheanstalk": "~3.0",
|
||||
"php-amqplib/php-amqplib": "~2.4",
|
||||
"predis/predis": "^1.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
"squizlabs/php_codesniffer": "~2.0",
|
||||
"vlucas/phpdotenv": "^2.4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"codeception/specify": "BDD-style code blocks",
|
||||
@@ -1516,7 +1518,7 @@
|
||||
"functional testing",
|
||||
"unit testing"
|
||||
],
|
||||
"time": "2016-09-29 01:29:59"
|
||||
"time": "2016-12-05 04:12:24"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
@@ -1731,16 +1733,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
|
||||
"reference": "2693c101803ca78b27972d84081d027fca790a1e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
|
||||
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/2693c101803ca78b27972d84081d027fca790a1e",
|
||||
"reference": "2693c101803ca78b27972d84081d027fca790a1e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1778,7 +1780,7 @@
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"time": "2016-05-18 16:56:05"
|
||||
"time": "2016-11-18 17:47:58"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
@@ -1939,16 +1941,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "0.2",
|
||||
"version": "0.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
|
||||
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
|
||||
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
|
||||
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1982,20 +1984,20 @@
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"time": "2016-06-10 07:14:17"
|
||||
"time": "2016-11-25 06:54:22"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.6.1",
|
||||
"version": "v1.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "58a8137754bc24b25740d4281399a4a3596058e0"
|
||||
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
|
||||
"reference": "58a8137754bc24b25740d4281399a4a3596058e0",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
|
||||
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2003,10 +2005,11 @@
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
|
||||
"sebastian/comparator": "^1.1",
|
||||
"sebastian/recursion-context": "^1.0"
|
||||
"sebastian/recursion-context": "^1.0|^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^2.0"
|
||||
"phpspec/phpspec": "^2.0",
|
||||
"phpunit/phpunit": "^4.8 || ^5.6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2044,7 +2047,7 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2016-06-07 08:13:47"
|
||||
"time": "2016-11-21 14:58:47"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -2110,16 +2113,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
|
||||
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2153,7 +2156,7 @@
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2015-06-21 13:08:43"
|
||||
"time": "2016-10-03 07:40:28"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
@@ -2242,16 +2245,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.4.8",
|
||||
"version": "1.4.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
|
||||
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
|
||||
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
|
||||
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2287,20 +2290,20 @@
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2015-09-15 10:49:45"
|
||||
"time": "2016-11-15 14:06:22"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.8.27",
|
||||
"version": "4.8.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90"
|
||||
"reference": "a534e04d0bd39c557c2881c341efd06fa6f1292a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c062dddcb68e44b563f66ee319ddae2b5a322a90",
|
||||
"reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a534e04d0bd39c557c2881c341efd06fa6f1292a",
|
||||
"reference": "a534e04d0bd39c557c2881c341efd06fa6f1292a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2316,7 +2319,7 @@
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "^1.0.6",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/comparator": "~1.2.2",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.3",
|
||||
"sebastian/exporter": "~1.2",
|
||||
@@ -2359,7 +2362,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2016-07-21 06:48:14"
|
||||
"time": "2016-12-01 17:05:48"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@@ -2469,22 +2472,22 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
|
||||
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
|
||||
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
|
||||
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/exporter": "~1.2"
|
||||
"sebastian/exporter": "~1.2 || ~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
@@ -2529,7 +2532,7 @@
|
||||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2015-07-26 15:48:44"
|
||||
"time": "2016-11-19 09:18:40"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@@ -2841,16 +2844,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v3.1.5",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "901319a31c9b3cee7857b4aeeb81b5d64dfa34fc"
|
||||
"reference": "34348c2691ce6254e8e008026f4c5e72c22bb318"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/901319a31c9b3cee7857b4aeeb81b5d64dfa34fc",
|
||||
"reference": "901319a31c9b3cee7857b4aeeb81b5d64dfa34fc",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/34348c2691ce6254e8e008026f4c5e72c22bb318",
|
||||
"reference": "34348c2691ce6254e8e008026f4c5e72c22bb318",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2867,7 +2870,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2894,20 +2897,20 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-09-06 11:02:40"
|
||||
"time": "2016-10-13 13:35:11"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v3.1.5",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "ca809c64072e0fe61c1c7fb3c76cdc32265042ac"
|
||||
"reference": "e1241f275814827c411d922ba8e64cf2a00b2994"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/ca809c64072e0fe61c1c7fb3c76cdc32265042ac",
|
||||
"reference": "ca809c64072e0fe61c1c7fb3c76cdc32265042ac",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/e1241f275814827c411d922ba8e64cf2a00b2994",
|
||||
"reference": "e1241f275814827c411d922ba8e64cf2a00b2994",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2916,7 +2919,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2947,20 +2950,20 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-09-06 11:02:40"
|
||||
"time": "2016-11-03 08:11:03"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v3.1.5",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "bb7395e8b1db3654de82b9f35d019958276de4d7"
|
||||
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb7395e8b1db3654de82b9f35d019958276de4d7",
|
||||
"reference": "bb7395e8b1db3654de82b9f35d019958276de4d7",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c6b6111f5aae7c58698cdc10220785627ac44a2c",
|
||||
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2976,7 +2979,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3003,20 +3006,20 @@
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-08-05 08:37:39"
|
||||
"time": "2016-11-25 12:32:42"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v3.1.5",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f"
|
||||
"reference": "4263e35a1e342a0f195c9349c0dee38148f8a14f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/205b5ffbb518a98ba2ae60a52656c4a31ab00c6f",
|
||||
"reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/4263e35a1e342a0f195c9349c0dee38148f8a14f",
|
||||
"reference": "4263e35a1e342a0f195c9349c0dee38148f8a14f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3025,7 +3028,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3052,24 +3055,24 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-09-28 00:11:12"
|
||||
"time": "2016-11-03 08:11:03"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozart/assert.git",
|
||||
"reference": "bb2d123231c095735130cc8f6d31385a44c7b308"
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308",
|
||||
"reference": "bb2d123231c095735130cc8f6d31385a44c7b308",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.3|^7.0"
|
||||
"php": "^5.3.3 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6",
|
||||
@@ -3078,7 +3081,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3102,7 +3105,7 @@
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2016-08-09 15:02:57"
|
||||
"time": "2016-11-23 20:04:58"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
@@ -2,7 +2,7 @@ title: PLUGIN_ADMIN.DEFAULT
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-zа-я][a-zа-я0-9_\-]+"
|
||||
pattern: '[a-zа-я][a-zа-я0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -139,7 +139,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::rawRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::rawRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ title: PLUGIN_ADMIN:EXTERNAL
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-zа-я][a-zа-я0-9_\-]+"
|
||||
pattern: '[a-zа-я][a-zа-я0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -30,7 +30,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::rawRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::rawRoute'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -79,7 +79,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::rawRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::rawRoute'
|
||||
options:
|
||||
'': PLUGIN_ADMIN.DEFAULT_OPTION_SELECT
|
||||
validate:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -12,6 +12,6 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::rawRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::rawRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -32,7 +32,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::getLastPageRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::getLastPageRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
validate:
|
||||
@@ -44,7 +44,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PAGE_FILE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
data-options@: '\Grav\Common\Page\Pages::types'
|
||||
data-default@: '\Grav\Plugin\admin::getLastPageName'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::getLastPageName'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -25,7 +25,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::getLastPageRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::getLastPageRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
validate:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
pattern: '[a-z][a-z0-9_\-]+'
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
@@ -79,7 +79,7 @@ form:
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
data-default@: '\Grav\Plugin\admin::rawRoute'
|
||||
data-default@: '\Grav\Plugin\Admin\Admin::rawRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
title: Site
|
||||
title: Account
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
@@ -56,7 +56,7 @@ form:
|
||||
label: PLUGIN_ADMIN.LANGUAGE
|
||||
size: medium
|
||||
classes: fancy
|
||||
data-options@: '\Grav\Plugin\admin::adminLanguages'
|
||||
data-options@: '\Grav\Plugin\Admin\Admin::adminLanguages'
|
||||
default: 'en'
|
||||
help: PLUGIN_ADMIN.LANGUAGE_HELP
|
||||
|
||||
@@ -77,16 +77,9 @@ form:
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
access:
|
||||
type: permissions
|
||||
label: PLUGIN_ADMIN.PERMISSIONS
|
||||
ignore_empty: true
|
||||
validate:
|
||||
type: array
|
||||
|
||||
@@ -29,16 +29,9 @@ form:
|
||||
size: small
|
||||
label: PLUGIN_ADMIN_PRO.ICON
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
access:
|
||||
type: permissions
|
||||
label: PLUGIN_ADMIN.PERMISSIONS
|
||||
ignore_empty: true
|
||||
validate:
|
||||
type: array
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.1.8');
|
||||
define('GRAV_VERSION', '1.1.9');
|
||||
define('GRAV_TESTING', false);
|
||||
define('DS', '/');
|
||||
define('GRAV_PHP_MIN', '5.5.9');
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Grav\Common;
|
||||
use \Doctrine\Common\Cache as DoctrineCache;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
|
||||
/**
|
||||
* The GravCache object is used throughout Grav to store and retrieve cached data.
|
||||
@@ -356,36 +356,38 @@ class Cache extends Getters
|
||||
$remove_paths = self::$standard_remove;
|
||||
}
|
||||
|
||||
// Clearing cache event to add paths to clear
|
||||
Grav::instance()->fireEvent('onBeforeCacheClear', new Event(['remove' => $remove, 'paths' => &$remove_paths]));
|
||||
|
||||
foreach ($remove_paths as $stream) {
|
||||
|
||||
// Convert stream to a real path
|
||||
try {
|
||||
$path = $locator->findResource($stream, true, true);
|
||||
} catch (\Exception $e) {
|
||||
// stream not found..
|
||||
continue;
|
||||
}
|
||||
|
||||
$anything = false;
|
||||
$files = glob($path . '/*');
|
||||
$anything = false;
|
||||
$files = glob($path . '/*');
|
||||
|
||||
if (is_array($files)) {
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (@unlink($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (Folder::delete($file)) {
|
||||
$anything = true;
|
||||
if (is_array($files)) {
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (@unlink($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (Folder::delete($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($anything) {
|
||||
$output[] = '<red>Cleared: </red>' . $path . '/*';
|
||||
if ($anything) {
|
||||
$output[] = '<red>Cleared: </red>' . $path . '/*';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// stream not found or another error while deleting files.
|
||||
$output[] = '<red>ERROR: </red>' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -569,6 +570,7 @@ class Validation
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if ($options) {
|
||||
$useKey = isset($field['use']) && $field['use'] == 'keys';
|
||||
foreach ($values as $key => $value) {
|
||||
@@ -586,6 +588,18 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($field['ignore_empty']) && Utils::isPositive($field['ignore_empty'])) {
|
||||
foreach ($values as $key => $value) {
|
||||
foreach ($value as $inner_key => $inner_value) {
|
||||
if ($inner_value == '') {
|
||||
unset($value[$inner_key]);
|
||||
}
|
||||
}
|
||||
|
||||
$values[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,58 +23,63 @@ trait CompiledFile
|
||||
// Set some options
|
||||
$this->settings(['native' => true, 'compat' => true]);
|
||||
|
||||
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
|
||||
if ($var === null && $this->raw === null && $this->content === null) {
|
||||
$key = md5($this->filename);
|
||||
$file = PhpFile::instance(CACHE_DIR . DS . "compiled/files/{$key}{$this->extension}.php");
|
||||
try {
|
||||
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
|
||||
if ($var === null && $this->raw === null && $this->content === null) {
|
||||
$key = md5($this->filename);
|
||||
$file = PhpFile::instance(CACHE_DIR . DS . "compiled/files/{$key}{$this->extension}.php");
|
||||
|
||||
$modified = $this->modified();
|
||||
$modified = $this->modified();
|
||||
|
||||
if (!$modified) {
|
||||
return $this->decode($this->raw());
|
||||
}
|
||||
|
||||
$class = get_class($this);
|
||||
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!isset($cache['@class'])
|
||||
|| $cache['@class'] != $class
|
||||
|| $cache['modified'] != $modified
|
||||
|| $cache['filename'] != $this->filename
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
if (!$modified) {
|
||||
return $this->decode($this->raw());
|
||||
}
|
||||
|
||||
// Decode RAW file into compiled array.
|
||||
$data = (array) $this->decode($this->raw());
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'filename' => $this->filename,
|
||||
'modified' => $modified,
|
||||
'data' => $data
|
||||
];
|
||||
$class = get_class($this);
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
|
||||
// Compile cached file into bytecode cache
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($file->filename(), true);
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!isset($cache['@class'])
|
||||
|| $cache['@class'] != $class
|
||||
|| $cache['modified'] != $modified
|
||||
|| $cache['filename'] != $this->filename
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
// Decode RAW file into compiled array.
|
||||
$data = (array)$this->decode($this->raw());
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'filename' => $this->filename,
|
||||
'modified' => $modified,
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
|
||||
// Compile cached file into bytecode cache
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($file->filename(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$file->free();
|
||||
$file->free();
|
||||
|
||||
$this->content = $cache['data'];
|
||||
$this->content = $cache['data'];
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException(sprintf('Failed to read %s: %s', basename($this->filename), $e->getMessage()), 500, $e);
|
||||
}
|
||||
|
||||
return parent::content($var);
|
||||
|
||||
28
system/src/Grav/Common/File/CompiledJsonFile.php
Normal file
28
system/src/Grav/Common/File/CompiledJsonFile.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.File
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\File;
|
||||
|
||||
use RocketTheme\Toolbox\File\JsonFile;
|
||||
|
||||
class CompiledJsonFile extends JsonFile
|
||||
{
|
||||
use CompiledFile;
|
||||
|
||||
/**
|
||||
* Decode RAW string into contents.
|
||||
*
|
||||
* @param string $var
|
||||
* @param bool $assoc
|
||||
* @return array mixed
|
||||
*/
|
||||
protected function decode($var, $assoc = true)
|
||||
{
|
||||
return (array) json_decode($var, $assoc);
|
||||
}
|
||||
}
|
||||
@@ -386,7 +386,6 @@ abstract class Folder
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function mkdir($folder)
|
||||
{
|
||||
@@ -396,7 +395,6 @@ abstract class Folder
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function create($folder)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@ class Grav extends Container
|
||||
'events' => 'RocketTheme\Toolbox\Event\EventDispatcher',
|
||||
'cache' => 'Grav\Common\Cache',
|
||||
'session' => 'Grav\Common\Session',
|
||||
'Grav\Common\Service\MessagesServiceProvider',
|
||||
'plugins' => 'Grav\Common\Plugins',
|
||||
'themes' => 'Grav\Common\Themes',
|
||||
'twig' => 'Grav\Common\Twig\Twig',
|
||||
|
||||
103
system/src/Grav/Common/Helpers/Base32.php
Normal file
103
system/src/Grav/Common/Helpers/Base32.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Helpers
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Helpers;
|
||||
|
||||
class Base32 {
|
||||
protected static $base32Chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
protected static $base32Lookup = array(
|
||||
0xFF,0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, // '0', '1', '2', '3', '4', '5', '6', '7'
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // '8', '9', ':', ';', '<', '=', '>', '?'
|
||||
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G'
|
||||
0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
|
||||
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
|
||||
0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF, // 'X', 'Y', 'Z', '[', '\', ']', '^', '_'
|
||||
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g'
|
||||
0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
|
||||
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
|
||||
0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF // 'x', 'y', 'z', '{', '|', '}', '~', 'DEL'
|
||||
);
|
||||
|
||||
/**
|
||||
* Encode in Base32
|
||||
*
|
||||
* @param $bytes
|
||||
* @return string
|
||||
*/
|
||||
public static function encode( $bytes ) {
|
||||
$i = 0; $index = 0; $digit = 0;
|
||||
$base32 = "";
|
||||
$bytes_len = strlen($bytes);
|
||||
while( $i < $bytes_len ) {
|
||||
$currByte = ord($bytes{$i});
|
||||
/* Is the current digit going to span a byte boundary? */
|
||||
if( $index > 3 ) {
|
||||
if( ($i + 1) < $bytes_len ) {
|
||||
$nextByte = ord($bytes{$i+1});
|
||||
} else {
|
||||
$nextByte = 0;
|
||||
}
|
||||
$digit = $currByte & (0xFF >> $index);
|
||||
$index = ($index + 5) % 8;
|
||||
$digit <<= $index;
|
||||
$digit |= $nextByte >> (8 - $index);
|
||||
$i++;
|
||||
} else {
|
||||
$digit = ($currByte >> (8 - ($index + 5))) & 0x1F;
|
||||
$index = ($index + 5) % 8;
|
||||
if( $index == 0 ) $i++;
|
||||
}
|
||||
$base32 .= self::$base32Chars{$digit};
|
||||
}
|
||||
return $base32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode in Base32
|
||||
*
|
||||
* @param $base32
|
||||
* @return string
|
||||
*/
|
||||
public static function decode( $base32 ) {
|
||||
$bytes = array();
|
||||
$base32_len = strlen($base32);
|
||||
for( $i=$base32_len*5/8-1; $i>=0; --$i ) {
|
||||
$bytes[] = 0;
|
||||
}
|
||||
for( $i = 0, $index = 0, $offset = 0; $i < $base32_len; $i++ ) {
|
||||
$lookup = ord($base32{$i}) - ord('0');
|
||||
/* Skip chars outside the lookup table */
|
||||
if( $lookup < 0 || $lookup >= count(self::$base32Lookup) ) {
|
||||
continue;
|
||||
}
|
||||
$digit = self::$base32Lookup[$lookup];
|
||||
/* If this digit is not in the table, ignore it */
|
||||
if( $digit == 0xFF ) continue;
|
||||
if( $index <= 3 ) {
|
||||
$index = ($index + 5) % 8;
|
||||
if( $index == 0) {
|
||||
$bytes[$offset] |= $digit;
|
||||
$offset++;
|
||||
if( $offset >= count($bytes) ) break;
|
||||
} else {
|
||||
$bytes[$offset] |= $digit << (8 - $index);
|
||||
}
|
||||
} else {
|
||||
$index = ($index + 5) % 8;
|
||||
$bytes[$offset] |= ($digit >> $index);
|
||||
$offset++;
|
||||
if ($offset >= count($bytes) ) break;
|
||||
$bytes[$offset] |= $digit << (8 - $index);
|
||||
}
|
||||
}
|
||||
$bites = "";
|
||||
foreach( $bytes as $byte ) $bites .= chr($byte);
|
||||
return $bites;
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,9 @@ namespace Grav\Common\Helpers;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Common\Page\Medium\Medium;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class Excerpts
|
||||
{
|
||||
@@ -115,11 +115,11 @@ class Excerpts
|
||||
*/
|
||||
public static function processLinkExcerpt($excerpt, $page, $type = 'link')
|
||||
{
|
||||
$url = $excerpt['element']['attributes']['href'];
|
||||
$url = htmlspecialchars_decode(urldecode($excerpt['element']['attributes']['href']));
|
||||
|
||||
$url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
|
||||
$url_parts = static::parseUrl($url);
|
||||
|
||||
// if there is a query, then parse it and build action calls
|
||||
// If there is a query, then parse it and build action calls.
|
||||
if (isset($url_parts['query'])) {
|
||||
$actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
|
||||
$parts = explode('=', $item, 2);
|
||||
@@ -129,19 +129,19 @@ class Excerpts
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
// valid attributes supported
|
||||
// Valid attributes supported.
|
||||
$valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];
|
||||
|
||||
// Unless told to not process, go through actions
|
||||
// Unless told to not process, go through actions.
|
||||
if (array_key_exists('noprocess', $actions)) {
|
||||
unset($actions['noprocess']);
|
||||
} else {
|
||||
// loop through actions for the image and call them
|
||||
// Loop through actions for the image and call them.
|
||||
foreach ($actions as $attrib => $value) {
|
||||
$key = $attrib;
|
||||
|
||||
if (in_array($attrib, $valid_attributes)) {
|
||||
// support both class and classes
|
||||
// support both class and classes.
|
||||
if ($attrib == 'classes') {
|
||||
$attrib = 'class';
|
||||
}
|
||||
@@ -154,25 +154,33 @@ class Excerpts
|
||||
$url_parts['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
// if no query elements left, unset query
|
||||
// If no query elements left, unset query.
|
||||
if (empty($url_parts['query'])) {
|
||||
unset ($url_parts['query']);
|
||||
}
|
||||
|
||||
// set path to / if not set
|
||||
// Set path to / if not set.
|
||||
if (empty($url_parts['path'])) {
|
||||
$url_parts['path'] = '';
|
||||
}
|
||||
|
||||
// if special scheme, just return
|
||||
if(isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) {
|
||||
// If scheme isn't http(s)..
|
||||
if (!empty($url_parts['scheme']) && !in_array($url_parts['scheme'], ['http', 'https'])) {
|
||||
// Handle custom streams.
|
||||
if ($type !== 'image' && !empty($url_parts['stream']) && !empty($url_parts['path'])) {
|
||||
$url_parts['path'] = Grav::instance()['base_url_relative'] . '/' . static::resolveStream("{$url_parts['scheme']}://{$url_parts['path']}");
|
||||
unset($url_parts['stream'], $url_parts['scheme']);
|
||||
|
||||
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
// handle paths and such
|
||||
// Handle paths and such.
|
||||
$url_parts = Uri::convertUrl($page, $url_parts, $type);
|
||||
|
||||
// build the URL from the component parts and set it on the element
|
||||
// Build the URL from the component parts and set it on the element.
|
||||
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
|
||||
|
||||
return $excerpt;
|
||||
@@ -187,62 +195,65 @@ class Excerpts
|
||||
*/
|
||||
public static function processImageExcerpt($excerpt, $page)
|
||||
{
|
||||
$url = $excerpt['element']['attributes']['src'];
|
||||
$url = htmlspecialchars_decode(urldecode($excerpt['element']['attributes']['src']));
|
||||
$url_parts = static::parseUrl($url);
|
||||
|
||||
$url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
|
||||
$media = null;
|
||||
$filename = null;
|
||||
|
||||
if (isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) {
|
||||
$stream_path = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];
|
||||
$url_parts['path'] = $stream_path;
|
||||
unset($url_parts['host']);
|
||||
unset($url_parts['scheme']);
|
||||
}
|
||||
if (!empty($url_parts['stream'])) {
|
||||
$filename = $url_parts['scheme'] . '://' . (isset($url_parts['path']) ? $url_parts['path'] : '');
|
||||
|
||||
$this_host = isset($url_parts['host']) && $url_parts['host'] == Grav::instance()['uri']->host();
|
||||
$media = $page->media();
|
||||
|
||||
// if there is no host set but there is a path, the file is local
|
||||
if ((!isset($url_parts['host']) || $this_host) && isset($url_parts['path'])) {
|
||||
} else {
|
||||
// File is also local if scheme is http(s) and host matches.
|
||||
$local_file = isset($url_parts['path'])
|
||||
&& (empty($url_parts['scheme']) || in_array($url_parts['scheme'], ['http', 'https']))
|
||||
&& (empty($url_parts['host']) || $url_parts['host'] == Grav::instance()['uri']->host());
|
||||
|
||||
$path_parts = pathinfo($url_parts['path']);
|
||||
$media = null;
|
||||
if ($local_file) {
|
||||
$filename = basename($url_parts['path']);
|
||||
$folder = dirname($url_parts['path']);
|
||||
|
||||
// get the local path to page media if possible
|
||||
if ($path_parts['dirname'] == $page->url(false, false, false)) {
|
||||
// get the media objects for this page
|
||||
$media = $page->media();
|
||||
} else {
|
||||
// see if this is an external page to this one
|
||||
$base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
|
||||
$page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/');
|
||||
|
||||
$ext_page = Grav::instance()['pages']->dispatch($page_route, true);
|
||||
if ($ext_page) {
|
||||
$media = $ext_page->media();
|
||||
// Get the local path to page media if possible.
|
||||
if ($folder === $page->url(false, false, false)) {
|
||||
// Get the media objects for this page.
|
||||
$media = $page->media();
|
||||
} else {
|
||||
Grav::instance()->fireEvent('onMediaLocate', new Event(['route' => $page_route, 'media' => &$media]));
|
||||
// see if this is an external page to this one
|
||||
$base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
|
||||
$page_route = '/' . ltrim(str_replace($base_url, '', $folder), '/');
|
||||
|
||||
$ext_page = Grav::instance()['pages']->dispatch($page_route, true);
|
||||
if ($ext_page) {
|
||||
$media = $ext_page->media();
|
||||
} else {
|
||||
Grav::instance()->fireEvent('onMediaLocate', new Event(['route' => $page_route, 'media' => &$media]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a media file that matches the path referenced..
|
||||
if ($media && isset($media->all()[$path_parts['basename']])) {
|
||||
// get the medium object
|
||||
/** @var Medium $medium */
|
||||
$medium = $media->all()[$path_parts['basename']];
|
||||
// If there is a media file that matches the path referenced..
|
||||
if ($media && $filename && isset($media[$filename])) {
|
||||
// Get the medium object.
|
||||
/** @var Medium $medium */
|
||||
$medium = $media[$filename];
|
||||
|
||||
// Process operations
|
||||
$medium = static::processMediaActions($medium, $url_parts);
|
||||
// Process operations
|
||||
$medium = static::processMediaActions($medium, $url_parts);
|
||||
|
||||
$alt = isset($excerpt['element']['attributes']['alt']) ? $excerpt['element']['attributes']['alt'] : '';
|
||||
$title = isset($excerpt['element']['attributes']['title']) ? $excerpt['element']['attributes']['title'] : '';
|
||||
$class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
|
||||
$id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
|
||||
$alt = isset($excerpt['element']['attributes']['alt']) ? $excerpt['element']['attributes']['alt'] : '';
|
||||
$title = isset($excerpt['element']['attributes']['title']) ? $excerpt['element']['attributes']['title'] : '';
|
||||
$class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
|
||||
$id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
|
||||
|
||||
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
|
||||
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
|
||||
|
||||
} else {
|
||||
// not a current page media file, see if it needs converting to relative
|
||||
$excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
} else {
|
||||
// Not a current page media file, see if it needs converting to relative.
|
||||
$excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
@@ -282,8 +293,15 @@ class Excerpts
|
||||
|
||||
// loop through actions for the image and call them
|
||||
foreach ($actions as $action) {
|
||||
$medium = call_user_func_array([$medium, $action['method']],
|
||||
explode(',', $action['params']));
|
||||
$matches = [];
|
||||
|
||||
if (preg_match('/\[(.*)\]/', $action['params'], $matches)) {
|
||||
$args = [explode(',', $matches[1])];
|
||||
} else {
|
||||
$args = explode(',', $action['params']);
|
||||
}
|
||||
|
||||
$medium = call_user_func_array([$medium, $action['method']], $args);
|
||||
}
|
||||
|
||||
if (isset($url_parts['fragment'])) {
|
||||
@@ -293,4 +311,40 @@ class Excerpts
|
||||
return $medium;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of parse_url() which works also with local streams.
|
||||
*
|
||||
* @param string $url
|
||||
* @return array|bool
|
||||
*/
|
||||
protected static function parseUrl($url)
|
||||
{
|
||||
$url_parts = parse_url($url);
|
||||
|
||||
if (isset($url_parts['scheme'])) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
// Special handling for the streams.
|
||||
if ($locator->schemeExists($url_parts['scheme'])) {
|
||||
if (isset($url_parts['host'])) {
|
||||
// Merge host and path into a path.
|
||||
$url_parts['path'] = $url_parts['host'] . (isset($url_parts['path']) ? '/' . $url_parts['path'] : '');
|
||||
unset($url_parts['host']);
|
||||
}
|
||||
|
||||
$url_parts['stream'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $url_parts;
|
||||
}
|
||||
|
||||
protected static function resolveStream($url)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
return $locator->isStream($url) ? ($locator->findResource($url, false) ?: $locator->findResource($url, false, true)) : $url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +189,10 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
|
||||
*/
|
||||
public function random($num = 1)
|
||||
{
|
||||
if ($num > count($this->items)) {
|
||||
$num = count($this->items);
|
||||
}
|
||||
|
||||
$this->items = array_intersect_key($this->items, array_flip((array)array_rand($this->items, $num)));
|
||||
|
||||
return $this;
|
||||
|
||||
@@ -52,6 +52,8 @@ class LanguageCodes
|
||||
'fi' => [ 'name' => 'Finnish', 'nativeName' => 'Suomi' ],
|
||||
'fj-FJ' => [ 'name' => 'Fijian', 'nativeName' => 'Vosa vaka-Viti' ],
|
||||
'fr' => [ 'name' => 'French', 'nativeName' => 'Français' ],
|
||||
'fr-CA' => [ 'name' => 'French (Canada)', 'nativeName' => 'Français (Canada)' ],
|
||||
'fr-FR' => [ 'name' => 'French (France)', 'nativeName' => 'Français (France)' ],
|
||||
'fur' => [ 'name' => 'Friulian', 'nativeName' => 'Furlan' ],
|
||||
'fur-IT' => [ 'name' => 'Friulian', 'nativeName' => 'Furlan' ],
|
||||
'fy' => [ 'name' => 'Frisian', 'nativeName' => 'Frysk' ],
|
||||
|
||||
@@ -84,7 +84,6 @@ class Collection extends Iterator
|
||||
public function setParams(array $params)
|
||||
{
|
||||
$this->params = array_merge($this->params, $params);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -172,12 +171,13 @@ class Collection extends Iterator
|
||||
* @param string $by
|
||||
* @param string $dir
|
||||
* @param array $manual
|
||||
* @param string $sort_flags
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function order($by, $dir = 'asc', $manual = null)
|
||||
public function order($by, $dir = 'asc', $manual = null, $sort_flags = null)
|
||||
{
|
||||
$this->items = $this->pages->sortCollection($this, $by, $dir, $manual);
|
||||
$this->items = $this->pages->sortCollection($this, $by, $dir, $manual, $sort_flags);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -8,51 +8,77 @@
|
||||
|
||||
namespace Grav\Common\Page;
|
||||
|
||||
use Grav\Common\Getters;
|
||||
use Grav\Common\Page\Medium\Medium;
|
||||
use Grav\Common\Page\Medium\AbstractMedia;
|
||||
use Grav\Common\Page\Medium\GlobalMedia;
|
||||
use Grav\Common\Page\Medium\MediumFactory;
|
||||
|
||||
class Media extends Getters
|
||||
class Media extends AbstractMedia
|
||||
{
|
||||
protected $gettersVariable = 'instances';
|
||||
protected $path;
|
||||
protected static $global;
|
||||
|
||||
protected $instances = [];
|
||||
protected $images = [];
|
||||
protected $videos = [];
|
||||
protected $audios = [];
|
||||
protected $files = [];
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
*/
|
||||
public function __construct($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
if (!isset(static::$global)) {
|
||||
// Add fallback to global media.
|
||||
static::$global = new GlobalMedia($path);
|
||||
}
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return parent::offsetExists($offset) ?: isset(static::$global[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return parent::offsetGet($offset) ?: static::$global[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize class.
|
||||
*/
|
||||
protected function init()
|
||||
{
|
||||
|
||||
// Handle special cases where page doesn't exist in filesystem.
|
||||
if (!is_dir($path)) {
|
||||
if (!is_dir($this->path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
$iterator = new \FilesystemIterator($path, \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS);
|
||||
$iterator = new \FilesystemIterator($this->path, \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS);
|
||||
|
||||
$media = [];
|
||||
|
||||
/** @var \DirectoryIterator $info */
|
||||
foreach ($iterator as $path => $info) {
|
||||
// Ignore folders and Markdown files.
|
||||
if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename() === '.DS_Store') {
|
||||
if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename()[0] === '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find out what type we're dealing with
|
||||
list($basename, $ext, $type, $extra) = $this->getFileParts($info->getFilename());
|
||||
|
||||
$media["{$basename}.{$ext}"] = isset($media["{$basename}.{$ext}"]) ? $media["{$basename}.{$ext}"] : [];
|
||||
|
||||
if ($type === 'alternative') {
|
||||
$media["{$basename}.{$ext}"][$type] = isset($media["{$basename}.{$ext}"][$type]) ? $media["{$basename}.{$ext}"][$type] : [];
|
||||
$media["{$basename}.{$ext}"][$type][$extra] = [ 'file' => $path, 'size' => $info->getSize() ];
|
||||
} else {
|
||||
$media["{$basename}.{$ext}"][$type] = [ 'file' => $path, 'size' => $info->getSize() ];
|
||||
@@ -75,6 +101,9 @@ class Media extends Getters
|
||||
|
||||
// Create the base medium
|
||||
if (empty($types['base'])) {
|
||||
if (!isset($types['alternative'])) {
|
||||
continue;
|
||||
}
|
||||
$max = max(array_keys($types['alternative']));
|
||||
$medium = $types['alternative'][$max]['file'];
|
||||
$medium = MediumFactory::scaledFromMedium($medium, $max, 1)['file'];
|
||||
@@ -110,8 +139,9 @@ class Media extends Getters
|
||||
$types['alternative'][$i] = MediumFactory::scaledFromMedium($alternatives[$max]['file'], $max, $i);
|
||||
}
|
||||
|
||||
foreach ($types['alternative'] as $ratio => $altMedium) {
|
||||
foreach ($types['alternative'] as $altMedium) {
|
||||
if ($altMedium['file'] != $medium) {
|
||||
$ratio = $altMedium['file']->get('width') / $medium->get('width');
|
||||
$medium->addAlternative($ratio, $altMedium['file']);
|
||||
}
|
||||
}
|
||||
@@ -120,134 +150,4 @@ class Media extends Getters
|
||||
$this->add($name, $medium);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get medium by filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return Medium|null
|
||||
*/
|
||||
public function get($filename)
|
||||
{
|
||||
return isset($this->instances[$filename]) ? $this->instances[$filename] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all image media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function images()
|
||||
{
|
||||
ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all video media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all audio media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->audios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all file media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function add($name, $file)
|
||||
{
|
||||
$this->instances[$name] = $file;
|
||||
switch ($file->type) {
|
||||
case 'image':
|
||||
$this->images[$name] = $file;
|
||||
break;
|
||||
case 'video':
|
||||
$this->videos[$name] = $file;
|
||||
break;
|
||||
case 'audio':
|
||||
$this->audios[$name] = $file;
|
||||
break;
|
||||
default:
|
||||
$this->files[$name] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename, extension and meta part.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileParts($filename)
|
||||
{
|
||||
$fileParts = explode('.', $filename);
|
||||
|
||||
$name = array_shift($fileParts);
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
|
||||
if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
|
||||
$name = $matches[1];
|
||||
$extension = $matches[3];
|
||||
$extra = (int) $matches[2];
|
||||
$type = 'alternative';
|
||||
|
||||
if ($extra === 1) {
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
}
|
||||
} else {
|
||||
$extension = null;
|
||||
while (($part = array_shift($fileParts)) !== null) {
|
||||
if ($part != 'meta' && $part != 'thumb') {
|
||||
if (isset($extension)) {
|
||||
$name .= '.' . $extension;
|
||||
}
|
||||
$extension = $part;
|
||||
} else {
|
||||
$type = $part;
|
||||
$extra = '.' . $part . '.' . implode('.', $fileParts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($name, $extension, $type, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
164
system/src/Grav/Common/Page/Medium/AbstractMedia.php
Normal file
164
system/src/Grav/Common/Page/Medium/AbstractMedia.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Page
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Getters;
|
||||
|
||||
abstract class AbstractMedia extends Getters
|
||||
{
|
||||
protected $gettersVariable = 'instances';
|
||||
|
||||
protected $instances = [];
|
||||
protected $images = [];
|
||||
protected $videos = [];
|
||||
protected $audios = [];
|
||||
protected $files = [];
|
||||
|
||||
/**
|
||||
* Get medium by filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return Medium|null
|
||||
*/
|
||||
public function get($filename)
|
||||
{
|
||||
return $this->offsetGet($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call object as function to get medium by filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke($filename)
|
||||
{
|
||||
return $this->offsetGet($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all image media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function images()
|
||||
{
|
||||
ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all video media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all audio media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->audios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all file media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param Medium $file
|
||||
*/
|
||||
protected function add($name, $file)
|
||||
{
|
||||
$this->instances[$name] = $file;
|
||||
switch ($file->type) {
|
||||
case 'image':
|
||||
$this->images[$name] = $file;
|
||||
break;
|
||||
case 'video':
|
||||
$this->videos[$name] = $file;
|
||||
break;
|
||||
case 'audio':
|
||||
$this->audios[$name] = $file;
|
||||
break;
|
||||
default:
|
||||
$this->files[$name] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename, extension and meta part.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileParts($filename)
|
||||
{
|
||||
if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
|
||||
$name = $matches[1];
|
||||
$extension = $matches[3];
|
||||
$extra = (int) $matches[2];
|
||||
$type = 'alternative';
|
||||
|
||||
if ($extra === 1) {
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
}
|
||||
} else {
|
||||
$fileParts = explode('.', $filename);
|
||||
|
||||
$name = array_shift($fileParts);
|
||||
$extension = null;
|
||||
$extra = null;
|
||||
$type = 'base';
|
||||
|
||||
while (($part = array_shift($fileParts)) !== null) {
|
||||
if ($part != 'meta' && $part != 'thumb') {
|
||||
if (isset($extension)) {
|
||||
$name .= '.' . $extension;
|
||||
}
|
||||
$extension = $part;
|
||||
} else {
|
||||
$type = $part;
|
||||
$extra = '.' . $part . '.' . implode('.', $fileParts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($name, $extension, $type, $extra);
|
||||
}
|
||||
}
|
||||
117
system/src/Grav/Common/Page/Medium/GlobalMedia.php
Normal file
117
system/src/Grav/Common/Page/Medium/GlobalMedia.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Page
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class GlobalMedia extends AbstractMedia
|
||||
{
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return parent::offsetExists($offset) ?: !empty($this->resolveStream($offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return parent::offsetGet($offset) ?: $this->addMedium($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string|null
|
||||
*/
|
||||
protected function resolveStream($filename)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
return $locator->isStream($filename) ? ($locator->findResource($filename) ?: null) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $stream
|
||||
* @return Medium|null
|
||||
*/
|
||||
protected function addMedium($stream)
|
||||
{
|
||||
$filename = $this->resolveStream($stream);
|
||||
if (!$filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = dirname($filename);
|
||||
list($basename, $ext,, $extra) = $this->getFileParts(basename($filename));
|
||||
$medium = MediumFactory::fromFile($filename);
|
||||
|
||||
if (empty($medium)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$medium->set('size', filesize($filename));
|
||||
$scale = (int) ($extra ?: 1);
|
||||
|
||||
if ($scale !== 1) {
|
||||
$altMedium = $medium;
|
||||
|
||||
// Create scaled down regular sized image.
|
||||
$medium = MediumFactory::scaledFromMedium($altMedium, $scale, 1)['file'];
|
||||
|
||||
if (empty($medium)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add original sized image as alternative.
|
||||
$medium->addAlternative($scale, $altMedium['file']);
|
||||
|
||||
// Locate or generate smaller retina images.
|
||||
for ($i = $scale-1; $i > 1; $i--) {
|
||||
$altFilename = "{$path}/{$basename}@{$i}x.{$ext}";
|
||||
|
||||
if (file_exists($altFilename)) {
|
||||
$scaled = MediumFactory::fromFile($altFilename);
|
||||
} else {
|
||||
$scaled = MediumFactory::scaledFromMedium($altMedium, $scale, $i)['file'];
|
||||
}
|
||||
|
||||
if ($scaled) {
|
||||
$medium->addAlternative($i, $scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$meta = "{$path}/{$basename}.{$ext}.yaml";
|
||||
if (file_exists($meta)) {
|
||||
$medium->addMetaFile($meta);
|
||||
}
|
||||
$meta = "{$path}/{$basename}.{$ext}.meta.yaml";
|
||||
if (file_exists($meta)) {
|
||||
$medium->addMetaFile($meta);
|
||||
}
|
||||
|
||||
$thumb = "{$path}/{$basename}.thumb.{$ext}";
|
||||
if (file_exists($thumb)) {
|
||||
$medium->set('thumbnails.page', $thumb);
|
||||
}
|
||||
|
||||
$this->add($stream, $medium);
|
||||
|
||||
return $medium;
|
||||
}
|
||||
}
|
||||
@@ -236,14 +236,16 @@ class ImageMedium extends Medium
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate derivatives
|
||||
* Generate alternative image widths, using either an array of integers, or
|
||||
* a min width, a max width, and a step parameter to fill out the necessary
|
||||
* widths. Existing image alternatives won't be overwritten.
|
||||
*
|
||||
* @param int $min_width
|
||||
* @param int $max_width
|
||||
* @param int $step
|
||||
* @param int|int[] $min_width
|
||||
* @param int [$max_width=2500]
|
||||
* @param int [$step=200]
|
||||
* @return $this
|
||||
*/
|
||||
public function derivatives($min_width, $max_width, $step = 200) {
|
||||
public function derivatives($min_width, $max_width = 2500, $step = 200) {
|
||||
if (!empty($this->alternatives)) {
|
||||
$max = max(array_keys($this->alternatives));
|
||||
$base = $this->alternatives[$max];
|
||||
@@ -251,10 +253,23 @@ class ImageMedium extends Medium
|
||||
$base = $this;
|
||||
}
|
||||
|
||||
// Do not upscale images.
|
||||
$max_width = min($max_width, $base->get('width'));
|
||||
$widths = [];
|
||||
|
||||
for ($width = $min_width; $width < $max_width; $width = $width + $step) {
|
||||
if (func_num_args() === 1) {
|
||||
foreach ((array) func_get_arg(0) as $width) {
|
||||
if ($width < $base->get('width')) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$max_width = min($max_width, $base->get('width'));
|
||||
|
||||
for ($width = $min_width; $width < $max_width; $width = $width + $step) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($widths as $width) {
|
||||
// Only generate image alternatives that don't already exist
|
||||
if (array_key_exists((int) $width, $this->alternatives)) {
|
||||
continue;
|
||||
@@ -267,10 +282,10 @@ class ImageMedium extends Medium
|
||||
// retrieved from the page cache
|
||||
if (isset($derivative)) {
|
||||
$index = 2;
|
||||
$widths = array_keys($this->alternatives);
|
||||
sort($widths);
|
||||
$alt_widths = array_keys($this->alternatives);
|
||||
sort($alt_widths);
|
||||
|
||||
foreach ($widths as $i => $key) {
|
||||
foreach ($alt_widths as $i => $key) {
|
||||
if ($width > $key) {
|
||||
$index += max($i, 1);
|
||||
}
|
||||
@@ -497,7 +512,7 @@ class ImageMedium extends Medium
|
||||
try {
|
||||
call_user_func_array([$this->image, $method], $args);
|
||||
|
||||
foreach ($this->alternatives as $ratio => $medium) {
|
||||
foreach ($this->alternatives as $medium) {
|
||||
if (!$medium->image) {
|
||||
$medium->image();
|
||||
}
|
||||
@@ -509,7 +524,7 @@ class ImageMedium extends Medium
|
||||
if (isset(self::$magic_resize_actions[$method])) {
|
||||
foreach (self::$magic_resize_actions[$method] as $param) {
|
||||
if (isset($args_copy[$param])) {
|
||||
$args_copy[$param] = (int) $args_copy[$param] * $ratio;
|
||||
$args_copy[$param] *= $medium->get('ratio');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,7 +547,9 @@ class ImageMedium extends Medium
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$file = $this->get('filepath');
|
||||
$cacheDir = $locator->findResource('cache://images', true);
|
||||
|
||||
// Use existing cache folder or if it doesn't exist, create it.
|
||||
$cacheDir = $locator->findResource('cache://images', true) ?: $locator->findResource('cache://images', true, true);
|
||||
|
||||
$this->image = ImageFile::open($file)
|
||||
->setCacheDir($cacheDir)
|
||||
|
||||
@@ -150,8 +150,8 @@ class Medium extends Data implements RenderableInterface
|
||||
/**
|
||||
* Get/set querystring for the file's url
|
||||
*
|
||||
* @param string $hash
|
||||
* @param boolean $withHash
|
||||
* @param string $querystring
|
||||
* @param boolean $withQuestionmark
|
||||
* @return string
|
||||
*/
|
||||
public function querystring($querystring = null, $withQuestionmark = true)
|
||||
|
||||
@@ -902,6 +902,8 @@ class Page
|
||||
$this->route(Grav::instance()['pages']->root()->route() . '/' . $this->slug());
|
||||
}
|
||||
|
||||
$this->raw_route = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -2269,6 +2271,7 @@ class Page
|
||||
continue;
|
||||
}
|
||||
foreach ($items as $item) {
|
||||
$item = rawurldecode($item);
|
||||
if (empty($page->taxonomy[$taxonomy]) || !in_array(htmlspecialchars_decode($item,
|
||||
ENT_QUOTES), $page->taxonomy[$taxonomy])
|
||||
) {
|
||||
@@ -2291,7 +2294,14 @@ class Page
|
||||
$by = isset($params['order']['by']) ? $params['order']['by'] : 'default';
|
||||
$dir = isset($params['order']['dir']) ? $params['order']['dir'] : 'asc';
|
||||
$custom = isset($params['order']['custom']) ? $params['order']['custom'] : null;
|
||||
$collection->order($by, $dir, $custom);
|
||||
$sort_flags = isset($params['order']['sort_flags']) ? $params['order']['sort_flags'] : null;
|
||||
|
||||
if (is_array($sort_flags)) {
|
||||
$sort_flags = array_map('constant', $sort_flags); //transform strings to constant value
|
||||
$sort_flags = array_reduce($sort_flags, function($a, $b) { return $a | $b; }, 0); //merge constant values using bit or
|
||||
}
|
||||
|
||||
$collection->order($by, $dir, $custom, $sort_flags);
|
||||
}
|
||||
|
||||
/** @var Grav $grav */
|
||||
@@ -2411,7 +2421,10 @@ class Page
|
||||
switch ($parts[0]) {
|
||||
case 'modular':
|
||||
$results = new Collection();
|
||||
$results = $results->addPage($page)->Modular();
|
||||
foreach ($page->children() as $child) {
|
||||
$results = $results->addPage($child);
|
||||
}
|
||||
$results->modular();
|
||||
break;
|
||||
case 'page':
|
||||
case 'self':
|
||||
|
||||
@@ -21,6 +21,7 @@ use Grav\Plugin\Admin;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Whoops\Exception\ErrorException;
|
||||
use Collator as Collator;
|
||||
|
||||
class Pages
|
||||
{
|
||||
@@ -197,7 +198,7 @@ class Pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function sort(Page $page, $order_by = null, $order_dir = null)
|
||||
public function sort(Page $page, $order_by = null, $order_dir = null, $sort_flags = null)
|
||||
{
|
||||
if ($order_by === null) {
|
||||
$order_by = $page->orderBy();
|
||||
@@ -214,7 +215,7 @@ class Pages
|
||||
}
|
||||
|
||||
if (!isset($this->sort[$path][$order_by])) {
|
||||
$this->buildSort($path, $children, $order_by, $page->orderManual());
|
||||
$this->buildSort($path, $children, $order_by, $page->orderManual(), $sort_flags);
|
||||
}
|
||||
|
||||
$sort = $this->sort[$path][$order_by];
|
||||
@@ -235,7 +236,7 @@ class Pages
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public function sortCollection(Collection $collection, $orderBy, $orderDir = 'asc', $orderManual = null)
|
||||
public function sortCollection(Collection $collection, $orderBy, $orderDir = 'asc', $orderManual = null, $sort_flags = null)
|
||||
{
|
||||
$items = $collection->toArray();
|
||||
if (!$items) {
|
||||
@@ -244,7 +245,7 @@ class Pages
|
||||
|
||||
$lookup = md5(json_encode($items) . json_encode($orderManual) . $orderBy . $orderDir);
|
||||
if (!isset($this->sort[$lookup][$orderBy])) {
|
||||
$this->buildSort($lookup, $items, $orderBy, $orderManual);
|
||||
$this->buildSort($lookup, $items, $orderBy, $orderManual, $sort_flags);
|
||||
}
|
||||
|
||||
$sort = $this->sort[$lookup][$orderBy];
|
||||
@@ -342,13 +343,19 @@ class Pages
|
||||
$page = $this->dispatch($route, $all);
|
||||
} else {
|
||||
// Try Regex style redirects
|
||||
$source_url = $url;
|
||||
$extension = $this->grav['uri']->extension();
|
||||
if (isset($extension)) {
|
||||
$source_url.= '.' . $extension;
|
||||
}
|
||||
|
||||
$site_redirects = $config->get("site.redirects");
|
||||
if (is_array($site_redirects)) {
|
||||
foreach ((array)$site_redirects as $pattern => $replace) {
|
||||
$pattern = '#' . $pattern . '#';
|
||||
try {
|
||||
$found = preg_replace($pattern, $replace, $url);
|
||||
if ($found != $url) {
|
||||
$found = preg_replace($pattern, $replace, $source_url);
|
||||
if ($found != $source_url) {
|
||||
$this->grav->redirectLangSafe($found);
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
@@ -363,8 +370,8 @@ class Pages
|
||||
foreach ((array)$site_routes as $pattern => $replace) {
|
||||
$pattern = '#' . $pattern . '#';
|
||||
try {
|
||||
$found = preg_replace($pattern, $replace, $url);
|
||||
if ($found != $url) {
|
||||
$found = preg_replace($pattern, $replace, $source_url);
|
||||
if ($found != $source_url) {
|
||||
$page = $this->dispatch($found, $all);
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
@@ -564,17 +571,21 @@ class Pages
|
||||
*/
|
||||
public static function pageTypes()
|
||||
{
|
||||
/** @var Admin $admin */
|
||||
$admin = Grav::instance()['admin'];
|
||||
if (isset(Grav::instance()['admin'])) {
|
||||
/** @var Admin $admin */
|
||||
$admin = Grav::instance()['admin'];
|
||||
|
||||
/** @var Page $page */
|
||||
$page = $admin->getPage($admin->route);
|
||||
/** @var Page $page */
|
||||
$page = $admin->getPage($admin->route);
|
||||
|
||||
if ($page && $page->modular()) {
|
||||
return static::modularTypes();
|
||||
if ($page && $page->modular()) {
|
||||
return static::modularTypes();
|
||||
}
|
||||
|
||||
return static::types();
|
||||
}
|
||||
|
||||
return static::types();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,11 +658,12 @@ class Pages
|
||||
|
||||
$parents = $pages->getList(null, 0, $rawRoutes);
|
||||
|
||||
/** @var Admin $admin */
|
||||
$admin = $grav['admin'];
|
||||
if (isset($grav['admin'])) {
|
||||
// Remove current route from parents
|
||||
|
||||
/** @var Admin $admin */
|
||||
$admin = $grav['admin'];
|
||||
|
||||
// Remove current route from parents
|
||||
if (isset($admin)) {
|
||||
$page = $admin->getPage($admin->route);
|
||||
$page_route = $page->route();
|
||||
if (isset($parents[$page_route])) {
|
||||
@@ -1017,12 +1029,11 @@ class Pages
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function buildSort($path, array $pages, $order_by = 'default', $manual = null)
|
||||
protected function buildSort($path, array $pages, $order_by = 'default', $manual = null, $sort_flags = null)
|
||||
{
|
||||
$list = [];
|
||||
$header_default = null;
|
||||
$header_query = null;
|
||||
$sort_flags = SORT_NATURAL | SORT_FLAG_CASE;
|
||||
|
||||
// do this header query work only once
|
||||
if (strpos($order_by, 'header.') === 0) {
|
||||
@@ -1050,6 +1061,14 @@ class Pages
|
||||
$list[$key] = $child->modified();
|
||||
$sort_flags = SORT_REGULAR;
|
||||
break;
|
||||
case 'publish_date':
|
||||
$list[$key] = $child->publishDate();
|
||||
$sort_flags = SORT_REGULAR;
|
||||
break;
|
||||
case 'unpublish_date':
|
||||
$list[$key] = $child->unpublishDate();
|
||||
$sort_flags = SORT_REGULAR;
|
||||
break;
|
||||
case 'slug':
|
||||
$list[$key] = $child->slug();
|
||||
break;
|
||||
@@ -1064,16 +1083,20 @@ class Pages
|
||||
} else {
|
||||
$list[$key] = $header_default ?: $key;
|
||||
}
|
||||
$sort_flags = SORT_REGULAR;
|
||||
$sort_flags = $sort_flags ?: SORT_REGULAR;
|
||||
break;
|
||||
case 'manual':
|
||||
case 'default':
|
||||
default:
|
||||
$list[$key] = $key;
|
||||
$sort_flags = SORT_REGULAR;
|
||||
$sort_flags = $sort_flags ?: SORT_REGULAR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$sort_flags) {
|
||||
$sort_flags = SORT_NATURAL | SORT_FLAG_CASE;
|
||||
}
|
||||
|
||||
// handle special case when order_by is random
|
||||
if ($order_by == 'random') {
|
||||
$list = $this->arrayShuffle($list);
|
||||
@@ -1081,7 +1104,7 @@ class Pages
|
||||
// else just sort the list according to specified key
|
||||
if (extension_loaded('intl')) {
|
||||
$locale = setlocale(LC_COLLATE, 0); //`setlocale` with a 0 param returns the current locale set
|
||||
$col = \Collator::create($locale);
|
||||
$col = Collator::create($locale);
|
||||
if ($col) {
|
||||
$col->asort($list, $sort_flags);
|
||||
} else {
|
||||
|
||||
30
system/src/Grav/Common/Service/MessagesServiceProvider.php
Normal file
30
system/src/Grav/Common/Service/MessagesServiceProvider.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Service
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Service;
|
||||
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
use RocketTheme\Toolbox\Session\Message;
|
||||
|
||||
class MessagesServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
public function register(Container $container)
|
||||
{
|
||||
// Define session message service.
|
||||
$container['messages'] = function ($c) {
|
||||
$session = $c['session'];
|
||||
|
||||
if (!isset($session->messages)) {
|
||||
$session->messages = new Message;
|
||||
}
|
||||
|
||||
return $session->messages;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,8 @@ class Taxonomy
|
||||
foreach ((array)$items as $item) {
|
||||
if (isset($this->taxonomy_map[$taxonomy][$item])) {
|
||||
$matches[] = $this->taxonomy_map[$taxonomy][$item];
|
||||
} else {
|
||||
$matches[] = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,4 +128,20 @@ class Taxonomy
|
||||
|
||||
return $this->taxonomy_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets item keys per taxonomy
|
||||
*
|
||||
* @param string $taxonomy taxonomy name
|
||||
*
|
||||
* @return array keys of this taxonomy
|
||||
*/
|
||||
public function getTaxonomyItemKeys($taxonomy) {
|
||||
if (isset($this->taxonomy_map[$taxonomy])) {
|
||||
|
||||
$results = array_keys($this->taxonomy_map[$taxonomy]);
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ class TwigExtension extends \Twig_Extension
|
||||
new \Twig_SimpleFunction('url', [$this, 'urlFunc']),
|
||||
new \Twig_SimpleFunction('json_decode', [$this, 'jsonDecodeFilter']),
|
||||
new \Twig_SimpleFunction('get_cookie', [$this, 'getCookie']),
|
||||
new \Twig_SimpleFunction('redirect_me', [$this, 'redirectFunc']),
|
||||
new \Twig_SimpleFunction('range', [$this, 'rangeFunc']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -820,4 +822,30 @@ class TwigExtension extends \Twig_Extension
|
||||
{
|
||||
return preg_replace($pattern, $replace, $subject, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* redirect browser from twig
|
||||
*
|
||||
* @param string $url the url to redirect to
|
||||
* @param int $statusCode statusCode, default 303
|
||||
*/
|
||||
public function redirectFunc($url, $statusCode = 303)
|
||||
{
|
||||
header('Location: ' . $url, true, $statusCode);
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an array containing a range of elements, optionally stepped
|
||||
*
|
||||
* @param int $start Minimum number, default 0
|
||||
* @param int $end Maximum number, default `getrandmax()`
|
||||
* @param int $step Increment between elements in the sequence, default 1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rangeFunc($start = 0, $end = 100, $step = 1)
|
||||
{
|
||||
return range($start, $end, $step);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,11 +304,10 @@ class Uri
|
||||
$bits = parse_url($uri);
|
||||
|
||||
// process query string
|
||||
if (isset($bits['query']) && isset($bits['path'])) {
|
||||
if (isset($bits['query'])) {
|
||||
if (!$this->query) {
|
||||
$this->query = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
|
||||
}
|
||||
$uri = $bits['path'];
|
||||
}
|
||||
|
||||
//process fragment
|
||||
@@ -316,8 +315,11 @@ class Uri
|
||||
$this->fragment = $bits['fragment'];
|
||||
}
|
||||
|
||||
// Get the path. If there's no path, make sure pathinfo() still returns dirname variable
|
||||
$path = isset($bits['path']) ? $bits['path'] : '/';
|
||||
|
||||
// remove the extension if there is one set
|
||||
$parts = pathinfo($uri);
|
||||
$parts = pathinfo($path);
|
||||
|
||||
// set the original basename
|
||||
$this->basename = $parts['basename'];
|
||||
@@ -331,12 +333,12 @@ class Uri
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/\.(' . $valid_page_types . ')$/', $parts['basename'])) {
|
||||
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
}
|
||||
|
||||
// set the new url
|
||||
$this->url = $this->root . $uri;
|
||||
$this->path = $uri;
|
||||
$this->url = $this->root . $path;
|
||||
$this->path = $path;
|
||||
$this->content_path = trim(str_replace($this->base, '', $this->path), '/');
|
||||
if ($this->content_path != '') {
|
||||
$this->paths = explode('/', $this->content_path);
|
||||
|
||||
@@ -87,7 +87,7 @@ class Group extends Data
|
||||
$config->set("groups.$this->groupname.$value", $this->items['data'][$value]);
|
||||
}
|
||||
}
|
||||
if ($field['type'] == 'array') {
|
||||
if ($field['type'] == 'array' || $field['type'] == 'permissions') {
|
||||
$value = $field['name'];
|
||||
$arrayValues = Utils::getDotNotation($this->items['data'], $field['name']);
|
||||
|
||||
|
||||
@@ -54,6 +54,42 @@ class User extends Data
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a user by username, email, etc
|
||||
*
|
||||
* @param $query the query to search for
|
||||
* @param array $fields the fields to search
|
||||
* @return User
|
||||
*/
|
||||
public static function find($query, $fields = ['username', 'email'])
|
||||
{
|
||||
$account_dir = Grav::instance()['locator']->findResource('account://');
|
||||
$files = array_diff(scandir($account_dir), ['.', '..']);
|
||||
|
||||
// Try with username first, you never know!
|
||||
if (in_array('username', $fields)) {
|
||||
$user = User::load($query);
|
||||
unset($fields[array_search('username', $fields)]);
|
||||
} else {
|
||||
$user = User::load('');
|
||||
}
|
||||
|
||||
// If not found, try the fields
|
||||
if (!$user->exists()) {
|
||||
foreach ($files as $file) {
|
||||
if (Utils::endsWith($file, YAML_EXT)) {
|
||||
$find_user = User::load(trim(pathinfo($file, PATHINFO_FILENAME)));
|
||||
foreach ($fields as $field) {
|
||||
if ($find_user[$field] == $query) {
|
||||
return $find_user;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove user account.
|
||||
*
|
||||
|
||||
@@ -188,7 +188,11 @@ abstract class Utils
|
||||
*/
|
||||
public static function truncateHtml($text, $length = 100, $ellipsis = '...')
|
||||
{
|
||||
return Truncator::truncateLetters($text, $length, $ellipsis);
|
||||
if (mb_strlen($text) <= $length) {
|
||||
return $text;
|
||||
} else {
|
||||
return Truncator::truncateLetters($text, $length, $ellipsis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,6 @@ class SandboxCommand extends ConsoleCommand
|
||||
* @var array
|
||||
*/
|
||||
protected $mappings = [
|
||||
'/.editorconfig' => '/.editorconfig',
|
||||
'/.gitignore' => '/.gitignore',
|
||||
'/CHANGELOG.md' => '/CHANGELOG.md',
|
||||
'/LICENSE.txt' => '/LICENSE.txt',
|
||||
@@ -59,7 +58,6 @@ class SandboxCommand extends ConsoleCommand
|
||||
'/system' => '/system',
|
||||
'/vendor' => '/vendor',
|
||||
'/webserver-configs' => '/webserver-configs',
|
||||
'/codeception.yml' => '/codeception.yml',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,7 +59,7 @@ class SelfupgradeCommand extends ConsoleCommand
|
||||
{
|
||||
$this
|
||||
->setName("self-upgrade")
|
||||
->setAliases(['selfupgrade'])
|
||||
->setAliases(['selfupgrade', 'selfupdate'])
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Grav\Console\Gpm;
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Common\GPM\Upgrader;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@@ -109,6 +110,22 @@ class UpdateCommand extends ConsoleCommand
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
$this->upgrader = new Upgrader($this->input->getOption('force'));
|
||||
$local = $this->upgrader->getLocalVersion();
|
||||
$remote = $this->upgrader->getRemoteVersion();
|
||||
if ($local !== $remote) {
|
||||
$this->output->writeln("<yellow>WARNING</yellow>: A new version of Grav is available. You should update Grav before updating plugins and themes. If you continue without updating Grav, some plugins or themes may stop working.");
|
||||
$this->output->writeln("");
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion("Continue with the update process? [Y|n] ", true);
|
||||
$answer = $questionHelper->ask($this->input, $this->output, $question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("<red>Update aborted. Exiting...</red>");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
|
||||
@@ -183,4 +183,26 @@ class TwigExtensionTest extends \Codeception\TestCase\Test
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function testRangeFunc()
|
||||
{
|
||||
$hundred = [];
|
||||
for($i = 0; $i <= 100; $i++) { $hundred[] = $i; }
|
||||
|
||||
|
||||
$this->assertSame([0], $this->twig_ext->rangeFunc(0, 0));
|
||||
$this->assertSame([0, 1, 2], $this->twig_ext->rangeFunc(0, 2));
|
||||
|
||||
$this->assertSame([0, 5, 10, 15], $this->twig_ext->rangeFunc(0, 16, 5));
|
||||
|
||||
// default (min 0, max 100, step 1)
|
||||
$this->assertSame($hundred, $this->twig_ext->rangeFunc());
|
||||
|
||||
// 95 items, starting from 5, (min 5, max 100, step 1)
|
||||
$this->assertSame(array_slice($hundred, 5), $this->twig_ext->rangeFunc(5));
|
||||
|
||||
// reversed range
|
||||
$this->assertSame(array_reverse($hundred), $this->twig_ext->rangeFunc(100, 0));
|
||||
$this->assertSame([4, 2, 0], $this->twig_ext->rangeFunc(4, 0, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
$this->assertEquals('<p>This is a string to truncate</p>', Utils::truncateHtml('<p>This is a string to truncate</p>', 100));
|
||||
$this->assertEquals('<input type="file" id="file" multiple>', Utils::truncateHtml('<input type="file" id="file" multiple />', 6));
|
||||
$this->assertEquals('<ol><li>item 1 <i>so...</i></li></ol>', Utils::truncateHtml('<ol><li>item 1 <i>something</i></li><li>item 2 <strong>bold</strong></li></ol>', 10));
|
||||
$this->assertEquals("<p>This is a string.</p>\n<p>It splits two lines.</p>", Utils::truncateHtml("<p>This is a string.</p>\n<p>It splits two lines.</p>", 100));
|
||||
}
|
||||
|
||||
public function testSafeTruncateHtml()
|
||||
|
||||
@@ -6,23 +6,25 @@ fastcgi / 127.0.0.1:9000 php
|
||||
# deny all direct access for these folders
|
||||
rewrite {
|
||||
r /(.git|cache|bin|logs|backups|tests)/.*$
|
||||
status 403
|
||||
to /403
|
||||
}
|
||||
# deny running scripts inside core system folders
|
||||
rewrite {
|
||||
r /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$
|
||||
status 403
|
||||
to /403
|
||||
}
|
||||
# deny running scripts inside user folder
|
||||
rewrite {
|
||||
r /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$
|
||||
status 403
|
||||
to /403
|
||||
}
|
||||
# deny access to specific files in the root folder
|
||||
rewrite {
|
||||
r /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)
|
||||
status 403
|
||||
to /403
|
||||
}
|
||||
|
||||
status 403 /403
|
||||
## End - Security
|
||||
|
||||
# global rewrite should come last.
|
||||
|
||||
33
webserver-configs/Caddyfile-0.8.x
Normal file
33
webserver-configs/Caddyfile-0.8.x
Normal file
@@ -0,0 +1,33 @@
|
||||
# Caddyfile for Caddy 0.8.x and below
|
||||
|
||||
:8080
|
||||
gzip
|
||||
fastcgi / 127.0.0.1:9000 php
|
||||
|
||||
# Begin - Security
|
||||
# deny all direct access for these folders
|
||||
rewrite {
|
||||
r /(.git|cache|bin|logs|backups|tests)/.*$
|
||||
status 403
|
||||
}
|
||||
# deny running scripts inside core system folders
|
||||
rewrite {
|
||||
r /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$
|
||||
status 403
|
||||
}
|
||||
# deny running scripts inside user folder
|
||||
rewrite {
|
||||
r /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$
|
||||
status 403
|
||||
}
|
||||
# deny access to specific files in the root folder
|
||||
rewrite {
|
||||
r /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)
|
||||
status 403
|
||||
}
|
||||
## End - Security
|
||||
|
||||
# global rewrite should come last.
|
||||
rewrite {
|
||||
to {path} {path}/ /index.php?_url={uri}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
RewriteEngine On
|
||||
|
||||
## Begin RewriteBase
|
||||
# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# If you are getting 500 or 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# You should change the '/' to your appropriate subfolder. For example if you have
|
||||
# your Grav install at the root of your site '/' should work, else it might be something
|
||||
# along the lines of: RewriteBase /<your_sub_folder>
|
||||
@@ -13,6 +13,16 @@ RewriteEngine On
|
||||
|
||||
## End - RewriteBase
|
||||
|
||||
## Begin - X-Forwarded-Proto
|
||||
# In some hosted or load balanced environments, SSL negotiation happens upstream.
|
||||
# In order for Grav to recognize the connection as secure, you need to uncomment
|
||||
# the following lines.
|
||||
#
|
||||
# RewriteCond %{HTTP:X-Forwarded-Proto} https
|
||||
# RewriteRule .* - [E=HTTPS:on]
|
||||
#
|
||||
## End - X-Forwarded-Proto
|
||||
|
||||
## Begin - Exploits
|
||||
# If you experience problems on your site block out the operations listed below
|
||||
# This attempts to block the most common type of exploit `attempts` to Grav
|
||||
@@ -52,7 +62,7 @@ RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
|
||||
# Block all direct access to .md files:
|
||||
RewriteRule \.md$ error [F]
|
||||
# Block all direct access to files and folders beginning with a dot
|
||||
RewriteRule (^\.|/\.) - [F]
|
||||
RewriteRule (^|/)\.(?!well-known) - [F]
|
||||
# Block access to specific files in the root folder
|
||||
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|\.htaccess)$ error [F]
|
||||
## End - Security
|
||||
@@ -62,4 +72,4 @@ RewriteRule ^(LICENSE.txt|composer.lock|composer.json|\.htaccess)$ error [F]
|
||||
# Begin - Prevent Browsing and Set Default Resources
|
||||
Options -Indexes
|
||||
DirectoryIndex index.php index.html index.htm
|
||||
# End - Prevent Browsing and Set Default Resources
|
||||
# End - Prevent Browsing and Set Default Resources
|
||||
@@ -16,6 +16,17 @@ server {
|
||||
}
|
||||
## End - Index
|
||||
|
||||
## Begin - Security
|
||||
# deny all direct access for these folders
|
||||
location ~* /(.git|cache|bin|logs|backup|tests)/.*$ { return 403; }
|
||||
# deny running scripts inside core system folders
|
||||
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny running scripts inside user folder
|
||||
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny access to specific files in the root folder
|
||||
location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
|
||||
## End - Security
|
||||
|
||||
## Begin - PHP
|
||||
location ~ \.php$ {
|
||||
# Choose either a socket or TCP/IP address
|
||||
@@ -28,16 +39,5 @@ server {
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
}
|
||||
## End - PHP
|
||||
|
||||
## Begin - Security
|
||||
# deny all direct access for these folders
|
||||
location ~* /(.git|cache|bin|logs|backups|tests)/.*$ { return 403; }
|
||||
# deny running scripts inside core system folders
|
||||
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny running scripts inside user folder
|
||||
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny access to specific files in the root folder
|
||||
location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
|
||||
## End - Security
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user