mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
Compare commits
104 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1df6b76e25 | ||
|
|
2153e20bc5 | ||
|
|
0cbc98ab53 | ||
|
|
0915a0413d | ||
|
|
f4d3d302f4 | ||
|
|
5d5e2264c0 | ||
|
|
b39fc72bd2 | ||
|
|
d6d50c4b66 | ||
|
|
791ef8ad88 | ||
|
|
e0861e5505 | ||
|
|
48c9176d90 | ||
|
|
33cb20561e | ||
|
|
0acb38f586 | ||
|
|
1a41e00a4f | ||
|
|
48ef93e495 | ||
|
|
3f7da86711 | ||
|
|
11aa2314d5 | ||
|
|
179c5065ca | ||
|
|
7c60f73942 | ||
|
|
7095c665b7 | ||
|
|
c6d94885e0 | ||
|
|
d9ddab8239 | ||
|
|
a118d45177 | ||
|
|
416c400367 | ||
|
|
e6839530d8 | ||
|
|
fea9e53be3 | ||
|
|
c5b3792a60 | ||
|
|
4f83b5da5b | ||
|
|
504c8faf4c | ||
|
|
4d6db5b334 | ||
|
|
ec1fc1f1e3 | ||
|
|
563cf8900c | ||
|
|
0850c2f362 | ||
|
|
f30334d80f | ||
|
|
9057a804a2 | ||
|
|
4c5c26033a | ||
|
|
a4f679adcf | ||
|
|
e9e12392ac | ||
|
|
6b4663c2ff | ||
|
|
0411c3a98b | ||
|
|
972a758ac9 | ||
|
|
05d72306c6 | ||
|
|
18b7c0955d | ||
|
|
71cbbf4e1e | ||
|
|
0606e12872 | ||
|
|
afc7cac5ab | ||
|
|
471e3d8954 | ||
|
|
89a92cddc7 | ||
|
|
74988f1254 | ||
|
|
f2f2bc1cf8 | ||
|
|
31c5809e4a | ||
|
|
b4b8b63e24 | ||
|
|
9c0de8b0d3 | ||
|
|
f4cca777c2 | ||
|
|
8d7d143d01 | ||
|
|
d9109e9934 | ||
|
|
be8eb63944 | ||
|
|
9342981d8c | ||
|
|
6e9af3bb29 | ||
|
|
7e39755154 | ||
|
|
97af8919fc | ||
|
|
6cdfaeb8fb | ||
|
|
4ea00b0140 | ||
|
|
864c5027c6 | ||
|
|
0bb55faa2d | ||
|
|
f757863e1c | ||
|
|
3ffd2f5f5e | ||
|
|
6aa135e80a | ||
|
|
07f4bd0699 | ||
|
|
c200a55336 | ||
|
|
14fed2bb75 | ||
|
|
44ecd61489 | ||
|
|
882212520f | ||
|
|
9467939f53 | ||
|
|
e3933ebdf6 | ||
|
|
0d99a03c39 | ||
|
|
e9117301d4 | ||
|
|
bf199e9394 | ||
|
|
c070b0afbb | ||
|
|
d54387b281 | ||
|
|
2bc6848464 | ||
|
|
ab7c5d2fc5 | ||
|
|
abefbfc776 | ||
|
|
ad173ca129 | ||
|
|
d69ef0e39c | ||
|
|
436be17881 | ||
|
|
9a5fa7e699 | ||
|
|
d502ff08c1 | ||
|
|
14eb1281f9 | ||
|
|
8fd7a5aebe | ||
|
|
08423df547 | ||
|
|
40563ed2f8 | ||
|
|
b639f09ca7 | ||
|
|
dd134ad551 | ||
|
|
3d93d50cf0 | ||
|
|
f1da7b6063 | ||
|
|
ef7b33f9b6 | ||
|
|
0f0e6ab1c8 | ||
|
|
5362b312d1 | ||
|
|
ca4d6a398f | ||
|
|
ed00d480f2 | ||
|
|
057bdd546b | ||
|
|
7762f0c85e | ||
|
|
4b777f508b |
@@ -12,13 +12,6 @@ notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
hipchat:
|
||||
# hipchat_api@grav
|
||||
rooms:
|
||||
- secure: "bqO0wM1B7bJnQw2fuhquSXEqI9gw6WmFytIh9sEWXzbYTzTUP5t0PcKOd3FT2BNMRaDxPJLVl+vG/oqmqDUBkEmOGcG504IQjeNzZqnMz0tXQMIcCc22Las9tFfc4Jf6RVi/qGomFtHGE9Wgii+TAN4zqZaufbNjwd8SyjO0+W8="
|
||||
template:
|
||||
- '%{repository}#%{build_number} (%{branch}): Travis Job Finished [%{duration}] (<a href="%{build_url}">Details</a>)'
|
||||
format: html
|
||||
slack:
|
||||
secure: dowksPsxxCxGKT6nis5hUgkp6+ZDAhoqzQHF9rJnx4hx0iEygPhVBs7pKl9yL2jubYJoLs+EXwE7z1dYgDAEJh4BnfrCokCMLpFGcxVxQC/HeAUdSQ2/RtdBYR5PRT75ScaFpqM/SfXXZVtnwVXAw9Z+JC6BjQ9vmn23m51Jw4k=
|
||||
env:
|
||||
|
||||
109
CHANGELOG.md
109
CHANGELOG.md
@@ -1,3 +1,102 @@
|
||||
# v1.6.9
|
||||
## 05/09/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added `Route::withoutParams()` methods
|
||||
* Added `Pages::setCheckMethod()` method to override page configuration in Admin Plugin
|
||||
* Added `Cache::clearCache('invalidate')` parameter for just invalidating the cache without deleting any cached files
|
||||
* Made `UserCollectionInderface` to extend `Countable` to get the count of existing users
|
||||
1. [](#improved)
|
||||
* Flex admin: added default search options for flex objects
|
||||
* Flex collection and object now fall back to the default template if template file doesn't exist
|
||||
* Updated Vendor libraries including Twig 1.40.1
|
||||
* Updated language files from `https://crowdin.com/project/grav-core`
|
||||
1. [](#bugfix)
|
||||
* Fixed `$grav['route']` from being modified when the route instance gets modified
|
||||
* Fixed Assets options array mixed with standalone priority [#2477](https://github.com/getgrav/grav/issues/2477)
|
||||
* Fix for `avatar_url` provided by 3rd party providers
|
||||
* Fixed non standard `lang` code lengths in `Utils` and `Session` detection
|
||||
* Fixed saving a new object in Flex `SimpleStorage`
|
||||
* Fixed exception in `Flex::getDirectories()` if the first parameter is set
|
||||
* Output correct "Last Updated" in `bin/gpm info` command
|
||||
* Checkbox getting interpreted as string, so created new `Validation::filterCheckbox()`
|
||||
* Fixed backwards compatibility to `select` field with `selectize.create` set to true [git-sync#141](https://github.com/trilbymedia/grav-plugin-git-sync/issues/141)
|
||||
* Fixed `YamlFormatter::decode()` to always return array [#2494](https://github.com/getgrav/grav/pull/2494)
|
||||
* Fixed empty `$grav['request']->getAttribute('route')->getExtension()`
|
||||
|
||||
# v1.6.8
|
||||
## 04/23/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added `FlexCollection::filterBy()` method
|
||||
1. [](#bugfix)
|
||||
* Revert `Use Null Coalesce Operator` [#2466](https://github.com/getgrav/grav/pull/2466)
|
||||
* Fixed `FormTrait::render()` not providing config variable
|
||||
* Updated `bin/grav clean` to clear `cache/compiled` and `user/config/security.yaml`
|
||||
|
||||
# v1.6.7
|
||||
## 04/22/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `bin/grav yamllinter` CLI command to find YAML Linting issues [#2468](https://github.com/getgrav/grav/issues/2468#issuecomment-485151681)
|
||||
1. [](#improved)
|
||||
* Improve `FormTrait` backwards compatibility with existing forms
|
||||
* Added a new `Utils::getSubnet()` function for IPv4/IPv6 parsing [#2465](https://github.com/getgrav/grav/pull/2465)
|
||||
1. [](#bugfix)
|
||||
* Remove disabled fields from the form schema
|
||||
* Fix issue when excluding `inlineJs` and `inlineCss` from Assets pipeline [#2468](https://github.com/getgrav/grav/issues/2468)
|
||||
* Fix for manually set position on external URLs [#2470](https://github.com/getgrav/grav/issues/2470)
|
||||
|
||||
# v1.6.6
|
||||
## 04/17/2019
|
||||
|
||||
1. [](#new)
|
||||
* `FormInterface` now implements `RenderInterface`
|
||||
* Added new `FormInterface::getTask()` method which reads the task from `form.task` in the blueprint
|
||||
1. [](#improved)
|
||||
* Updated vendor libraries to latest
|
||||
1. [](#bugfix)
|
||||
* Rollback `redirect_default_route` logic as it has issues with multi-lang [#2459](https://github.com/getgrav/grav/issues/2459)
|
||||
* Fix potential issue with `|contains` Twig filter on PHP 7.3
|
||||
* Fixed bug in text field filtering: return empty string if value isn't a string or number [#2460](https://github.com/getgrav/grav/issues/2460)
|
||||
* Force Asset `priority` to be an integer and not throw error if invalid string passed [#2461](https://github.com/getgrav/grav/issues/2461)
|
||||
* Fixed bug in text field filtering: return empty string if value isn't a string or number
|
||||
* Fixed `FlexForm` missing getter methods for defining form variables
|
||||
|
||||
# v1.6.5
|
||||
## 04/15/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Backwards compatiblity with old `Uri::__toString()` output
|
||||
|
||||
# v1.6.4
|
||||
## 04/15/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension`
|
||||
* Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445)
|
||||
* Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446)
|
||||
* Fixed issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332)
|
||||
* Updated rounding logic for `Utils::parseSize()` [#2394](https://github.com/getgrav/grav/issues/2394)
|
||||
* Fixed Flex simple storage not being properly initialized if used with caching
|
||||
|
||||
# v1.6.3
|
||||
## 04/12/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added `Blueprint::addDynamicHandler()` method to allow custom dynamic handlers, for example `custom-options@: getCustomOptions`
|
||||
1. [](#bugfix)
|
||||
* Missed a `CacheCommand` reference in `bin/grav` [#2442](https://github.com/getgrav/grav/issues/2442)
|
||||
* Fixed issue with `Utils::normalizePath` messing with external URLs [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fix for `vUndefined` versions when upgrading
|
||||
|
||||
# v1.6.2
|
||||
## 04/11/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Revert renaming of `ClearCacheCommand` to ensure CLI GPM upgrades go smoothly
|
||||
|
||||
# v1.6.1
|
||||
## 04/11/2019
|
||||
|
||||
@@ -24,7 +123,7 @@
|
||||
* Added `Grav\Framework\Object\ObjectIndex` class
|
||||
* Added `Grav\Framework\Flex` classes
|
||||
* Added support for hiding form fields in blueprints by using dynamic property like `security@: admin.foobar`, `scope@: object` or `scope-ignore@: object` to any field
|
||||
* New experimental **FlexObjects** powered `Users` for increased performance and capability (**disabled** by default)
|
||||
* New experimental **FlexObjects** powered `Users` for increased performance and capability (**disabled** by default)
|
||||
* Added PSR-7 and PSR-15 classes
|
||||
* Added `Grav\Framework\DI\Container` class
|
||||
* Added `Grav\Framework\RequestHandler\RequestHandler` class
|
||||
@@ -100,7 +199,7 @@
|
||||
* Added ability to reset `Page::metadata` to allow rebuilding from automatically generated values
|
||||
* Added back missing `page.types` field in system content configuration [admin#1612](https://github.com/getgrav/grav-plugin-admin/issues/1612)
|
||||
* Console commands: add method for invalidating cache
|
||||
* Updated languages
|
||||
* Updated languages
|
||||
* Improved `$page->forms()` call, added `$page->addForms()`
|
||||
* Updated languages from crowdin
|
||||
* Fixed `ImageMedium` constructor warning when file does not exist
|
||||
@@ -121,7 +220,7 @@
|
||||
* Added apcu autoloader optimization
|
||||
* Additional helper methods in `Language`, `Languages`, and `LanguageCodes` classes
|
||||
* Call `onFatalException` event also on internal PHP errors
|
||||
* Built-in PHP Webserver: log requests before handling them
|
||||
* Built-in PHP Webserver: log requests before handling them
|
||||
* Added support for syslog and syslog facility logging (default: 'file')
|
||||
* Improved usability of `System` configuration blueprint with side-tabs
|
||||
1. [](#bugfix)
|
||||
@@ -146,7 +245,7 @@
|
||||
* Fixed failed login if user attempts to log in with upper case non-english letters
|
||||
* Removed extra authenticated/authorized fields when saving existing user from a form
|
||||
* Fixed `Grav\Framework\Route::__toString()` returning relative URL, not relative route
|
||||
* Fixed handling of `append_url_extension` inside of `Page::templateFormat()` [#2264](https://github.com/getgrav/grav/issues/2264)
|
||||
* Fixed handling of `append_url_extension` inside of `Page::templateFormat()` [#2264](https://github.com/getgrav/grav/issues/2264)
|
||||
* Fixed a broken language string [#2261](https://github.com/getgrav/grav/issues/2261)
|
||||
* Fixed clearing cache having no effect on Doctrine cache
|
||||
* Fixed `Medium::relativePath()` for streams
|
||||
@@ -199,7 +298,7 @@
|
||||
* Updated vendor libraries
|
||||
1. [](#bugfix)
|
||||
* Support spaces with filenames in responsive images [#2300](https://github.com/getgrav/grav/pull/2300)
|
||||
|
||||
|
||||
# v1.5.6
|
||||
## 12/14/2018
|
||||
|
||||
|
||||
21
bin/grav
21
bin/grav
@@ -3,6 +3,7 @@
|
||||
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\Grav;
|
||||
use League\CLImate\CLImate;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
\define('GRAV_CLI', true);
|
||||
@@ -24,7 +25,22 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
|
||||
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
|
||||
}
|
||||
|
||||
Grav::instance(array('loader' => $autoload));
|
||||
$climate = new League\CLImate\CLImate;
|
||||
$climate->arguments->add([
|
||||
'environment' => [
|
||||
'prefix' => 'e',
|
||||
'longPrefix' => 'env',
|
||||
'description' => 'Configuration Environment',
|
||||
'defaultValue' => 'localhost'
|
||||
]
|
||||
]);
|
||||
$climate->arguments->parse();
|
||||
|
||||
// Set up environment based on params.
|
||||
$environment = $climate->arguments->get('environment');
|
||||
|
||||
$grav = Grav::instance(array('loader' => $autoload));
|
||||
$grav->setup($environment);
|
||||
|
||||
if (!ini_get('date.timezone')) {
|
||||
date_default_timezone_set('UTC');
|
||||
@@ -40,11 +56,12 @@ $app->addCommands(array(
|
||||
new \Grav\Console\Cli\ComposerCommand(),
|
||||
new \Grav\Console\Cli\SandboxCommand(),
|
||||
new \Grav\Console\Cli\CleanCommand(),
|
||||
new \Grav\Console\Cli\CacheCommand(),
|
||||
new \Grav\Console\Cli\ClearCacheCommand(),
|
||||
new \Grav\Console\Cli\BackupCommand(),
|
||||
new \Grav\Console\Cli\NewProjectCommand(),
|
||||
new \Grav\Console\Cli\SchedulerCommand(),
|
||||
new \Grav\Console\Cli\SecurityCommand(),
|
||||
new \Grav\Console\Cli\LogViewerCommand(),
|
||||
new \Grav\Console\Cli\YamlLinterCommand(),
|
||||
));
|
||||
$app->run();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"kodus/psr7-server": "*",
|
||||
"nyholm/psr7": "^1.0",
|
||||
|
||||
"twig/twig": "~1.35",
|
||||
"twig/twig": "~1.40",
|
||||
"erusev/parsedown": "1.6.4",
|
||||
"erusev/parsedown-extra": "~0.7",
|
||||
"symfony/yaml": "~4.2",
|
||||
@@ -89,6 +89,8 @@
|
||||
"exclude": ["VERSION"]
|
||||
},
|
||||
"scripts": {
|
||||
"api-16": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.16.md",
|
||||
"api-15": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.md",
|
||||
"post-create-project-cmd": "bin/grav install",
|
||||
"phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon system/src --memory-limit=256M",
|
||||
"phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon system/src/Grav/Framework --memory-limit=256M",
|
||||
|
||||
170
composer.lock
generated
170
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dce6e4d72c9b5ac769cd3d93fecdf1c2",
|
||||
"content-hash": "f9429e7cd2e75a232f968b01a1024983",
|
||||
"packages": [
|
||||
{
|
||||
"name": "antoligy/dom-string-iterators",
|
||||
@@ -541,17 +541,17 @@
|
||||
},
|
||||
{
|
||||
"name": "gregwar/image",
|
||||
"version": "v2.0.24",
|
||||
"version": "v2.0.25",
|
||||
"target-dir": "Gregwar/Image",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Gregwar/Image.git",
|
||||
"reference": "52145816255dd20cb4bb115d0f9e1030c6287994"
|
||||
"reference": "03534d5760cbea5c96e6292041ff81a3bb205c36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Gregwar/Image/zipball/52145816255dd20cb4bb115d0f9e1030c6287994",
|
||||
"reference": "52145816255dd20cb4bb115d0f9e1030c6287994",
|
||||
"url": "https://api.github.com/repos/Gregwar/Image/zipball/03534d5760cbea5c96e6292041ff81a3bb205c36",
|
||||
"reference": "03534d5760cbea5c96e6292041ff81a3bb205c36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -589,7 +589,7 @@
|
||||
"gd",
|
||||
"image"
|
||||
],
|
||||
"time": "2019-01-27T15:10:06+00:00"
|
||||
"time": "2019-03-01T15:55:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
@@ -1333,16 +1333,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c"
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1381,7 +1381,7 @@
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2018-07-30T21:54:04+00:00"
|
||||
"time": "2019-04-30T12:38:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
@@ -1774,16 +1774,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384"
|
||||
"reference": "e2840bb38bddad7a0feaf85931e38fdcffdb2f81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/e2840bb38bddad7a0feaf85931e38fdcffdb2f81",
|
||||
"reference": "e2840bb38bddad7a0feaf85931e38fdcffdb2f81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1842,7 +1842,7 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-04-01T07:32:59+00:00"
|
||||
"time": "2019-04-08T14:23:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/contracts",
|
||||
@@ -1914,16 +1914,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544"
|
||||
"reference": "fbce53cd74ac509cbe74b6f227622650ab759b02"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544",
|
||||
"reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fbce53cd74ac509cbe74b6f227622650ab759b02",
|
||||
"reference": "fbce53cd74ac509cbe74b6f227622650ab759b02",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1974,7 +1974,7 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-03-30T15:58:42+00:00"
|
||||
"time": "2019-04-06T13:51:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -2267,16 +2267,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6"
|
||||
"reference": "8cf39fb4ccff793340c258ee7760fd40bfe745fe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6",
|
||||
"reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/8cf39fb4ccff793340c258ee7760fd40bfe745fe",
|
||||
"reference": "8cf39fb4ccff793340c258ee7760fd40bfe745fe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2312,20 +2312,20 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-03-10T20:07:02+00:00"
|
||||
"time": "2019-04-10T16:20:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "9f87189ac10b42edf7fb8edc846f1937c6d157cf"
|
||||
"reference": "3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/9f87189ac10b42edf7fb8edc846f1937c6d157cf",
|
||||
"reference": "9f87189ac10b42edf7fb8edc846f1937c6d157cf",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce",
|
||||
"reference": "3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2388,11 +2388,11 @@
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
"time": "2019-05-01T12:55:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
@@ -2451,16 +2451,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.38.4",
|
||||
"version": "v1.40.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "7732e9e7017d751313811bd118de61302e9c8b35"
|
||||
"reference": "35889516bbd6bbe46a600c2c33b03515df4a076e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/7732e9e7017d751313811bd118de61302e9c8b35",
|
||||
"reference": "7732e9e7017d751313811bd118de61302e9c8b35",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/35889516bbd6bbe46a600c2c33b03515df4a076e",
|
||||
"reference": "35889516bbd6bbe46a600c2c33b03515df4a076e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2475,7 +2475,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.38-dev"
|
||||
"dev-master": "1.40-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2513,7 +2513,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2019-03-23T14:27:19+00:00"
|
||||
"time": "2019-04-29T14:12:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "willdurand/negotiation",
|
||||
@@ -2630,16 +2630,16 @@
|
||||
},
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "2.5.5",
|
||||
"version": "2.5.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "547a64cb31edcf1902b296c511f5ca74101bcb4c"
|
||||
"reference": "b83a9338296e706fab2ceb49de8a352fbca3dc98"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/547a64cb31edcf1902b296c511f5ca74101bcb4c",
|
||||
"reference": "547a64cb31edcf1902b296c511f5ca74101bcb4c",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/b83a9338296e706fab2ceb49de8a352fbca3dc98",
|
||||
"reference": "b83a9338296e706fab2ceb49de8a352fbca3dc98",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2718,7 +2718,7 @@
|
||||
"functional testing",
|
||||
"unit testing"
|
||||
],
|
||||
"time": "2019-03-23T17:57:45+00:00"
|
||||
"time": "2019-04-24T11:28:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "codeception/phpunit-wrapper",
|
||||
@@ -3172,16 +3172,16 @@
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.8.1",
|
||||
"version": "1.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8"
|
||||
"reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
|
||||
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
|
||||
"reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3216,7 +3216,7 @@
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"time": "2018-06-11T23:09:50+00:00"
|
||||
"time": "2019-04-07T13:18:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/bootstrap",
|
||||
@@ -4000,16 +4000,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "4.3.0",
|
||||
"version": "4.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "94fd0001232e47129dd3504189fa1c7225010d08"
|
||||
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
|
||||
"reference": "94fd0001232e47129dd3504189fa1c7225010d08",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
|
||||
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4047,7 +4047,7 @@
|
||||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2017-11-30T07:14:17+00:00"
|
||||
"time": "2019-04-30T17:48:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
@@ -4161,28 +4161,29 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "2cc49f47c69b023eaf05b48e6529389893b13d74"
|
||||
"reference": "472d3161d289f652713a5e353532fa4592663a57"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/2cc49f47c69b023eaf05b48e6529389893b13d74",
|
||||
"reference": "2cc49f47c69b023eaf05b48e6529389893b13d74",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/472d3161d289f652713a5e353532fa4592663a57",
|
||||
"reference": "472d3161d289f652713a5e353532fa4592663a57",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"consistence/coding-standard": "^2.0.0",
|
||||
"consistence/coding-standard": "^3.5",
|
||||
"jakub-onderka/php-parallel-lint": "^0.9.2",
|
||||
"phing/phing": "^2.16.0",
|
||||
"phpstan/phpstan": "^0.10",
|
||||
"phpunit/phpunit": "^6.3",
|
||||
"slevomat/coding-standard": "^3.3.0",
|
||||
"slevomat/coding-standard": "^4.7.2",
|
||||
"squizlabs/php_codesniffer": "^3.3.2",
|
||||
"symfony/process": "^3.4 || ^4.0"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -4203,7 +4204,7 @@
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||
"time": "2019-01-14T12:26:23+00:00"
|
||||
"time": "2019-04-23T20:26:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
@@ -4578,16 +4579,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "7.5.8",
|
||||
"version": "7.5.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a"
|
||||
"reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c29c0525cf4572c11efe1db49a8b8aee9dfac58a",
|
||||
"reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/134669cf0eeac3f79bc7f0c793efbc158bffc160",
|
||||
"reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4658,7 +4659,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2019-03-26T13:23:54+00:00"
|
||||
"time": "2019-04-19T15:50:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
@@ -4827,16 +4828,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "4.1.0",
|
||||
"version": "4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "6fda8ce1974b62b14935adc02a9ed38252eca656"
|
||||
"reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fda8ce1974b62b14935adc02a9ed38252eca656",
|
||||
"reference": "6fda8ce1974b62b14935adc02a9ed38252eca656",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/3095910f0f0fb155ac4021fc51a4a7a39ac04e8a",
|
||||
"reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4851,7 +4852,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -4876,7 +4877,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2019-02-01T05:27:49+00:00"
|
||||
"time": "2019-04-25T07:55:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@@ -5228,16 +5229,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "61d85c5af2fc058014c7c89504c3944e73a086f0"
|
||||
"reference": "c09c18cca96d7067152f78956faf55346c338283"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/61d85c5af2fc058014c7c89504c3944e73a086f0",
|
||||
"reference": "61d85c5af2fc058014c7c89504c3944e73a086f0",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/c09c18cca96d7067152f78956faf55346c338283",
|
||||
"reference": "c09c18cca96d7067152f78956faf55346c338283",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5281,11 +5282,11 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
"time": "2019-04-07T09:56:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
@@ -5338,7 +5339,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
@@ -5395,16 +5396,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v4.2.5",
|
||||
"version": "v4.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a"
|
||||
"reference": "e45135658bd6c14b61850bf131c4f09a55133f69"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/e45135658bd6c14b61850bf131c4f09a55133f69",
|
||||
"reference": "e45135658bd6c14b61850bf131c4f09a55133f69",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5440,7 +5441,7 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-02-23T15:42:05+00:00"
|
||||
"time": "2019-04-06T13:51:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
@@ -5593,7 +5594,8 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-zip": "*"
|
||||
"ext-zip": "*",
|
||||
"ext-dom": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.6.1');
|
||||
define('GRAV_VERSION', '1.6.9');
|
||||
define('GRAV_TESTING', false);
|
||||
define('DS', '/');
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ GRAV:
|
||||
BAD_DATE: Fecha errónea
|
||||
AGO: antes
|
||||
FROM_NOW: desde ahora
|
||||
JUST_NOW: justo ahora
|
||||
JUST_NOW: hace un momento
|
||||
SECOND: segundo
|
||||
MINUTE: minuto
|
||||
HOUR: hora
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
---
|
||||
GRAV:
|
||||
FRONTMATTER_ERROR_PAGE: "---\npealkiri: %1$s\n---\n\n# Viga: vigane Frontmatter'i\n\nasukoht: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- 'equipment'
|
||||
- 'informatsioon'
|
||||
- 'rice'
|
||||
- 'money'
|
||||
- 'species'
|
||||
- 'series'
|
||||
- 'kala'
|
||||
- 'lammas'
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'inimesed'
|
||||
'man': 'mees'
|
||||
'child': 'lapsed'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': '.'
|
||||
'first': '.'
|
||||
'second': '.'
|
||||
'third': '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Kuupäev määramata
|
||||
BAD_DATE: Vigane kuupäev
|
||||
AGO: tagasi
|
||||
FROM_NOW: praegusest
|
||||
JUST_NOW: just nüüd
|
||||
SECOND: sekund
|
||||
MINUTE: minut
|
||||
HOUR: tundi
|
||||
@@ -60,3 +79,7 @@ GRAV:
|
||||
- 'reede'
|
||||
- 'laupäev'
|
||||
- 'pühapäev'
|
||||
CRON:
|
||||
EVERY: iga
|
||||
EVERY_MONTH: iga kuu
|
||||
TEXT_PERIOD: Iga <b />
|
||||
|
||||
@@ -14,6 +14,8 @@ GRAV:
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1es'
|
||||
'/(bu)s$/i': 'Bus'
|
||||
'/(alias|status)/i': 'alias|status'
|
||||
'/(ax|test)is$/i': '\1s'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
|
||||
@@ -11,6 +11,8 @@ GRAV:
|
||||
- 'fish'
|
||||
- 'sheep'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Engin dagsetning gefin
|
||||
BAD_DATE: Röng dagsetning
|
||||
AGO: síðan
|
||||
JUST_NOW: í þessu
|
||||
SECOND: sekúndu
|
||||
@@ -45,6 +47,7 @@ GRAV:
|
||||
DEC_PLURAL: árat
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Sannvottun mistókst:</b>
|
||||
INVALID_INPUT: Ógilt inntak í
|
||||
MISSING_REQUIRED_FIELD: 'Vantar nauðsynlegan reit:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- 'janúar'
|
||||
@@ -67,3 +70,11 @@ GRAV:
|
||||
- 'Föstudagur'
|
||||
- 'Laugardagur'
|
||||
- 'Sunnudagur'
|
||||
CRON:
|
||||
TEXT_TIME: ' á <b />:<b />'
|
||||
TEXT_DOW: ' á <b />'
|
||||
TEXT_MONTH: ' af <b />'
|
||||
TEXT_DOM: ' á <b />'
|
||||
ERROR1: Merkið %s er ekki stutt!
|
||||
ERROR3: Það ætti að setja jquery_element inn í stillingar jqCron
|
||||
ERROR4: Óþekkt segð
|
||||
|
||||
@@ -35,3 +35,12 @@ GRAV:
|
||||
- 'Outubro'
|
||||
- 'Novembro'
|
||||
- 'Dezembro'
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- 'equipment'
|
||||
- 'information'
|
||||
- 'arroz'
|
||||
- 'money'
|
||||
- 'species'
|
||||
- 'series'
|
||||
- 'fish'
|
||||
- 'sheep'
|
||||
|
||||
@@ -1,10 +1,75 @@
|
||||
---
|
||||
GRAV:
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Chyba: Chybný frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- 'vybavenie'
|
||||
- 'informácie'
|
||||
- 'ryža'
|
||||
- 'peniaze'
|
||||
- 'druhy'
|
||||
- 'séria'
|
||||
- 'ryba'
|
||||
- 'ovce'
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'ľudia'
|
||||
'man': 'muži'
|
||||
'child': 'deti'
|
||||
'sex': 'pohlavia'
|
||||
'move': 'pohyby'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': '.'
|
||||
'first': '.'
|
||||
'second': '.'
|
||||
'third': '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Neposkytnutý žiaden dátum
|
||||
BAD_DATE: Nesprávny dátum
|
||||
AGO: pred
|
||||
FROM_NOW: odteraz
|
||||
JUST_NOW: práve teraz
|
||||
SECOND: sekunda
|
||||
MINUTE: minúta
|
||||
HOUR: hodina
|
||||
@@ -14,10 +79,12 @@ GRAV:
|
||||
YEAR: rok
|
||||
DECADE: desaťročie
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: hod
|
||||
WK: t
|
||||
MO: m
|
||||
YR: r
|
||||
DEC: dec
|
||||
SECOND_PLURAL: sekúnd
|
||||
MINUTE_PLURAL: minút
|
||||
HOUR_PLURAL: hodín
|
||||
@@ -58,3 +125,20 @@ GRAV:
|
||||
- 'Piatok'
|
||||
- 'Sobota'
|
||||
- 'Nedeľa'
|
||||
CRON:
|
||||
EVERY: každý
|
||||
EVERY_HOUR: každú hodinu
|
||||
EVERY_MINUTE: každú minútu
|
||||
EVERY_DAY_OF_WEEK: každý deň v týždni
|
||||
EVERY_DAY_OF_MONTH: každý deň v mesiaci
|
||||
EVERY_MONTH: každý mesiac
|
||||
TEXT_PERIOD: Každý <b />
|
||||
TEXT_MINS: ' at <b /> minute(s) past the hour'
|
||||
TEXT_TIME: ' at <b />:<b />'
|
||||
TEXT_DOW: ' on <b />'
|
||||
TEXT_MONTH: ' of <b />'
|
||||
TEXT_DOM: ' on <b />'
|
||||
ERROR1: Tag %s nieje podporovaný!
|
||||
ERROR2: Chybný počet položiek
|
||||
ERROR3: jquery_element musí byť nastavený v nastaveniach pre jqCron
|
||||
ERROR4: Neznámy výraz
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
---
|
||||
GRAV:
|
||||
FRONTMATTER_ERROR_PAGE: "--- titel: %1$s --- # Fel: Ogiltig Frontmatter-sökväg: `%2$s` **%3$s** ``` %4$s ```"
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- 'utrustning'
|
||||
- 'information'
|
||||
- 'ris'
|
||||
- 'pengar'
|
||||
- 'arter'
|
||||
- 'serier'
|
||||
- 'fisk'
|
||||
- 'får'
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'personer'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Inget datum har angivits
|
||||
BAD_DATE: Ogiltigt datum
|
||||
|
||||
@@ -1,24 +1,44 @@
|
||||
---
|
||||
GRAV:
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# 錯誤: 不正確的 Frontmatter\n\n路徑: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: 沒有提供日期
|
||||
BAD_DATE: 錯誤日期
|
||||
AGO: 之前
|
||||
FROM_NOW: 之後
|
||||
JUST_NOW: 剛剛
|
||||
SECOND: 秒
|
||||
MINUTE: 分
|
||||
HOUR: 小時
|
||||
DAY: 天
|
||||
WEEK: 週
|
||||
MONTH: 月
|
||||
YEAR: 年
|
||||
DECADE: 十年
|
||||
SEC: 秒
|
||||
MIN: 分
|
||||
HR: 小時
|
||||
WK: 週
|
||||
MO: 月
|
||||
YR: 年
|
||||
DEC: 十年
|
||||
SECOND_PLURAL: 秒
|
||||
MINUTE_PLURAL: 分
|
||||
HOUR_PLURAL: 時
|
||||
DAY_PLURAL: 日
|
||||
WEEK_PLURAL: 周
|
||||
HOUR_PLURAL: 小時
|
||||
DAY_PLURAL: 天
|
||||
WEEK_PLURAL: 週
|
||||
MONTH_PLURAL: 月
|
||||
YEAR_PLURAL: 年
|
||||
DECADE_PLURAL: 十年
|
||||
SEC_PLURAL: 秒
|
||||
MIN_PLURAL: 分
|
||||
HR_PLURAL: 時
|
||||
WK_PLURAL: 周
|
||||
WK_PLURAL: 週
|
||||
MO_PLURAL: 月
|
||||
YR_PLURAL: 年
|
||||
DEC_PLURAL: 十年
|
||||
FORM:
|
||||
MISSING_REQUIRED_FIELD: 遺漏必填欄位:
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- '一月'
|
||||
- '二月'
|
||||
|
||||
@@ -1,57 +1,122 @@
|
||||
---
|
||||
GRAV:
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# 錯誤: 不正確的 Frontmatter\n\n路徑: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
FRONTMATTER_ERROR_PAGE: "---\n标题: %1$s\n---\n\n# 错误:无效参数\n\n位置: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- '装备'
|
||||
- '信息'
|
||||
- '大米'
|
||||
- '钱'
|
||||
- '物种'
|
||||
- '系列'
|
||||
- '鱼'
|
||||
- '羊'
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': '人员'
|
||||
'man': '男人'
|
||||
'child': '儿童'
|
||||
'sex': '性别'
|
||||
'move': '移动'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': 'th'
|
||||
'first': 'st'
|
||||
'second': 'md'
|
||||
'third': 'rd'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: 沒有提供日期
|
||||
BAD_DATE: 錯誤日期
|
||||
AGO: 之前
|
||||
FROM_NOW: 之後
|
||||
JUST_NOW: 剛剛
|
||||
NO_DATE_PROVIDED: 无日期信息
|
||||
BAD_DATE: 无效日期
|
||||
AGO: 前
|
||||
FROM_NOW: 距今
|
||||
JUST_NOW: 刚刚
|
||||
SECOND: 秒
|
||||
MINUTE: 分
|
||||
HOUR: 小時
|
||||
MINUTE: 分钟
|
||||
HOUR: 小时
|
||||
DAY: 天
|
||||
WEEK: 週
|
||||
WEEK: 周
|
||||
MONTH: 月
|
||||
YEAR: 年
|
||||
DECADE: 十年
|
||||
SEC: 秒
|
||||
MIN: 分
|
||||
HR: 小時
|
||||
WK: 週
|
||||
MIN: 分钟
|
||||
HR: 小时
|
||||
WK: 周
|
||||
MO: 月
|
||||
YR: 年
|
||||
DEC: 十年
|
||||
DEC: 年代
|
||||
SECOND_PLURAL: 秒
|
||||
MINUTE_PLURAL: 分
|
||||
HOUR_PLURAL: 小時
|
||||
HOUR_PLURAL: 小时
|
||||
DAY_PLURAL: 天
|
||||
WEEK_PLURAL: 週
|
||||
WEEK_PLURAL: 周
|
||||
MONTH_PLURAL: 月
|
||||
YEAR_PLURAL: 年
|
||||
DECADE_PLURAL: 十年
|
||||
SEC_PLURAL: 秒
|
||||
MIN_PLURAL: 分
|
||||
HR_PLURAL: 時
|
||||
WK_PLURAL: 週
|
||||
HR_PLURAL: 时
|
||||
WK_PLURAL: 周
|
||||
MO_PLURAL: 月
|
||||
YR_PLURAL: 年
|
||||
DEC_PLURAL: 十年
|
||||
DEC_PLURAL: 年代
|
||||
FORM:
|
||||
MISSING_REQUIRED_FIELD: 遺漏必填欄位:
|
||||
VALIDATION_FAIL: <b>验证失败:</b>
|
||||
INVALID_INPUT: 无效输入
|
||||
MISSING_REQUIRED_FIELD: 必填字段缺失:
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- '一月'
|
||||
- '二月'
|
||||
- '三月'
|
||||
- '四月'
|
||||
- '五月'
|
||||
- '六月'
|
||||
- '七月'
|
||||
- '八月'
|
||||
- '九月'
|
||||
- '十月'
|
||||
- '十一月'
|
||||
- '十二月'
|
||||
- '1月'
|
||||
- '2月'
|
||||
- '3月'
|
||||
- '4月'
|
||||
- '5月'
|
||||
- '6月'
|
||||
- '7月'
|
||||
- '8月'
|
||||
- '9月'
|
||||
- '10月'
|
||||
- '11月'
|
||||
- '12月'
|
||||
DAYS_OF_THE_WEEK:
|
||||
- '星期一'
|
||||
- '星期二'
|
||||
@@ -60,4 +125,20 @@ GRAV:
|
||||
- '星期五'
|
||||
- '星期六'
|
||||
- '星期日'
|
||||
|
||||
CRON:
|
||||
EVERY: 每隔
|
||||
EVERY_HOUR: 每小时
|
||||
EVERY_MINUTE: 每分钟
|
||||
EVERY_DAY_OF_WEEK: 一周中的每一天
|
||||
EVERY_DAY_OF_MONTH: 月份中的每一天
|
||||
EVERY_MONTH: 每月
|
||||
TEXT_PERIOD: 所有 <b />
|
||||
TEXT_MINS: ' 在 <b /> 小时过后的分钟'
|
||||
TEXT_TIME: ' 在 <b />:<b />'
|
||||
TEXT_DOW: ' on <b />'
|
||||
TEXT_MONTH: ' of <b />'
|
||||
TEXT_DOM: ' on <b />'
|
||||
ERROR1: 不支持分享类型 %s
|
||||
ERROR2: 无效数字
|
||||
ERROR3: 请在 jqCron 设置中设定 jquery_element
|
||||
ERROR4: 无法识别表达式
|
||||
|
||||
@@ -45,8 +45,10 @@ class Assets extends PropertyObject
|
||||
|
||||
// Config Options
|
||||
protected $css_pipeline;
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $css_pipeline_before_excludes;
|
||||
protected $js_pipeline;
|
||||
protected $js_pipeline_include_externals;
|
||||
protected $js_pipeline_before_excludes;
|
||||
protected $pipeline_options = [];
|
||||
|
||||
@@ -170,7 +172,8 @@ class Assets extends PropertyObject
|
||||
// If pipeline disabled, set to position if provided, else after
|
||||
if (isset($options['pipeline'])) {
|
||||
if ($options['pipeline'] === false) {
|
||||
$excludes = strtolower($type . '_pipeline_before_excludes');
|
||||
$exclude_type = ($type === $this::JS_TYPE || $type === $this::INLINE_JS_TYPE) ? $this::JS_TYPE : $this::CSS_TYPE;
|
||||
$excludes = strtolower($exclude_type . '_pipeline_before_excludes');
|
||||
if ($this->{$excludes}) {
|
||||
$default = 'after';
|
||||
} else {
|
||||
@@ -264,6 +267,22 @@ class Assets extends PropertyObject
|
||||
protected function filterAssets($assets, $key, $value, $sort = false)
|
||||
{
|
||||
$results = array_filter($assets, function($asset) use ($key, $value) {
|
||||
|
||||
if ($key === 'position' && $value === 'pipeline') {
|
||||
|
||||
$type = $asset->getType();
|
||||
|
||||
if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false && $asset['position'] === 'pipeline' ) {
|
||||
if ($this->{$type . '_pipeline_before_excludes'}) {
|
||||
$asset->setPosition('after');
|
||||
} else {
|
||||
$asset->setPosition('before');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($asset[$key] === $value) return true;
|
||||
return false;
|
||||
});
|
||||
@@ -292,11 +311,9 @@ class Assets extends PropertyObject
|
||||
$before_output = '';
|
||||
$pipeline_output = '';
|
||||
$after_output = '';
|
||||
$no_pipeline = [];
|
||||
|
||||
$assets = 'assets_' . $type;
|
||||
$pipeline_enabled = $type . '_pipeline';
|
||||
$before_excludes = $type . '_pipeline_before_excludes';
|
||||
$render_pipeline = 'render' . ucfirst($type);
|
||||
|
||||
$group_assets = $this->filterAssets($this->$assets, 'group', $group);
|
||||
@@ -309,22 +326,13 @@ class Assets extends PropertyObject
|
||||
$options = array_merge($this->pipeline_options, ['timestamp' => $this->timestamp]);
|
||||
|
||||
$pipeline = new Pipeline($options);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes, $no_pipeline);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes);
|
||||
} else {
|
||||
foreach ($pipeline_assets as $asset) {
|
||||
$pipeline_output .= $asset->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stuff that couldn't be pipelined
|
||||
if (!empty($no_pipeline)) {
|
||||
if ($this->{$before_excludes}) {
|
||||
$after_assets = array_merge($after_assets, $no_pipeline);
|
||||
} else {
|
||||
$before_assets = array_merge($before_assets, $no_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
// Before Pipeline
|
||||
foreach ($before_assets as $asset) {
|
||||
$before_output .= $asset->render();
|
||||
|
||||
@@ -78,6 +78,9 @@ abstract class BaseAsset extends PropertyObject
|
||||
}
|
||||
}
|
||||
|
||||
// Force priority to be an int
|
||||
$this->priority = (int) $this->priority;
|
||||
|
||||
// Do some special stuff for CSS/JS (not inline)
|
||||
if (!Utils::startsWith($this->getType(), 'inline')) {
|
||||
$this->base_url = rtrim($uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
|
||||
@@ -129,6 +132,12 @@ abstract class BaseAsset extends PropertyObject
|
||||
return $this->remote;
|
||||
}
|
||||
|
||||
public function setPosition($position)
|
||||
{
|
||||
$this->position = $position;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -50,9 +50,6 @@ class Pipeline extends PropertyObject
|
||||
protected $query;
|
||||
protected $asset;
|
||||
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $js_pipeline_include_externals;
|
||||
|
||||
/**
|
||||
* Closure used by the pipeline to fetch assets.
|
||||
*
|
||||
@@ -91,11 +88,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderCss($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderCss($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -119,21 +115,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->css_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('css')) {
|
||||
@@ -164,11 +152,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderJs($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderJs($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -192,21 +179,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->js_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('js')) {
|
||||
|
||||
@@ -38,11 +38,10 @@ trait AssetUtilsTrait
|
||||
*
|
||||
* @param array $assets
|
||||
* @param bool $css
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function gatherLinks(array $assets, $css = true, &$no_pipeline = [])
|
||||
protected function gatherLinks(array $assets, $css = true)
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
@@ -74,9 +73,6 @@ trait AssetUtilsTrait
|
||||
|
||||
// No file found, skip it...
|
||||
if ($file === false) {
|
||||
if (!$local) { // Assume we couldn't download this file for some reason assume it's not pipeline compatible
|
||||
$no_pipeline[$id] = $asset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,19 +24,21 @@ trait LegacyAssetsTrait
|
||||
// First argument is always the asset
|
||||
array_shift($args);
|
||||
|
||||
if (\count($args) === 0) {
|
||||
if (count($args) === 0) {
|
||||
return [];
|
||||
}
|
||||
if (\count($args) === 1 && \is_array($args[0])) {
|
||||
// New options array format
|
||||
if (count($args) === 1 && is_array($args[0])) {
|
||||
return $args[0];
|
||||
}
|
||||
// Handle obscure case where options array is mixed with a priority
|
||||
if (count($args) === 2 && is_array($args[0]) && is_int($args[1])) {
|
||||
$arguments = $args[0];
|
||||
$arguments['priority'] = $args[1];
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case(Assets::INLINE_CSS_TYPE):
|
||||
$defaults = ['priority' => null, 'group' => null];
|
||||
$arguments = $this->createArgumentsFromLegacy($args, $defaults);
|
||||
break;
|
||||
|
||||
case(Assets::JS_TYPE):
|
||||
$defaults = ['priority' => null, 'pipeline' => true, 'loading' => null, 'group' => null];
|
||||
$arguments = $this->createArgumentsFromLegacy($args, $defaults);
|
||||
@@ -55,6 +57,11 @@ trait LegacyAssetsTrait
|
||||
|
||||
break;
|
||||
|
||||
case(Assets::INLINE_CSS_TYPE):
|
||||
$defaults = ['priority' => null, 'group' => null];
|
||||
$arguments = $this->createArgumentsFromLegacy($args, $defaults);
|
||||
break;
|
||||
|
||||
default:
|
||||
case(Assets::CSS_TYPE):
|
||||
$defaults = ['priority' => null, 'pipeline' => true, 'group' => null, 'loading' => null];
|
||||
|
||||
@@ -437,6 +437,9 @@ class Cache extends Getters
|
||||
case 'tmp-only':
|
||||
$remove_paths = self::$tmp_remove;
|
||||
break;
|
||||
case 'invalidate':
|
||||
$remove_paths = [];
|
||||
break;
|
||||
default:
|
||||
if (Grav::instance()['config']->get('system.cache.clear_images_by_default')) {
|
||||
$remove_paths = self::$standard_remove;
|
||||
|
||||
@@ -28,6 +28,15 @@ class Blueprint extends BlueprintForm
|
||||
/** @var array */
|
||||
protected $defaults;
|
||||
|
||||
protected $handlers = [];
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->blueprintSchema) {
|
||||
$this->blueprintSchema = clone $this->blueprintSchema;
|
||||
}
|
||||
}
|
||||
|
||||
public function setScope($scope)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
@@ -66,6 +75,55 @@ class Blueprint extends BlueprintForm
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize blueprints with its dynamic fields.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
foreach ($this->dynamic as $key => $data) {
|
||||
// Locate field.
|
||||
$path = explode('/', $key);
|
||||
$current = &$this->items;
|
||||
|
||||
foreach ($path as $field) {
|
||||
if (\is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = [];
|
||||
}
|
||||
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!\is_array($current)) {
|
||||
$current = [$field => []];
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = [];
|
||||
}
|
||||
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// Set dynamic property.
|
||||
foreach ($data as $property => $call) {
|
||||
$action = $call['action'];
|
||||
$method = 'dynamic' . ucfirst($action);
|
||||
|
||||
if (isset($this->handlers[$action])) {
|
||||
$callable = $this->handlers[$action];
|
||||
$callable($current, $property, $call);
|
||||
} elseif (method_exists($this, $method)) {
|
||||
$this->{$method}($current, $property, $call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two arrays by using blueprints.
|
||||
*
|
||||
@@ -165,6 +223,11 @@ class Blueprint extends BlueprintForm
|
||||
return $this->blueprintSchema;
|
||||
}
|
||||
|
||||
public function addDynamicHandler(string $name, callable $callable): void
|
||||
{
|
||||
$this->handlers[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize validator.
|
||||
*/
|
||||
|
||||
@@ -142,7 +142,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
if (!empty($rule['disabled']) || !empty($rule['validate']['ignore'])) {
|
||||
// Skip validation in the ignored field.
|
||||
continue;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
$val = $rules[$key] ?? $rules['*'] ?? null;
|
||||
$rule = \is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if (empty($rule['validate']['ignore'])) {
|
||||
if (empty($rule['disabled']) && empty($rule['validate']['ignore'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
if (!empty($rule['disabled']) || !empty($rule['validate']['ignore'])) {
|
||||
// Skip any data in the ignored field.
|
||||
unset($results[$key]);
|
||||
continue;
|
||||
@@ -240,6 +240,8 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
if (
|
||||
// Not an input field
|
||||
!$field
|
||||
// Field has been disabled
|
||||
|| !empty($field['disabled'])
|
||||
// Field validation is set to be ignored
|
||||
|| !empty($field['validate']['ignore'])
|
||||
// Field is toggleable and the toggle is turned off
|
||||
@@ -273,7 +275,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
$field = $this->items[$field];
|
||||
|
||||
// Skip ignored field, it will not be required.
|
||||
if (!empty($field['validate']['ignore'])) {
|
||||
if (!empty($field['disabled']) || !empty($field['validate']['ignore'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,10 @@ class Validation
|
||||
|
||||
protected static function filterText($value, array $params, array $field)
|
||||
{
|
||||
if (!\is_string($value) && !is_numeric($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!empty($params['trim'])) {
|
||||
$value = trim($value);
|
||||
}
|
||||
@@ -161,6 +165,11 @@ class Validation
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
protected static function filterCheckbox($value, array $params, array $field)
|
||||
{
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
protected static function filterCommaList($value, array $params, array $field)
|
||||
{
|
||||
return \is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
|
||||
@@ -567,6 +576,11 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
// If creating new values is allowed, no further checks are needed.
|
||||
if (!empty($field['selectize']['create'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$options = $field['options'] ?? [];
|
||||
$use = $field['use'] ?? 'values';
|
||||
|
||||
|
||||
@@ -12,11 +12,16 @@ namespace Grav\Common\GPM\Remote;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\GPM\Common\Package as BasePackage;
|
||||
|
||||
class Package extends BasePackage
|
||||
class Package extends BasePackage implements \JsonSerializable
|
||||
{
|
||||
public function __construct($package, $package_type = null)
|
||||
{
|
||||
$data = new Data($package);
|
||||
parent::__construct($data, $package_type);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ class Truncator {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
*/
|
||||
public function truncate(
|
||||
$text,
|
||||
|
||||
76
system/src/Grav/Common/Helpers/YamlLinter.php
Normal file
76
system/src/Grav/Common/Helpers/YamlLinter.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Helpers
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Helpers;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\File\MarkdownFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class YamlLinter
|
||||
{
|
||||
public static function lint()
|
||||
{
|
||||
$errors = static::lintConfig();
|
||||
$errors = $errors + static::lintPages();
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public static function lintPages()
|
||||
{
|
||||
return static::recurseFolder('page://');
|
||||
}
|
||||
|
||||
public static function lintConfig()
|
||||
{
|
||||
return static::recurseFolder('config://');
|
||||
}
|
||||
|
||||
public static function recurseFolder($path, $extensions = 'md|yaml')
|
||||
{
|
||||
$lint_errors = [];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
||||
if ($locator->isStream($path)) {
|
||||
$directory = $locator->getRecursiveIterator($path, $flags);
|
||||
} else {
|
||||
$directory = new \RecursiveDirectoryIterator($path, $flags);
|
||||
}
|
||||
$recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $filepath => $file) {
|
||||
try {
|
||||
Yaml::parse(static::extractYaml($filepath));
|
||||
} catch (\Exception $e) {
|
||||
$lint_errors[str_replace(GRAV_ROOT, '', $filepath)] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return $lint_errors;
|
||||
}
|
||||
|
||||
protected static function extractYaml($path)
|
||||
{
|
||||
$extension = pathinfo($path, PATHINFO_EXTENSION);
|
||||
if ($extension === 'md') {
|
||||
$file = MarkdownFile::instance($path);
|
||||
$contents = $file->frontmatter();
|
||||
} else {
|
||||
$contents = file_get_contents($path);
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,6 +104,11 @@ class Language
|
||||
public function getAvailable()
|
||||
{
|
||||
$languagesArray = $this->languages; //Make local copy
|
||||
|
||||
$languagesArray = array_map(function($value) {
|
||||
return preg_quote($value);
|
||||
}, $languagesArray);
|
||||
|
||||
sort($languagesArray);
|
||||
|
||||
return implode('|', array_reverse($languagesArray));
|
||||
|
||||
@@ -414,9 +414,7 @@ class Page implements PageInterface
|
||||
$this->markdown_extra = (bool)$this->header->markdown_extra;
|
||||
}
|
||||
if (isset($this->header->taxonomy)) {
|
||||
foreach ((array)$this->header->taxonomy as $taxonomy => $taxitems) {
|
||||
$this->taxonomy[$taxonomy] = (array)$taxitems;
|
||||
}
|
||||
$this->taxonomy($this->header->taxonomy);
|
||||
}
|
||||
if (isset($this->header->max_count)) {
|
||||
$this->max_count = (int)$this->header->max_count;
|
||||
@@ -2296,6 +2294,14 @@ class Page implements PageInterface
|
||||
public function taxonomy($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
// make sure first level are arrays
|
||||
array_walk($var, function(&$value) {
|
||||
$value = (array) $value;
|
||||
});
|
||||
// make sure all values are strings
|
||||
array_walk_recursive($var, function(&$value) {
|
||||
$value = (string) $value;
|
||||
});
|
||||
$this->taxonomy = $var;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,9 @@ class Pages
|
||||
*/
|
||||
protected $ignore_hidden;
|
||||
|
||||
/** @var string */
|
||||
protected $check_method;
|
||||
|
||||
/**
|
||||
* @var Types
|
||||
*/
|
||||
@@ -226,6 +229,11 @@ class Pages
|
||||
return $this->baseUrl($lang, $absolute) . Uri::filterPath($route);
|
||||
}
|
||||
|
||||
public function setCheckMethod($method)
|
||||
{
|
||||
$this->check_method = strtolower($method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class initialization. Must be called before using this class.
|
||||
*/
|
||||
@@ -240,6 +248,10 @@ class Pages
|
||||
$this->children = [];
|
||||
$this->routes = [];
|
||||
|
||||
if (!$this->check_method) {
|
||||
$this->setCheckMethod($config->get('system.cache.check.method', 'file'));
|
||||
}
|
||||
|
||||
$this->buildPages();
|
||||
}
|
||||
|
||||
@@ -947,7 +959,7 @@ class Pages
|
||||
$taxonomy = $this->grav['taxonomy'];
|
||||
|
||||
// how should we check for last modified? Default is by file
|
||||
switch (strtolower($config->get('system.cache.check.method', 'file'))) {
|
||||
switch ($this->check_method) {
|
||||
case 'none':
|
||||
case 'off':
|
||||
$hash = 0;
|
||||
|
||||
@@ -30,10 +30,13 @@ class RequestProcessor extends ProcessorBase
|
||||
$request = $request->withParsedBody(json_decode($request->getBody()->getContents(), true));
|
||||
}
|
||||
|
||||
$uri = $request->getUri();
|
||||
$ext = mb_strtolower(pathinfo($uri->getPath(), PATHINFO_EXTENSION));
|
||||
|
||||
$request = $request
|
||||
->withAttribute('grav', $this->container)
|
||||
->withAttribute('time', $_SERVER['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME)
|
||||
->withAttribute('route', Uri::getCurrentRoute())
|
||||
->withAttribute('route', Uri::getCurrentRoute()->withExtension($ext))
|
||||
->withAttribute('referrer', $this->container['uri']->referrer());
|
||||
|
||||
$event = new RequestHandlerEvent(['request' => $request, 'handler' => $handler]);
|
||||
|
||||
@@ -31,8 +31,8 @@ class RequestServiceProvider implements ServiceProviderInterface
|
||||
return $creator->fromGlobals();
|
||||
};
|
||||
|
||||
$container['route'] = function() {
|
||||
return Uri::getCurrentRoute();
|
||||
};
|
||||
$container['route'] = $container->factory(function() {
|
||||
return clone Uri::getCurrentRoute();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use Grav\Common\Config\Config;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Session;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
use RocketTheme\Toolbox\Session\Message;
|
||||
@@ -55,8 +56,7 @@ class SessionServiceProvider implements ServiceProviderInterface
|
||||
$current_route = str_replace(Uri::filterPath($uri->rootUrl(false)), '', parse_url($uri->url(true), PHP_URL_PATH));
|
||||
|
||||
// Check no language, simple language prefix (en) and region specific language prefix (en-US).
|
||||
$pos = strpos($current_route, $base);
|
||||
if ($pos === 0 || $pos === 3 || $pos === 6) {
|
||||
if (Utils::startsWith($current_route, $base) || Utils::pathPrefixedByLangCode($current_route)) {
|
||||
$cookie_lifetime = $config->get('plugins.admin.session.timeout', 1800);
|
||||
$enabled = $is_admin = true;
|
||||
}
|
||||
|
||||
@@ -447,7 +447,11 @@ class TwigExtension extends \Twig_Extension implements \Twig_Extension_GlobalsIn
|
||||
*/
|
||||
public function containsFilter($haystack, $needle)
|
||||
{
|
||||
return (strpos($haystack, $needle) !== false);
|
||||
if (empty($needle)) {
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
return (strpos($haystack, (string) $needle) !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,7 +144,7 @@ class Uri
|
||||
} else {
|
||||
$this->root = $this->base . $this->root_path;
|
||||
}
|
||||
$this->uri = Utils::replaceFirstOccurrence($orig_root_path, $this->root_path, $this->uri);
|
||||
$this->uri = Utils::replaceFirstOccurrence($orig_root_path, $this->root_path, $this->uri);
|
||||
} else {
|
||||
$this->root = $this->base . $this->root_path;
|
||||
}
|
||||
@@ -187,11 +187,9 @@ class Uri
|
||||
$this->extension = $parts['extension'];
|
||||
}
|
||||
|
||||
$valid_page_types = implode('|', $config->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/\.(' . $valid_page_types . ')$/', $parts['basename'])) {
|
||||
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
if ($this->isValidExtension($this->extension)) {
|
||||
$path = Utils::replaceLastOccurrence(".{$this->extension}", '', $path);
|
||||
}
|
||||
|
||||
// set the new url
|
||||
@@ -214,7 +212,7 @@ class Uri
|
||||
/**
|
||||
* Return URI path.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $id
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
@@ -230,8 +228,8 @@ class Uri
|
||||
/**
|
||||
* Return route to the current URI. By default route doesn't include base path.
|
||||
*
|
||||
* @param bool $absolute True to include full path.
|
||||
* @param bool $domain True to include domain. Works only if first parameter is also true.
|
||||
* @param bool $absolute True to include full path.
|
||||
* @param bool $domain True to include domain. Works only if first parameter is also true.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -243,8 +241,8 @@ class Uri
|
||||
/**
|
||||
* Return full query string or a single query attribute.
|
||||
*
|
||||
* @param string $id Optional attribute. Get a single query attribute if set
|
||||
* @param bool $raw If true and $id is not set, return the full query array. Otherwise return the query string
|
||||
* @param string $id Optional attribute. Get a single query attribute if set
|
||||
* @param bool $raw If true and $id is not set, return the full query array. Otherwise return the query string
|
||||
*
|
||||
* @return string|array Returns an array if $id = null and $raw = true
|
||||
*/
|
||||
@@ -268,8 +266,8 @@ class Uri
|
||||
/**
|
||||
* Return all or a single query parameter as a URI compatible string.
|
||||
*
|
||||
* @param string $id Optional parameter name.
|
||||
* @param boolean $array return the array format or not
|
||||
* @param string $id Optional parameter name.
|
||||
* @param boolean $array return the array format or not
|
||||
*
|
||||
* @return null|string|array
|
||||
*/
|
||||
@@ -301,7 +299,7 @@ class Uri
|
||||
/**
|
||||
* Get URI parameter.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $id
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
@@ -332,7 +330,7 @@ class Uri
|
||||
/**
|
||||
* Return URL.
|
||||
*
|
||||
* @param bool $include_host Include hostname.
|
||||
* @param bool $include_host Include hostname.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -523,7 +521,7 @@ class Uri
|
||||
/**
|
||||
* Return root URL to the site.
|
||||
*
|
||||
* @param bool $include_host Include hostname.
|
||||
* @param bool $include_host Include hostname.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -584,15 +582,28 @@ class Uri
|
||||
return static::buildUrl($this->toArray());
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
public function toOriginalString()
|
||||
{
|
||||
return static::buildUrl($this->toArray(true));
|
||||
}
|
||||
|
||||
public function toArray($full = false)
|
||||
{
|
||||
if ($full === true) {
|
||||
$root_path = $this->root_path ?? '';
|
||||
$extension = isset($this->extension) && $this->isValidExtension($this->extension) ? '.' . $this->extension : '';
|
||||
$path = $root_path . $this->path . $extension;
|
||||
} else {
|
||||
$path = $this->path;
|
||||
}
|
||||
|
||||
return [
|
||||
'scheme' => $this->scheme,
|
||||
'host' => $this->host,
|
||||
'port' => $this->port,
|
||||
'user' => $this->user,
|
||||
'pass' => $this->password,
|
||||
'path' => $this->path,
|
||||
'path' => $path,
|
||||
'params' => $this->params,
|
||||
'query' => $this->query,
|
||||
'fragment' => $this->fragment
|
||||
@@ -1143,7 +1154,7 @@ class Uri
|
||||
$this->scheme = $env['X-FORWARDED-PROTO'];
|
||||
} elseif (isset($env['HTTP_CLOUDFRONT_FORWARDED_PROTO'])) {
|
||||
$this->scheme = $env['HTTP_CLOUDFRONT_FORWARDED_PROTO'];
|
||||
} elseif (isset($env['REQUEST_SCHEME'])) {
|
||||
} elseif (isset($env['REQUEST_SCHEME']) && empty($env['HTTPS'])) {
|
||||
$this->scheme = $env['REQUEST_SCHEME'];
|
||||
} else {
|
||||
$https = $env['HTTPS'] ?? '';
|
||||
@@ -1326,6 +1337,38 @@ class Uri
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a valid Grav extension
|
||||
*
|
||||
* @param $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidExtension($extension)
|
||||
{
|
||||
$valid_page_types = implode('|', Grav::instance()['config']->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/(' . $valid_page_types . ')/', $extension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow overriding of any element (be careful!)
|
||||
*
|
||||
* @param $data
|
||||
* @return Uri
|
||||
*/
|
||||
public function setUriProperties($data)
|
||||
{
|
||||
foreach (get_object_vars($this) as $property => $default) {
|
||||
if (!array_key_exists($property, $data)) continue;
|
||||
$this->{$property} = $data[$property]; // assign value to object
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URI with port if needed
|
||||
*
|
||||
|
||||
@@ -118,4 +118,13 @@ class UserCollection implements UserCollectionInterface
|
||||
|
||||
return $file_path && unlink($file_path);
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
// check for existence of a user account
|
||||
$account_dir = $file_path = Grav::instance()['locator']->findResource('account://');
|
||||
$accounts = glob($account_dir . '/*.yaml') ?: [];
|
||||
|
||||
return count($accounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Grav\Common\User\Interfaces;
|
||||
|
||||
interface UserCollectionInterface
|
||||
interface UserCollectionInterface extends \Countable
|
||||
{
|
||||
/**
|
||||
* Load user account.
|
||||
|
||||
@@ -148,12 +148,13 @@ trait UserTrait
|
||||
|
||||
// Try looking for provider.
|
||||
$provider = $this->get('provider');
|
||||
if (\is_array($provider)) {
|
||||
if (isset($provider['avatar_url']) && \is_string($provider['avatar_url'])) {
|
||||
return $provider['avatar_url'];
|
||||
$provider_options = $this->get($provider);
|
||||
if (\is_array($provider_options)) {
|
||||
if (isset($provider_options['avatar_url']) && \is_string($provider_options['avatar_url'])) {
|
||||
return $provider_options['avatar_url'];
|
||||
}
|
||||
if (isset($provider['avatar']) && \is_string($provider['avatar'])) {
|
||||
return $provider['avatar'];
|
||||
if (isset($provider_options['avatar']) && \is_string($provider_options['avatar'])) {
|
||||
return $provider_options['avatar'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ abstract class Utils
|
||||
{
|
||||
protected static $nonces = [];
|
||||
|
||||
protected const ROOTURL_REGEX = '{^(\/*)}';
|
||||
protected const ROOTURL_REGEX = '{^((?:http[s]?:\/\/[^\/]+)|(?:\/\/[^\/]+))(.*)}';
|
||||
|
||||
// ^((?:http[s]?:)?[\/]?(?:\/))
|
||||
|
||||
/**
|
||||
* Simple helper method to make getting a Grav URL easier
|
||||
@@ -784,26 +786,46 @@ abstract class Utils
|
||||
*/
|
||||
public static function normalizePath($path)
|
||||
{
|
||||
// Resolve any streams
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($path)) {
|
||||
$path = $locator->findResource($path);
|
||||
}
|
||||
|
||||
// Set root properly for any URLs
|
||||
$root = '';
|
||||
preg_match(self::ROOTURL_REGEX, $path, $matches);
|
||||
if ($matches) {
|
||||
$root = $matches[0];
|
||||
$root = $matches[1];
|
||||
$path = $matches[2];
|
||||
}
|
||||
|
||||
$clean_path = static::replaceFirstOccurrence($root, '', $path);
|
||||
$segments = explode('/', trim($clean_path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
// Strip off leading / to ensure explode is accurate
|
||||
if (Utils::startsWith($path,'/')) {
|
||||
$root .= '/';
|
||||
$path = ltrim($path, '/');
|
||||
}
|
||||
$normalized = $root . implode('/', $ret);
|
||||
|
||||
// If there are any relative paths (..) handle those
|
||||
if (Utils::contains($path, '..')) {
|
||||
$segments = explode('/', trim($path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
}
|
||||
$path = implode('/', $ret);
|
||||
}
|
||||
|
||||
// Stick everything back together
|
||||
$normalized = $root . $path;
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
@@ -953,6 +975,7 @@ abstract class Utils
|
||||
* @param string $string The path
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public static function pathPrefixedByLangCode($string)
|
||||
{
|
||||
@@ -961,8 +984,13 @@ abstract class Utils
|
||||
}
|
||||
|
||||
$languages_enabled = Grav::instance()['config']->get('system.languages.supported', []);
|
||||
$parts = explode('/', trim($string, '/'));
|
||||
|
||||
return $string[0] === '/' && $string[3] === '/' && \in_array(substr($string, 1, 2), $languages_enabled, true);
|
||||
if (count($parts) > 0 && in_array($parts[0], $languages_enabled)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1319,6 +1347,8 @@ abstract class Utils
|
||||
$post_max_size = static::parseSize(ini_get('post_max_size'));
|
||||
if ($post_max_size > 0) {
|
||||
$max_size = $post_max_size;
|
||||
} else {
|
||||
$max_size = 0;
|
||||
}
|
||||
|
||||
$upload_max = static::parseSize(ini_get('upload_max_filesize'));
|
||||
@@ -1382,11 +1412,12 @@ abstract class Utils
|
||||
{
|
||||
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
|
||||
$size = preg_replace('/[^0-9\.]/', '', $size);
|
||||
|
||||
if ($unit) {
|
||||
return (int)((int)$size * (1024 ** stripos('bkmgtpezy', $unit[0])));
|
||||
$size = $size * pow(1024, stripos('bkmgtpezy', $unit[0]));
|
||||
}
|
||||
|
||||
return (int)$size;
|
||||
return (int) abs(round($size));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1447,4 +1478,44 @@ abstract class Utils
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the subnet of an ip with CIDR prefix size
|
||||
*
|
||||
* @param string $ip
|
||||
* @param int $prefix
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException if provided an invalid IP
|
||||
*/
|
||||
public static function getSubnet($ip, $prefix = 64)
|
||||
{
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException('Invalid IP: ' . $ip);
|
||||
}
|
||||
|
||||
// Packed representation of IP
|
||||
$ip = inet_pton($ip);
|
||||
|
||||
// Maximum netmask length = same as packed address
|
||||
$len = 8*strlen($ip);
|
||||
if ($prefix > $len) $prefix = $len;
|
||||
|
||||
$mask = str_repeat('f', $prefix>>2);
|
||||
|
||||
switch($prefix & 3)
|
||||
{
|
||||
case 3: $mask .= 'e'; break;
|
||||
case 2: $mask .= 'c'; break;
|
||||
case 1: $mask .= '8'; break;
|
||||
}
|
||||
$mask = str_pad($mask, $len>>2, '0');
|
||||
|
||||
// Packed representation of netmask
|
||||
$mask = pack('H*', $mask);
|
||||
// Bitwise - Take all bits that are both 1 to generate subnet
|
||||
$subnet = inet_ntop($ip & $mask);
|
||||
|
||||
return $subnet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,6 @@ class CleanCommand extends Command
|
||||
'vendor/doctrine/collections/composer.json',
|
||||
'vendor/doctrine/collections/phpunit.xml.dist',
|
||||
'vendor/doctrine/collections/tests',
|
||||
'vendor/dragonmantank/cron-expression/.editorconfig',
|
||||
'vendor/dragonmantank/cron-expression/composer.json',
|
||||
'vendor/dragonmantank/cron-expression/tests',
|
||||
'vendor/donatj/phpuseragentparser/.git',
|
||||
'vendor/donatj/phpuseragentparser/.gitignore',
|
||||
'vendor/donatj/phpuseragentparser/.editorconfig',
|
||||
@@ -83,6 +80,9 @@ class CleanCommand extends Command
|
||||
'vendor/donatj/phpuseragentparser/phpunit.xml.dist',
|
||||
'vendor/donatj/phpuseragentparser/Tests',
|
||||
'vendor/donatj/phpuseragentparser/Tools',
|
||||
'vendor/dragonmantank/cron-expression/.editorconfig',
|
||||
'vendor/dragonmantank/cron-expression/composer.json',
|
||||
'vendor/dragonmantank/cron-expression/tests',
|
||||
'vendor/erusev/parsedown/composer.json',
|
||||
'vendor/erusev/parsedown/phpunit.xml.dist',
|
||||
'vendor/erusev/parsedown/.travis.yml',
|
||||
@@ -123,6 +123,8 @@ class CleanCommand extends Command
|
||||
'vendor/gregwar/cache/Gregwar/Cache/demo',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/tests',
|
||||
'vendor/guzzlehttp/psr7/composer.json',
|
||||
'vendor/guzzlehttp/psr7/.editorconfig',
|
||||
'vendor/kodus/psr7-server/composer.json',
|
||||
'vendor/ircmaxell/password-compat/composer.json',
|
||||
'vendor/ircmaxell/password-compat/phpunit.xml.dist',
|
||||
'vendor/ircmaxell/password-compat/version-test.php',
|
||||
@@ -158,7 +160,7 @@ class CleanCommand extends Command
|
||||
'vendor/monolog/monolog/.php_cs',
|
||||
'vendor/monolog/monolog/tests',
|
||||
'vendor/nyholm/psr7/composer.json',
|
||||
'vendor/nyholm/psr7-server/composer.json',
|
||||
'vendor/nyholm/psr7/phpstan.neon.dist',
|
||||
'vendor/phive/twig-extensions-deferred/.gitignore',
|
||||
'vendor/phive/twig-extensions-deferred/.travis.yml',
|
||||
'vendor/phive/twig-extensions-deferred/composer.json',
|
||||
@@ -184,6 +186,11 @@ class CleanCommand extends Command
|
||||
'vendor/psr/simple-cache/composer.json',
|
||||
'vendor/psr/log/composer.json',
|
||||
'vendor/psr/log/.gitignore',
|
||||
'vendor/ralouphie/getallheaders/.gitignore',
|
||||
'vendor/ralouphie/getallheaders/.travis.yml',
|
||||
'vendor/ralouphie/getallheaders/composer.json',
|
||||
'vendor/ralouphie/getallheaders/phpunit.xml',
|
||||
'vendor/ralouphie/getallheaders/tests/',
|
||||
'vendor/rockettheme/toolbox/.git',
|
||||
'vendor/rockettheme/toolbox/.gitignore',
|
||||
'vendor/rockettheme/toolbox/.scrutinizer.yml',
|
||||
@@ -209,12 +216,15 @@ class CleanCommand extends Command
|
||||
'vendor/symfony/event-dispatcher/composer.json',
|
||||
'vendor/symfony/event-dispatcher/phpunit.xml.dist',
|
||||
'vendor/symfony/event-dispatcher/Tests',
|
||||
'vendor/symfony/polyfill-ctype/composer.json',
|
||||
'vendor/symfony/polyfill-iconv/.git',
|
||||
'vendor/symfony/polyfill-iconv/.gitignore',
|
||||
'vendor/symfony/polyfill-iconv/composer.json',
|
||||
'vendor/symfony/polyfill-mbstring/.git',
|
||||
'vendor/symfony/polyfill-mbstring/.gitignore',
|
||||
'vendor/symfony/polyfill-mbstring/composer.json',
|
||||
'vendor/symfony/polyfill-php72/composer.json',
|
||||
'vendor/symfony/polyfill-php73/composer.json',
|
||||
'vendor/symfony/process/.gitignore',
|
||||
'vendor/symfony/process/composer.json',
|
||||
'vendor/symfony/process/phpunit.xml.dist',
|
||||
@@ -246,6 +256,8 @@ class CleanCommand extends Command
|
||||
'vendor/willdurand/negotiation/composer.json',
|
||||
'vendor/willdurand/negotiation/phpunit.xml.dist',
|
||||
'vendor/willdurand/negotiation/tests',
|
||||
'user/config/security.yaml',
|
||||
'cache/compiled/',
|
||||
];
|
||||
|
||||
protected function configure()
|
||||
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class CacheCommand extends ConsoleCommand
|
||||
class ClearCacheCommand extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
@@ -21,6 +21,7 @@ class CacheCommand extends ConsoleCommand
|
||||
->setName('cache')
|
||||
->setAliases(['clearcache', 'cache-clear'])
|
||||
->setDescription('Clears Grav cache')
|
||||
->addOption('invalidate', null, InputOption::VALUE_NONE, 'Invalidate cache, but do not remove any files')
|
||||
->addOption('purge', null, InputOption::VALUE_NONE, 'If set purge old caches')
|
||||
->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all including compiled, twig, doctrine caches')
|
||||
->addOption('assets-only', null, InputOption::VALUE_NONE, 'If set will remove only assets/*')
|
||||
@@ -64,6 +65,8 @@ class CacheCommand extends ConsoleCommand
|
||||
$remove = 'cache-only';
|
||||
} elseif ($this->input->getOption('tmp-only')) {
|
||||
$remove = 'tmp-only';
|
||||
} elseif ($this->input->getOption('invalidate')) {
|
||||
$remove = 'invalidate';
|
||||
} else {
|
||||
$remove = 'standard';
|
||||
}
|
||||
73
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
73
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Helpers\LogViewer;
|
||||
use Grav\Common\Helpers\YamlLinter;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class YamlLinterCommand extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('yamllinter')
|
||||
->addOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com'
|
||||
)
|
||||
->setDescription('Checks various files for YAML errors')
|
||||
->setHelp("Checks various files for YAML errors");
|
||||
}
|
||||
|
||||
protected function serve()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$grav->setup();
|
||||
|
||||
$io = new SymfonyStyle($this->input, $this->output);
|
||||
|
||||
$io->title('Yaml Linter');
|
||||
|
||||
$io->section('User Configuration');
|
||||
$errors = YamlLinter::lintConfig();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with configuration');
|
||||
} else {
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
|
||||
$io->section('Pages Frontmatter');
|
||||
$errors = YamlLinter::lintPages();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with pages');
|
||||
} else {
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function displayErrors($errors, $io)
|
||||
{
|
||||
$io->error("YAML Linting issues found...");
|
||||
foreach ($errors as $path => $error) {
|
||||
$io->writeln("<yellow>$path</yellow> - $error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Console\Cli\CacheCommand;
|
||||
use Grav\Console\Cli\ClearCacheCommand;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
@@ -107,7 +107,7 @@ trait ConsoleTrait
|
||||
$all = ['--all' => true];
|
||||
}
|
||||
|
||||
$command = new CacheCommand();
|
||||
$command = new ClearCacheCommand();
|
||||
$input = new ArrayInput($all);
|
||||
return $command->run($input, $this->output);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ class InfoCommand extends ConsoleCommand
|
||||
|
||||
if ($info === 'date') {
|
||||
$name = 'Last Update';
|
||||
$data = date('D, j M Y, H:i:s, P ', strtotime('2014-09-16T00:07:16Z'));
|
||||
$data = date('D, j M Y, H:i:s, P ', strtotime($data));
|
||||
}
|
||||
|
||||
$name = str_pad($name, 12);
|
||||
|
||||
@@ -102,7 +102,7 @@ class YamlFormatter extends AbstractFormatter
|
||||
}
|
||||
|
||||
try {
|
||||
return YamlParser::parse($data);
|
||||
return (array) YamlParser::parse($data);
|
||||
} catch (ParseException $e) {
|
||||
if ($this->useCompatibleDecoder()) {
|
||||
return (array) FallbackYamlParser::parse($data);
|
||||
|
||||
@@ -91,7 +91,7 @@ class Flex implements \Countable
|
||||
// Return the directories in the given order.
|
||||
$directories = [];
|
||||
foreach ($types as $type) {
|
||||
$directories = $this->types[$type] ?? null;
|
||||
$directories[$type] = $this->types[$type] ?? null;
|
||||
}
|
||||
|
||||
return $keepMissing ? $directories : array_filter($directories);
|
||||
@@ -168,6 +168,11 @@ class Flex implements \Countable
|
||||
$keyFieldFind = 'storage_key';
|
||||
|
||||
foreach ($keys as $flexKey) {
|
||||
if (!$flexKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$flexKey = (string)$flexKey;
|
||||
// Normalize key and type using fallback to default type if it was set.
|
||||
[$key, $type, $guess] = $this->resolveKeyAndType($flexKey, $defaultType);
|
||||
|
||||
|
||||
@@ -123,6 +123,22 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
return $matching;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filters
|
||||
* @return FlexCollectionInterface
|
||||
*/
|
||||
public function filterBy(array $filters)
|
||||
{
|
||||
$expr = Criteria::expr();
|
||||
$criteria = Criteria::create();
|
||||
|
||||
foreach ($filters as $key => $value) {
|
||||
$criteria->andWhere($expr->eq($key, $value));
|
||||
}
|
||||
|
||||
return $this->matching($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexCollectionInterface::getFlexType()
|
||||
@@ -301,7 +317,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
]));
|
||||
|
||||
$output = $this->getTemplate($layout)->render(
|
||||
['grav' => $grav, 'block' => $block, 'collection' => $this, 'layout' => $layout] + $context
|
||||
['grav' => $grav, 'config' => $grav['config'], 'block' => $block, 'collection' => $this, 'layout' => $layout] + $context
|
||||
);
|
||||
|
||||
if ($debugger->enabled()) {
|
||||
@@ -474,7 +490,12 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
$twig = $grav['twig'];
|
||||
|
||||
try {
|
||||
return $twig->twig()->resolveTemplate(["flex-objects/layouts/{$this->getFlexType()}/collection/{$layout}.html.twig"]);
|
||||
return $twig->twig()->resolveTemplate(
|
||||
[
|
||||
"flex-objects/layouts/{$this->getFlexType()}/collection/{$layout}.html.twig",
|
||||
"flex-objects/layouts/_default/collection/{$layout}.html.twig"
|
||||
]
|
||||
);
|
||||
} catch (LoaderError $e) {
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
@@ -12,11 +12,15 @@ namespace Grav\Framework\Flex;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Twig\Twig;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Flex\Interfaces\FlexFormInterface;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Form\Traits\FormTrait;
|
||||
use Grav\Framework\Route\Route;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\TemplateWrapper;
|
||||
|
||||
/**
|
||||
* Class FlexForm
|
||||
@@ -45,11 +49,12 @@ class FlexForm implements FlexFormInterface
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->form = $form;
|
||||
|
||||
$uniqueId = $object->exists() ? $object->getStorageKey() : "{$object->getFlexType()}:new";
|
||||
$this->setObject($object);
|
||||
$this->setId($this->getName());
|
||||
$this->setUniqueId(md5($uniqueId));
|
||||
$this->errors = [];
|
||||
$this->messages = [];
|
||||
$this->submitted = false;
|
||||
|
||||
$flash = $this->getFlash();
|
||||
@@ -221,6 +226,42 @@ class FlexForm implements FlexFormInterface
|
||||
$this->doUnserialize($data);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
$method = "get{$name}";
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
$form = $this->getBlueprint()->form();
|
||||
|
||||
return $form[$name] ?? null;
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$method = "set{$name}";
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}($value);
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
$method = "get{$name}";
|
||||
if (method_exists($this, $method)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$form = $this->getBlueprint()->form();
|
||||
|
||||
return isset($form[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this method clones the object.
|
||||
*
|
||||
@@ -234,6 +275,29 @@ class FlexForm implements FlexFormInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $layout
|
||||
* @return TemplateWrapper
|
||||
* @throws LoaderError
|
||||
* @throws SyntaxError
|
||||
*/
|
||||
protected function getTemplate($layout)
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Twig $twig */
|
||||
$twig = $grav['twig'];
|
||||
|
||||
return $twig->twig()->resolveTemplate(
|
||||
[
|
||||
"flex-objects/layouts/{$this->getFlexType()}/form/{$layout}.html.twig",
|
||||
"flex-objects/layouts/_default/form/{$layout}.html.twig",
|
||||
"forms/{$layout}/form.html.twig",
|
||||
'forms/default/form.html.twig'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $files
|
||||
@@ -243,6 +307,7 @@ class FlexForm implements FlexFormInterface
|
||||
{
|
||||
/** @var FlexObject $object */
|
||||
$object = clone $this->getObject();
|
||||
|
||||
$object->update($data, $files);
|
||||
$object->save();
|
||||
|
||||
|
||||
@@ -98,6 +98,16 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
return $this->orderBy($orderings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexCollectionInterface::filterBy()
|
||||
*/
|
||||
public function filterBy(array $filters)
|
||||
{
|
||||
return $this->__call('filterBy', [$filters]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexCollectionInterface::getFlexType()
|
||||
@@ -386,10 +396,6 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
$cached = $result;
|
||||
}
|
||||
|
||||
if ($cached === null) {
|
||||
throw new \RuntimeException('Flex: Internal error');
|
||||
}
|
||||
|
||||
$cache->set($key, $cached);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$debugger->addException($e);
|
||||
|
||||
@@ -162,6 +162,13 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
{
|
||||
$options = $options ?? $this->getFlexDirectory()->getConfig('data.search.options', []);
|
||||
$properties = $properties ?? $this->getFlexDirectory()->getConfig('data.search.fields', []);
|
||||
if (!$properties) {
|
||||
foreach ($this->getFlexDirectory()->getConfig('admin.list.fields', []) as $property => $value) {
|
||||
if (!empty($value['link'])) {
|
||||
$properties[] = $property;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$weight = 0;
|
||||
foreach ((array)$properties as $property) {
|
||||
@@ -273,7 +280,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
return (float)$options['ends_with'];
|
||||
}
|
||||
if ((!$tested || !empty($options['contains'])) && Utils::contains($value, $search, $options['case_sensitive'] ?? false)) {
|
||||
return (float)$options['contains'];
|
||||
return (float)($options['contains'] ?? 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -416,7 +423,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
]));
|
||||
|
||||
$output = $this->getTemplate($layout)->render(
|
||||
['grav' => $grav, 'block' => $block, 'object' => $this, 'layout' => $layout] + $context
|
||||
['grav' => $grav, 'config' => $grav['config'], 'block' => $block, 'object' => $this, 'layout' => $layout] + $context
|
||||
);
|
||||
|
||||
if ($debugger->enabled()) {
|
||||
@@ -730,8 +737,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
|
||||
$grav = Grav::instance();
|
||||
/** @var Flex $flex */
|
||||
$flex = $grav['flex_directory'];
|
||||
$directory = $flex->getDirectory($type);
|
||||
$flex = $grav['flex_objects'] ?? null;
|
||||
$directory = $flex ? $flex->getDirectory($type) : null;
|
||||
if (!$directory) {
|
||||
throw new \InvalidArgumentException("Cannot unserialize '{$type}': Not found");
|
||||
}
|
||||
@@ -812,7 +819,12 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
$twig = $grav['twig'];
|
||||
|
||||
try {
|
||||
return $twig->twig()->resolveTemplate(["flex-objects/layouts/{$this->getFlexType()}/object/{$layout}.html.twig"]);
|
||||
return $twig->twig()->resolveTemplate(
|
||||
[
|
||||
"flex-objects/layouts/{$this->getFlexType()}/object/{$layout}.html.twig",
|
||||
"flex-objects/layouts/_default/object/{$layout}.html.twig"
|
||||
]
|
||||
);
|
||||
} catch (LoaderError $e) {
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
@@ -70,6 +70,14 @@ interface FlexCollectionInterface extends FlexCommonInterface, ObjectCollectionI
|
||||
*/
|
||||
public function sort(array $orderings);
|
||||
|
||||
/**
|
||||
* Filter collection by filter array with keys and values.
|
||||
*
|
||||
* @param array $filters
|
||||
* @return FlexCollectionInterface
|
||||
*/
|
||||
public function filterBy(array $filters);
|
||||
|
||||
/**
|
||||
* Get timestamps from all the objects in the collection.
|
||||
*
|
||||
|
||||
@@ -71,7 +71,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && file_exists($this->getPathFromKey($key));
|
||||
return $key && strpos($key, '@@') === false && file_exists($this->getPathFromKey($key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,11 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && isset($this->data[$key]);
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
return $key && strpos($key, '@@') === false && isset($this->data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +84,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function createRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = $this->getNewKey();
|
||||
@@ -99,6 +107,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function readRows(array $rows, array &$fetched = null): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
if (null === $row || (!\is_object($row) && !\is_array($row))) {
|
||||
@@ -123,6 +135,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function updateRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
@@ -144,6 +160,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function deleteRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
@@ -166,8 +186,15 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function replaceRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
if (strpos($key, '@@')) {
|
||||
$key = $this->getNewKey();
|
||||
}
|
||||
$this->data[$key] = $list[$key] = $row;
|
||||
}
|
||||
|
||||
@@ -184,6 +211,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function renameRow(string $src, string $dst): bool
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
if ($this->hasKey($dst)) {
|
||||
throw new \RuntimeException("Cannot rename object: key '{$dst}' is already taken");
|
||||
}
|
||||
@@ -221,6 +252,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
|
||||
protected function save() : void
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $this->getFile($this->getStoragePath());
|
||||
$file->save($this->data);
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Grav\Framework\Flex\Traits;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\User\Interfaces\UserInterface;
|
||||
use Grav\Framework\Flex\FlexDirectory;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
|
||||
/**
|
||||
@@ -44,7 +45,11 @@ trait FlexAuthorizeTrait
|
||||
$action = $this->exists() ? 'update' : 'create';
|
||||
}
|
||||
|
||||
return $user->authorize(sprintf($this->_authorize, $scope, $action));
|
||||
$directory = $this instanceof FlexDirectory ? $this : $this->getFlexDirectory();
|
||||
$config = $directory->getConfig();
|
||||
$allowed = $config->get("{$scope}.actions.{$action}") ?? $config->get("actions.{$action}") ?? true;
|
||||
|
||||
return $allowed && $user->authorize(sprintf($this->_authorize, $scope, $action));
|
||||
}
|
||||
|
||||
protected function setAuthorizeRule(string $authorize) : void
|
||||
|
||||
@@ -229,7 +229,6 @@ trait FlexMediaTrait
|
||||
}
|
||||
|
||||
// Remove Extra Files
|
||||
|
||||
foreach (scandir($targetPath, SCANDIR_SORT_NONE) as $file) {
|
||||
$preg_name = preg_quote($fileParts['filename'], '`');
|
||||
$preg_ext =preg_quote($fileParts['extension'], '`');
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Grav\Framework\Form\Interfaces;
|
||||
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Framework\Interfaces\RenderInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
@@ -18,7 +19,7 @@ use Psr\Http\Message\UploadedFileInterface;
|
||||
* Interface FormInterface
|
||||
* @package Grav\Framework\Form
|
||||
*/
|
||||
interface FormInterface extends \Serializable
|
||||
interface FormInterface extends RenderInterface, \Serializable
|
||||
{
|
||||
/**
|
||||
* Get HTML id="..." attribute.
|
||||
@@ -83,6 +84,13 @@ interface FormInterface extends \Serializable
|
||||
*/
|
||||
public function getNonce(): string;
|
||||
|
||||
/**
|
||||
* Get task for the form if set in blueprints.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTask(): string;
|
||||
|
||||
/**
|
||||
* Get form action (URL). If action is empty, it points to the current page.
|
||||
*
|
||||
@@ -132,6 +140,11 @@ interface FormInterface extends \Serializable
|
||||
*/
|
||||
public function isValid(): bool;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): ?string;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -14,11 +14,15 @@ use Grav\Common\Data\Data;
|
||||
use Grav\Common\Data\ValidationException;
|
||||
use Grav\Common\Form\FormFlash;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Twig\Twig;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\ContentBlock\HtmlBlock;
|
||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
||||
use Grav\Framework\Session\Session;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\TemplateWrapper;
|
||||
|
||||
/**
|
||||
* Trait FormTrait
|
||||
@@ -26,6 +30,13 @@ use Psr\Http\Message\UploadedFileInterface;
|
||||
*/
|
||||
trait FormTrait
|
||||
{
|
||||
/** @var string */
|
||||
public $status = 'success';
|
||||
/** @var string */
|
||||
public $message;
|
||||
/** @var string[] */
|
||||
public $messages = [];
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
/** @var string */
|
||||
@@ -34,8 +45,6 @@ trait FormTrait
|
||||
private $uniqueid;
|
||||
/** @var bool */
|
||||
private $submitted;
|
||||
/** @var string[] */
|
||||
private $errors;
|
||||
/** @var Data|object|null */
|
||||
private $data;
|
||||
/** @var array|UploadedFileInterface[] */
|
||||
@@ -95,6 +104,11 @@ trait FormTrait
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getTask(): string
|
||||
{
|
||||
return $this->getBlueprint()->get('form/task') ?? '';
|
||||
}
|
||||
|
||||
public function getData(string $name = null)
|
||||
{
|
||||
return null !== $name ? $this->data[$name] : $this->data;
|
||||
@@ -155,12 +169,24 @@ trait FormTrait
|
||||
*/
|
||||
public function handleRequest(ServerRequestInterface $request): FormInterface
|
||||
{
|
||||
// Set current form to be active.
|
||||
$grav = Grav::instance();
|
||||
$forms = $grav['forms'] ?? null;
|
||||
if ($forms) {
|
||||
$forms->setActiveForm($this);
|
||||
|
||||
/** @var Twig $twig */
|
||||
$twig = $grav['twig'];
|
||||
$twig->twig_vars['form'] = $this;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
[$data, $files] = $this->parseRequest($request);
|
||||
|
||||
$this->submit($data, $files);
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -182,12 +208,17 @@ trait FormTrait
|
||||
|
||||
public function isValid(): bool
|
||||
{
|
||||
return !$this->errors;
|
||||
return $this->status === 'success';
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return !$this->isValid() ? $this->message : null;
|
||||
}
|
||||
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
return !$this->isValid() ? $this->messages : [];
|
||||
}
|
||||
|
||||
public function isSubmitted(): bool
|
||||
@@ -197,7 +228,7 @@ trait FormTrait
|
||||
|
||||
public function validate(): bool
|
||||
{
|
||||
if ($this->errors) {
|
||||
if (!$this->isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,19 +236,14 @@ trait FormTrait
|
||||
$this->validateData($this->data);
|
||||
$this->validateUploads($this->getFiles());
|
||||
} catch (ValidationException $e) {
|
||||
$list = [];
|
||||
foreach ($e->getMessages() as $field => $errors) {
|
||||
$list[] = $errors;
|
||||
}
|
||||
$list = array_merge(...$list);
|
||||
$this->errors = $list;
|
||||
$this->setErrors($e->getMessages());
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
$this->filterData($this->data);
|
||||
|
||||
return empty($this->errors);
|
||||
return $this->isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +269,7 @@ trait FormTrait
|
||||
|
||||
$this->submitted = true;
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -256,7 +282,9 @@ trait FormTrait
|
||||
|
||||
$this->data = null;
|
||||
$this->files = [];
|
||||
$this->errors = [];
|
||||
$this->status = 'success';
|
||||
$this->message = null;
|
||||
$this->messages = [];
|
||||
$this->submitted = false;
|
||||
$this->flash = null;
|
||||
}
|
||||
@@ -301,7 +329,6 @@ trait FormTrait
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* Get form flash object.
|
||||
*
|
||||
* @return FormFlash
|
||||
@@ -309,44 +336,64 @@ trait FormTrait
|
||||
public function getFlash(): FormFlash
|
||||
{
|
||||
if (null === $this->flash) {
|
||||
/** @var Grav $grav */
|
||||
$grav = Grav::instance();
|
||||
$user = $grav['user'];
|
||||
$id = null;
|
||||
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
$user = $grav['user'] ?? null;
|
||||
if (isset($user)) {
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
}
|
||||
}
|
||||
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
/** @var Session $session */
|
||||
$session = $grav['session'];
|
||||
$id = $session->getId();
|
||||
}
|
||||
// Session Required for flash form
|
||||
$session = $grav['session'] ?? null;
|
||||
if (isset($session)) {
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
$id = $session->getId();
|
||||
}
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->flash;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FormInterface::render()
|
||||
*/
|
||||
public function render(string $layout = null, array $context = [])
|
||||
{
|
||||
if (null === $layout) {
|
||||
$layout = 'default';
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
$block = HtmlBlock::create();
|
||||
$block->disableCache();
|
||||
|
||||
$output = $this->getTemplate($layout)->render(
|
||||
['grav' => $grav, 'config' => $grav['config'], 'block' => $block, 'form' => $this, 'layout' => $layout] + $context
|
||||
);
|
||||
|
||||
$block->setContent($output);
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
protected function unsetFlash(): void
|
||||
{
|
||||
$this->flash = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all errors.
|
||||
*
|
||||
* @param array $errors
|
||||
*/
|
||||
protected function setErrors(array $errors): void
|
||||
{
|
||||
$this->errors = array_merge($this->errors, $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single error.
|
||||
*
|
||||
@@ -354,7 +401,40 @@ trait FormTrait
|
||||
*/
|
||||
protected function setError(string $error): void
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
$this->status = 'error';
|
||||
$this->message = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all errors.
|
||||
*
|
||||
* @param array $errors
|
||||
*/
|
||||
protected function setErrors(array $errors): void
|
||||
{
|
||||
$this->status = 'error';
|
||||
$this->messages = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $layout
|
||||
* @return TemplateWrapper
|
||||
* @throws LoaderError
|
||||
* @throws SyntaxError
|
||||
*/
|
||||
protected function getTemplate($layout)
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Twig $twig */
|
||||
$twig = $grav['twig'];
|
||||
|
||||
return $twig->twig()->resolveTemplate(
|
||||
[
|
||||
"forms/{$layout}/form.html.twig",
|
||||
'forms/default/form.html.twig'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,7 +583,7 @@ trait FormTrait
|
||||
$value = json_decode($value, true);
|
||||
if ($value === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
unset($data[$key]);
|
||||
$this->errors[] = "Badly encoded JSON data (for {$key}) was sent to the form";
|
||||
$this->setError("Badly encoded JSON data (for {$key}) was sent to the form");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -523,7 +603,9 @@ trait FormTrait
|
||||
'id' => $this->id,
|
||||
'uniqueid' => $this->uniqueid,
|
||||
'submitted' => $this->submitted,
|
||||
'errors' => $this->errors,
|
||||
'status' => $this->status,
|
||||
'message' => $this->message,
|
||||
'messages' => $this->messages,
|
||||
'data' => $data,
|
||||
'files' => $this->files,
|
||||
];
|
||||
@@ -538,7 +620,9 @@ trait FormTrait
|
||||
$this->id = $data['id'];
|
||||
$this->uniqueid = $data['uniqueid'];
|
||||
$this->submitted = $data['submitted'] ?? false;
|
||||
$this->errors = $data['errors'] ?? [];
|
||||
$this->status = $data['status'] ?? 'success';
|
||||
$this->message = $data['message'] ?? null;
|
||||
$this->messages = $data['messages'] ?? [];
|
||||
$this->data = isset($data['data']) ? new Data($data['data'], $this->getBlueprint()) : null;
|
||||
$this->files = $data['files'] ?? [];
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ trait NestedPropertyTrait
|
||||
$current[$offset] = [];
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot set nested property on non-array value');
|
||||
throw new \RuntimeException("Cannot set nested property {$property} on non-array value");
|
||||
}
|
||||
|
||||
$current = &$current[$offset];
|
||||
@@ -147,7 +147,7 @@ trait NestedPropertyTrait
|
||||
return $this;
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot set nested property on non-array value');
|
||||
throw new \RuntimeException("Cannot unset nested property {$property} on non-array value");
|
||||
}
|
||||
|
||||
$current = &$current[$offset];
|
||||
|
||||
@@ -193,6 +193,7 @@ class Route
|
||||
public function withRoute($route)
|
||||
{
|
||||
$this->route = $route;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -205,6 +206,7 @@ class Route
|
||||
public function withRoot($root)
|
||||
{
|
||||
$this->root = $root;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -250,6 +252,25 @@ class Route
|
||||
return $this->withParam('queryParams', $param, $value);
|
||||
}
|
||||
|
||||
public function withoutParams()
|
||||
{
|
||||
return $this->withoutGravParams()->withoutQueryParams();
|
||||
}
|
||||
|
||||
public function withoutGravParams()
|
||||
{
|
||||
$this->gravParams = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withoutQueryParams()
|
||||
{
|
||||
$this->queryParams = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Grav\Framework\Uri\Uri
|
||||
*/
|
||||
@@ -298,7 +319,7 @@ class Route
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new = $this->copy();
|
||||
if ($value === null) {
|
||||
unset($new->{$type}[$param]);
|
||||
} else {
|
||||
@@ -308,6 +329,11 @@ class Route
|
||||
return $new;
|
||||
}
|
||||
|
||||
protected function copy()
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeRoot
|
||||
* @return string
|
||||
|
||||
@@ -302,7 +302,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'https://api.getgrav.com:4040',
|
||||
'extension' => null,
|
||||
'addNonce' => 'https://username:password@api.getgrav.com:4040/v1/post/128/page:x/nonce:{{nonce}}?all=1',
|
||||
'__toString' => 'https://username:password@api.getgrav.com:4040/v1/post/128/page:x?all=1'
|
||||
'toOriginalString' => 'https://username:password@api.getgrav.com:4040/v1/post/128/page:x?all=1'
|
||||
],
|
||||
'https://google.com:443/' => [
|
||||
'scheme' => 'https://',
|
||||
@@ -392,7 +392,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://localhost/this%20is%20the%20path/my%20page/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/this%20is%20the%20path/my%20page'
|
||||
'toOriginalString' => 'http://localhost/this%20is%20the%20path/my%20page'
|
||||
],
|
||||
'http://localhost/pölöpölö/päläpälä' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -415,7 +415,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4'
|
||||
'toOriginalString' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4'
|
||||
],
|
||||
// Query params tests.
|
||||
'http://localhost:8080/grav/it/ueper?test=x&test2=y' => [
|
||||
@@ -573,7 +573,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'html',
|
||||
'addNonce' => 'http://localhost/a-page.html/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIXME <-
|
||||
'toOriginalString' => 'http://localhost/a-page.html',
|
||||
],
|
||||
'http://localhost/a-page.json' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -596,7 +596,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/a-page.json/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIX ME <-
|
||||
'toOriginalString' => 'http://localhost/a-page.json',
|
||||
],
|
||||
'http://localhost/admin/ajax.json/task:getnewsfeed' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -619,7 +619,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/admin/ajax.json/task:getnewsfeed/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/admin/ajax/task:getnewsfeed',
|
||||
'toOriginalString' => 'http://localhost/admin/ajax.json/task:getnewsfeed',
|
||||
],
|
||||
'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -642,7 +642,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/grav/admin/media/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', // FIXME <-
|
||||
'toOriginalString' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==',
|
||||
],
|
||||
'http://localhost/a-page.foo' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -665,7 +665,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'foo',
|
||||
'addNonce' => 'http://localhost/a-page.foo/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page.foo'
|
||||
'toOriginalString' => 'http://localhost/a-page.foo'
|
||||
],
|
||||
// Fragment tests.
|
||||
'http://localhost:8080/a/b/c#my-fragment' => [
|
||||
@@ -712,7 +712,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => '',
|
||||
'extension' => null,
|
||||
//'addNonce' => '%22%3E%3Cscript%3Ealert%3C/localhost/script%3E:/nonce:{{nonce}}', // FIXME <-
|
||||
'__toString' => '%22%3E%3Cscript%3Ealert%3C/localhost/script%3E:' // FIXME <-
|
||||
'toOriginalString' => '%22%3E%3Cscript%3Ealert%3C/localhost/script%3E:' // FIXME <-
|
||||
],
|
||||
'http://"><script>alert</script>' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -735,7 +735,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://unknown',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://unknown/script%3E/nonce:{{nonce}}',
|
||||
'__toString' => 'http://unknown/script%3E'
|
||||
'toOriginalString' => 'http://unknown/script%3E'
|
||||
],
|
||||
'http://localhost/"><script>alert</script>' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -758,7 +758,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://localhost/%22%3E%3Cscript%3Ealert%3C/script%3E/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
'toOriginalString' => 'http://localhost/%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
],
|
||||
'http://localhost/something/p1:foo/p2:"><script>alert</script>' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -781,7 +781,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
//'addNonce' => 'http://localhost/something/script%3E/p1:foo/p2:%22%3E%3Cscript%3Ealert%3C/nonce:{{nonce}}', // FIXME <-
|
||||
'__toString' => 'http://localhost/something/script%3E/p1:foo/p2:%22%3E%3Cscript%3Ealert%3C'
|
||||
'toOriginalString' => 'http://localhost/something/script%3E/p1:foo/p2:%22%3E%3Cscript%3Ealert%3C'
|
||||
],
|
||||
'http://localhost/something?p="><script>alert</script>' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -804,7 +804,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://localhost/something/nonce:{{nonce}}?p=%22%3E%3Cscript%3Ealert%3C/script%3E',
|
||||
'__toString' => 'http://localhost/something?p=%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
'toOriginalString' => 'http://localhost/something?p=%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
],
|
||||
'http://localhost/something#"><script>alert</script>' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -827,7 +827,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => null,
|
||||
'addNonce' => 'http://localhost/something/nonce:{{nonce}}#%22%3E%3Cscript%3Ealert%3C/script%3E',
|
||||
'__toString' => 'http://localhost/something#%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
'toOriginalString' => 'http://localhost/something#%22%3E%3Cscript%3Ealert%3C/script%3E'
|
||||
],
|
||||
'https://www.getgrav.org/something/"><script>eval(atob("aGlzdG9yeS5wdXNoU3RhdGUoJycsJycsJy8nKTskKCdoZWFkLGJvZHknKS5odG1sKCcnKS5sb2FkKCcvJyk7JC5wb3N0KCcvYWRtaW4nLGZ1bmN0aW9uKGRhdGEpeyQucG9zdCgkKGRhdGEpLmZpbmQoJ1tpZD1hZG1pbi11c2VyLWRldGFpbHNdIGEnKS5hdHRyKCdocmVmJykseydhZG1pbi1ub25jZSc6JChkYXRhKS5maW5kKCdbZGF0YS1jbGVhci1jYWNoZV0nKS5hdHRyKCdkYXRhLWNsZWFyLWNhY2hlJykuc3BsaXQoJzonKS5wb3AoKS50cmltKCksJ2RhdGFbcGFzc3dvcmRdJzonSW0zdjFsaDR4eDByJywndGFzayc6J3NhdmUnfSl9KQ=="))</script><' => [
|
||||
'scheme' => 'https://',
|
||||
@@ -850,7 +850,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'https://www.getgrav.org',
|
||||
'extension' => null,
|
||||
'addNonce' => 'https://www.getgrav.org/something/%22%3E%3Cscript%3Eeval%28atob%28%22aGlzdG9yeS5wdXNoU3RhdGUoJycsJycsJy8nKTskKCdoZWFkLGJvZHknKS5odG1sKCcnKS5sb2FkKCcvJyk7JC5wb3N0KCcvYWRtaW4nLGZ1bmN0aW9uKGRhdGEpeyQucG9zdCgkKGRhdGEpLmZpbmQoJ1tpZD1hZG1pbi11c2VyLWRldGFpbHNdIGEnKS5hdHRyKCdocmVmJykseydhZG1pbi1ub25jZSc6JChkYXRhKS5maW5kKCdbZGF0YS1jbGVhci1jYWNoZV0nKS5hdHRyKCdkYXRhLWNsZWFyLWNhY2hlJykuc3BsaXQoJzonKS5wb3AoKS50cmltKCksJ2RhdGFbcGFzc3dvcmRdJzonSW0zdjFsaDR4eDByJywndGFzayc6J3NhdmUnfSl9KQ==%22%29%29%3C/script%3E%3C/nonce:{{nonce}}',
|
||||
'__toString' => 'https://www.getgrav.org/something/%22%3E%3Cscript%3Eeval%28atob%28%22aGlzdG9yeS5wdXNoU3RhdGUoJycsJycsJy8nKTskKCdoZWFkLGJvZHknKS5odG1sKCcnKS5sb2FkKCcvJyk7JC5wb3N0KCcvYWRtaW4nLGZ1bmN0aW9uKGRhdGEpeyQucG9zdCgkKGRhdGEpLmZpbmQoJ1tpZD1hZG1pbi11c2VyLWRldGFpbHNdIGEnKS5hdHRyKCdocmVmJykseydhZG1pbi1ub25jZSc6JChkYXRhKS5maW5kKCdbZGF0YS1jbGVhci1jYWNoZV0nKS5hdHRyKCdkYXRhLWNsZWFyLWNhY2hlJykuc3BsaXQoJzonKS5wb3AoKS50cmltKCksJ2RhdGFbcGFzc3dvcmRdJzonSW0zdjFsaDR4eDByJywndGFzayc6J3NhdmUnfSl9KQ==%22%29%29%3C/script%3E%3C'
|
||||
'toOriginalString' => 'https://www.getgrav.org/something/%22%3E%3Cscript%3Eeval%28atob%28%22aGlzdG9yeS5wdXNoU3RhdGUoJycsJycsJy8nKTskKCdoZWFkLGJvZHknKS5odG1sKCcnKS5sb2FkKCcvJyk7JC5wb3N0KCcvYWRtaW4nLGZ1bmN0aW9uKGRhdGEpeyQucG9zdCgkKGRhdGEpLmZpbmQoJ1tpZD1hZG1pbi11c2VyLWRldGFpbHNdIGEnKS5hdHRyKCdocmVmJykseydhZG1pbi1ub25jZSc6JChkYXRhKS5maW5kKCdbZGF0YS1jbGVhci1jYWNoZV0nKS5hdHRyKCdkYXRhLWNsZWFyLWNhY2hlJykuc3BsaXQoJzonKS5wb3AoKS50cmltKCksJ2RhdGFbcGFzc3dvcmRdJzonSW0zdjFsaDR4eDByJywndGFzayc6J3NhdmUnfSl9KQ==%22%29%29%3C/script%3E%3C'
|
||||
],
|
||||
];
|
||||
|
||||
@@ -868,7 +868,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
protected function runTestSet(array $tests, $method, $params = [])
|
||||
{
|
||||
foreach ($tests as $url => $candidates) {
|
||||
if (!array_key_exists($method, $candidates) && $method !== '__toString') {
|
||||
if (!array_key_exists($method, $candidates) && $method !== 'toOriginalString') {
|
||||
continue;
|
||||
}
|
||||
if ($method === 'addNonce') {
|
||||
@@ -881,7 +881,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
}
|
||||
|
||||
$this->uri->initializeWithURL($url)->init();
|
||||
if ($method === '__toString' && !isset($candidates[$method])) {
|
||||
if ($method === 'toOriginalString' && !isset($candidates[$method])) {
|
||||
$expected = $url;
|
||||
} else {
|
||||
$expected = $candidates[$method];
|
||||
@@ -921,7 +921,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
|
||||
public function testToString()
|
||||
{
|
||||
$this->runTestSet($this->tests, '__toString');
|
||||
$this->runTestSet($this->tests, 'toOriginalString');
|
||||
}
|
||||
|
||||
public function testScheme()
|
||||
@@ -1121,6 +1121,24 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
];
|
||||
|
||||
$this->assertSame('http://foo:bar@localhost:8080/test?x=2#xxx', Uri::buildUrl($parsed_url));
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray(true)));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.foo', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.foo', Uri::buildUrl($uri->toArray(true)));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir/path1')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray(true)));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', Uri::buildUrl($uri->toArray(true)));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', Uri::buildUrl($uri->toArray(true)));
|
||||
}
|
||||
|
||||
public function testConvertUrl()
|
||||
|
||||
@@ -224,10 +224,19 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
$this->assertEquals('test', Utils::normalizePath('../test'));
|
||||
$this->assertEquals('/test', Utils::normalizePath('/../test'));
|
||||
$this->assertEquals('/test2', Utils::normalizePath('/test/../test2'));
|
||||
$this->assertEquals('/test/test2', Utils::normalizePath('/test/./test2'));
|
||||
$this->assertEquals('//something/test/test2', Utils::normalizePath('//../something/test/test2'));
|
||||
$this->assertEquals('//something/test2', Utils::normalizePath('//something/test/../test2'));
|
||||
$this->assertEquals('//test2', Utils::normalizePath('//something/../test/../test2'));
|
||||
$this->assertEquals('/test3', Utils::normalizePath('/test/../test2/../test3'));
|
||||
|
||||
$this->assertEquals('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
}
|
||||
|
||||
public function testIsFunctionDisabled()
|
||||
|
||||
@@ -26,7 +26,7 @@ To edit this page, simply navigate to the folder you installed **Grav** into, an
|
||||
|
||||
Creating a new page is a simple affair in **Grav**. Simply follow these simple steps:
|
||||
|
||||
1. Navigate to your pages folder: `user/pages/` and create a new folder. In this example, we will use [explicit default ordering](http://learn.getgrav.org/content/content-pages) and call the folder `02.mypage`.
|
||||
1. Navigate to your pages folder: `user/pages/` and create a new folder. In this example, we will use [explicit default ordering](http://learn.getgrav.org/content/content-pages) and call the folder `03.mypage`.
|
||||
2. Launch your text editor and paste in the following sample code:
|
||||
|
||||
---
|
||||
@@ -36,7 +36,7 @@ Creating a new page is a simple affair in **Grav**. Simply follow these simple
|
||||
|
||||
This is the body of **my new page** and I can easily use _Markdown_ syntax here.
|
||||
|
||||
3. Save this file in the `user/pages/02.mypage/` folder as `default.md`. This will tell **Grav** to render the page using the **default** template.
|
||||
3. Save this file in the `user/pages/03.mypage/` folder as `default.md`. This will tell **Grav** to render the page using the **default** template.
|
||||
4. That is it! Reload your browser to see your new page in the menu.
|
||||
|
||||
! NOTE: The page will automatically show up in the Menu after the "Home" menu item. If you wish to change the name that shows up in the Menu, simple add: `menu: My Page` between the dashes in the page content. This is called the YAML front matter, and it is where you configure page-specific options.
|
||||
! NOTE: The page will automatically show up in the Menu after the "Typography" menu item. If you wish to change the name that shows up in the Menu, simple add: `menu: My Page` between the dashes in the page content. This is called the YAML front matter, and it is where you configure page-specific options.
|
||||
|
||||
Reference in New Issue
Block a user