Compare commits

...

49 Commits
1.3.8 ... 1.3.9

Author SHA1 Message Date
Andy Miller
d4204f13f8 Merge branch 'release/1.3.9' 2017-12-05 17:16:13 -07:00
Andy Miller
0554b25c78 Prepare for release 2017-12-05 17:16:05 -07:00
Andy Miller
f4e7cbaa6e updated changelog 2017-12-05 17:15:28 -07:00
Andy Miller
83bfc1fd0f Added support for intl_enabled option 2017-12-05 17:03:05 -07:00
Andy Miller
30439b864d Added a quick type test for #1764 2017-12-05 11:04:59 -07:00
Andy Miller
80999121a9 Potential fix for #1764 2017-12-05 10:51:44 -07:00
Andy Miller
ca0d0bb373 Added a comment 2017-12-05 10:50:39 -07:00
Andy Miller
345578a05d Force field.multiple: true for checkboxes to use min/max rules 2017-12-04 22:32:26 -07:00
Andy Miller
1f0537124a Merge branch 'develop' of https://github.com/getgrav/grav into develop 2017-12-04 18:14:25 -07:00
Andy Miller
2a2b9a12a7 Fix for checkbox validation form#216 2017-12-04 18:14:20 -07:00
Iain Gillis
5a19e05931 Fix typo (#1770) 2017-12-02 22:08:55 -07:00
Andy Miller
6ae4680fcb Move system twig templates to last 2017-12-01 11:38:38 -07:00
Andy Miller
b4cf7899bb cleanup 2017-12-01 00:01:23 -07:00
Andy Miller
eac16911d0 Added new core twig templates 2017-11-30 18:31:13 -07:00
Andy Miller
21bef62b82 Added get and set FlashCookieObject() methods 2017-11-30 18:28:25 -07:00
Andy Miller
a1eccfdb61 Updated changelog 2017-11-28 12:58:04 -07:00
Matias Griese
90e05694d3 Merge remote-tracking branch 'origin/develop' into develop 2017-11-28 14:58:07 +02:00
Matias Griese
b97ac503a1 Add filter for item-list type (removes empty items from the list) 2017-11-28 14:57:53 +02:00
Agustin Villalba
2cc34151df Fixed issue #1742 where the creation of GPM object tried to connect to Remote repositories even if only Local package was needed (#1746)
All good, thanks!
2017-11-27 21:15:09 -07:00
Iain Gillis
4c160533c2 Add additional controls to HTML5 audio attributes (#1756)
Adds support for `autoplay`, `controls`, `loop`, and `preload` attributes, with rudimentary validation for preload.

Those for `autoplay`, `controls`, and `loop` are copied directly from pfcloutier-druide/aaa3f82

See also #1442.
2017-11-27 21:12:56 -07:00
Matias Griese
59dd0d1212 Fixed CSS Pipeline failing with Google remote fonts if the file was minified (#1261) (#1763)
* Fixed CSS Pipeline failing with Google remote fonts if the file was minified (#1261)

* Assets: Make tag check ungreedy again -- inline js may have tags in the content
2017-11-27 21:12:33 -07:00
Andy Miller
3bf7e38e52 Updated changelog 2017-11-27 18:30:10 -07:00
Andy Miller
362ee4c9eb Fix for URL encoding with Multibyte folders 2017-11-27 18:27:18 -07:00
Andy Miller
2462331884 Fix for MB Markdown links #1749 2017-11-27 18:21:08 -07:00
Matias Griese
cb4147a4bd Fixed token creation issue with Uri params like /id:3 2017-11-17 08:03:58 +02:00
Wensheng Yan
72f3a01abf Update Cache.php (#1745)
make sure find resource return valid path.
2017-11-15 18:35:44 -07:00
Matias Griese
31e3c1c295 Remove support for config.user, it was broken and bad practise 2017-11-10 22:07:29 +02:00
Andy Miller
37891a1032 Minor optimizations 2017-11-08 05:34:42 -07:00
Andy Miller
70284e1517 Sort using folder name #1740 2017-11-07 18:38:35 -07:00
Andy Miller
0bca1dcb48 Fix for custom_base_url issues #1736 2017-11-07 17:50:06 -07:00
Andy Miller
36f9865c0b Couple of utility functions 2017-11-07 17:44:40 -07:00
Matias Griese
cd48551630 Fix changelog 2017-11-07 17:00:34 +02:00
Matias Griese
0ff130650f Merge remote-tracking branch 'origin/develop' into develop 2017-11-07 16:57:59 +02:00
Matias Griese
9b445ac5b6 Fixed "Invalid AJAX response" When using Built-in PHP Webserver in Windows (#1258) 2017-11-07 16:57:52 +02:00
Andy Miller
c21248fcc2 Updated changelog 2017-11-06 19:52:05 -07:00
Andy Miller
88aa4c5ec9 Added ability to toggle lowercase urls 2017-11-06 19:50:59 -07:00
Matias Griese
0fd22ad933 Uri: Encode user and password to prevent issues in browsers 2017-11-06 10:26:17 +02:00
Andy Miller
00b56da220 Updated changelog 2017-11-02 14:51:13 -06:00
Andy Miller
fef6bdde5f Revert "Added system option to enable case insensitive urls. (#1638)"
This reverts commit 481fe1903e.
2017-11-02 14:48:42 -06:00
Sam
6f7938e939 Update README.md (#1705) 2017-11-01 17:21:14 -06:00
Viktor
2cd469cd7c Update CompiledFile.php (#1693)
const CACHE_DIR already defined with trailing slash

```php
define('CACHE_DIR', ROOT_DIR . 'cache/');
```
2017-11-01 17:20:38 -06:00
Andy Miller
0895b15489 Updated changelog 2017-10-31 16:38:16 -06:00
Andy Miller
d9062b60d6 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2017-10-31 16:36:47 -06:00
Andy Miller
3f4049031d use Event object in Page/Pages events 2017-10-31 16:36:43 -06:00
Andy Miller
c81ce71074 Fix active() + activeChild() to work with UTF-8 #1727 2017-10-31 16:36:13 -06:00
cofunin
f84ffd235b Fix ignoring media in modular.yaml (#1725) 2017-10-30 18:15:39 -06:00
Andy Miller
1ca6181856 Added onPageProcessed for dynamic addPage() calls 2017-10-30 16:19:13 -06:00
Andy Miller
f17954a5db Added a copy method to Medium object 2017-10-30 15:36:52 -06:00
Andy Miller
e9e4106d22 Merge tag '1.3.8' into develop
Release v1.3.8
2017-10-26 18:37:27 -06:00
25 changed files with 467 additions and 64 deletions

View File

@@ -1,3 +1,33 @@
# v1.3.9
## 12/05/2017
1. [](#new)
* Added new core Twig templates for `partials/metadata.html.twig` and `partials/messages.html.twig`
* Added ability to work with GPM locally [#1742](https://github.com/getgrav/grav/issues/1742)
* Added new HTML5 audio controls [#1756](https://github.com/getgrav/grav/issues/1756)
* Added `Medium::copy()` method to create a copy of a medium object
* Added new `force_lowercase_urls` functionality on routes and slugs
* Added new `item-list` filter type to remove empty items
* Added new `setFlashCookieObject()` and `getFlashCookieObject()` methods to `Session` object
* Added new `intl_enabled` option to disable PHP intl module collation when not needed
1. [](#bugfix)
* Fixed an issue with checkbox field validation [form#216](https://github.com/getgrav/grav-plugin-form/issues/216)
* Fixed issue with multibyte Markdown link URLs [#1749](https://github.com/getgrav/grav/issues/1749)
* Fixed issue with multibyte folder names [#1751](https://github.com/getgrav/grav/issues/1751)
* Fixed several issues related to `system.custom_base_url` that were broken [#1736](https://github.com/getgrav/grav/issues/1736)
* Dynamically added pages via `Pages::addPage()` were not firing `onPageProcessed()` event causing forms not to be processed
* Fixed `Page::active()` and `Page::activeChild()` to work with UTF-8 characters in the URL [#1727](https://github.com/getgrav/grav/issues/1727)
* Fixed typo in `modular.yaml` causing media to be ignored [#1725](https://github.com/getgrav/grav/issues/1725)
* Reverted `case_insensitive_urls` option as it was causing issues with taxonomy [#1733](https://github.com/getgrav/grav/pull/1733)
* Removed an extra `/` in `CompileFile.php` [#1693](https://github.com/getgrav/grav/pull/1693)
* Uri::Encode user and password to prevent issues in browsers
* Fixed "Invalid AJAX response" When using Built-in PHP Webserver in Windows [#1258](https://github.com/getgrav/grav-plugin-admin/issues/1258)
* Remove support for `config.user`, it was broken and bad practise
* Make sure that `clean cache` uses valid path [#1745](https://github.com/getgrav/grav/pull/1745)
* Fixed token creation issue with `Uri` params like `/id:3`
* Fixed CSS Pipeline failing with Google remote fonts if the file was minified [#1261](https://github.com/getgrav/grav-plugin-admin/issues/1261)
* Forced `field.multiple: true` to allow use of min/max options in `checkboxes.validate`
# v1.3.8
## 10/26/2017

View File

@@ -86,7 +86,7 @@ $ bin/gpm update
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement! Please refer to the [Contributing guide](CONTRIBUTING.md) for more guidance on this topic.
## Security issues
If you discover a possible security issue related to Grav or one of its plugins, please send an email to the core team at contact@getgrav.org and we'll address it as soon as possible.
If you discover a possible security issue related to Grav or one of its plugins, please email the core team at contact@getgrav.org and we'll address it as soon as possible.
# Getting Started
@@ -101,9 +101,11 @@ If you discover a possible security issue related to Grav or one of its plugins,
* Have a look at our [Basic Tutorial](https://learn.getgrav.org/basics/basic-tutorial)
* Dive into more [advanced](https://learn.getgrav.org/advanced) functions
* Learn about the [Grav CLI](https://learn.getgrav.org/cli-console/grav-cli)
* Review examples in the [Grav Cookbook](https://learn.getgrav.org/cookbook)
# Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/grav#backer)]
Support Grav with a monthly donation to help us continue development. [[Become a backer](https://opencollective.com/grav#backer)]
<a href="https://opencollective.com/grav/backer/0/website" target="_blank"><img src="https://opencollective.com/grav/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/grav/backer/1/website" target="_blank"><img src="https://opencollective.com/grav/backer/1/avatar.svg"></a>

View File

@@ -1131,6 +1131,16 @@ form:
label: PLUGIN_ADMIN.PWD_REGEX
help: PLUGIN_ADMIN.PWD_REGEX_HELP
intl_enabled:
type: toggle
label: PLUGIN_ADMIN.INTL_ENABLED
highlight: 1
help: PLUGIN_ADMIN.INTL_ENABLED_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
wrapped_site:
type: toggle
@@ -1154,17 +1164,6 @@ form:
validate:
type: bool
case_insensitive_urls:
type: toggle
label: PLUGIN_ADMIN.CASE_INSENSITIVE_URLS
highlight: 0
help: PLUGIN_ADMIN.CASE_INSENSITIVE_URLS_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
param_sep:
type: select
size: medium
@@ -1187,6 +1186,18 @@ form:
validate:
type: bool
force_lowercase_urls:
type: toggle
label: PLUGIN_ADMIN.FORCE_LOWERCASE_URLS
highlight: 1
default: 1
help: PLUGIN_ADMIN.FORCE_LOWERCASE_URLS_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
custom_base_url:
type: text
size: medium

View File

@@ -42,6 +42,6 @@ form:
type: ignore
content:
type: ignore
header.media_orider:
header.media_order:
type: ignore

View File

@@ -5,9 +5,11 @@ param_sep: ':' # Parameter separator, use ';'
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
reverse_proxy_setup: false # Running in a reverse proxy scenario with different webserver ports than proxy
force_ssl: false # If enabled, Grav forces to be accessed via HTTPS (NOTE: Not an ideal solution)
force_lowercase_urls: true # If you want to support mixed cased URLs set this to false
custom_base_url: '' # Set the base_url manually, e.g. http://yoursite.com/yourpath
username_regex: '^[a-z0-9_-]{3,16}$' # Only lowercase chars, digits, dashes, underscores. 3 - 16 chars
pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' # At least one number, one uppercase and lowercase letter, and be at least 8+ chars
intl_enabled: true # Special logic for PHP International Extension (mod_intl)
languages:
supported: [] # List of languages supported. eg: [en, fr, de]

View File

@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.3.8');
define('GRAV_VERSION', '1.3.9');
//define('GRAV_TESTING', true);
define('DS', '/');

View File

@@ -35,11 +35,15 @@ class Assets
const CSS_URL_REGEX = '{url\(([\'\"]?)(.*?)\1\)}';
/** @const Regex to match CSS sourcemap comments */
const CSS_SOURCEMAP_REGEX = '{\/\*# (.*) \*\/}';
const CSS_SOURCEMAP_REGEX = '{\/\*# (.*?) \*\/}';
/** @const Regex to match CSS import content */
const CSS_IMPORT_REGEX = '{@import(.*);}';
const CSS_IMPORT_REGEX = '{@import(.*?);}';
/**
* @const Regex to match <script> or <style> tag when adding inline style/script. Note that this only supports a
* single tag, so the check is greedy to avoid issues in JS.
*/
const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is';

View File

@@ -390,6 +390,7 @@ class Cache extends Getters
// Convert stream to a real path
try {
$path = $locator->findResource($stream, true, true);
if($path === false) continue;
$anything = false;
$files = glob($path . '/*');

View File

@@ -28,9 +28,12 @@ class Validation
$messages = [];
$validate = isset($field['validate']) ? (array) $field['validate'] : [];
// Validate type with fallback type text.
$type = (string) isset($validate['type']) ? $validate['type'] : $field['type'];
$method = 'type'.strtr($type, '-', '_');
// If value isn't required, we will stop validation if empty value is given.
if (empty($validate['required']) && ($value === null || $value === '')) {
if ((empty($validate['required']) || (isset($validate['required']) && $validate['required'] !== true)) && ($value === null || $value === '' || ($field['type'] === 'checkbox' && $value == false))) {
return $messages;
}
@@ -46,10 +49,6 @@ class Validation
// Get language class.
$language = Grav::instance()['language'];
// Validate type with fallback type text.
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
$method = 'type'.strtr($type, '-', '_');
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
$message = (string) isset($field['validate']['message'])
? $language->translate($field['validate']['message'])
@@ -161,7 +160,7 @@ class Validation
return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
}
protected static function typeCommaList($value, array $params, array $field)
public static function typeCommaList($value, array $params, array $field)
{
return is_array($value) ? true : self::typeText($value, $params, $field);
}
@@ -230,6 +229,8 @@ class Validation
*/
public static function typeCheckboxes($value, array $params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts to control number of options required
$field['multiple'] = true;
return self::typeArray((array) $value, $params, $field);
}
@@ -253,7 +254,7 @@ class Validation
if (!isset($field['value'])) {
$field['value'] = 1;
}
if ($value && $value != $field['value']) {
if (isset($value) && $value != $field['value']) {
return false;
}
@@ -758,6 +759,11 @@ class Validation
&& $value instanceof \Countable);
}
public static function filterItem_List($value, $params)
{
return array_values(array_filter($value, function($v) { return !empty($v); } ));
}
public static function validateJson($value, $params)
{
return (bool) (@json_decode($value));

View File

@@ -27,7 +27,7 @@ trait CompiledFile
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
if ($var === null && $this->raw === null && $this->content === null) {
$key = md5($this->filename);
$file = PhpFile::instance(CACHE_DIR . DS . "compiled/files/{$key}{$this->extension}.php");
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
$modified = $this->modified();

View File

@@ -17,6 +17,9 @@ use Symfony\Component\Yaml\Yaml;
class GPM extends Iterator
{
/** @var callable */
private $callback;
/**
* Local installed Packages
* @var Local\Packages
@@ -29,6 +32,9 @@ class GPM extends Iterator
*/
private $repository;
/** @var bool */
private $shouldRefresh;
/**
* @var Remote\GravCore
*/
@@ -47,18 +53,33 @@ class GPM extends Iterator
];
/**
* Creates a new GPM instance with Local and Remote packages available
* Loads Remote Packages available
*/
private function retrieveRemoteRepository()
{
if (!$this->repository) {
$this->repository = new Remote\Packages($this->shouldRefresh, $this->callback);
}
}
/**
* Creates a new GPM instance with Local packages available
* @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
* @param callable $callback Either a function or callback in array notation
*/
public function __construct($refresh = false, $callback = null)
{
$this->installed = new Local\Packages();
try {
$this->repository = new Remote\Packages($refresh, $callback);
$this->grav = new Remote\GravCore($refresh, $callback);
} catch (\Exception $e) {
}
$this->shouldRefresh = $refresh;
$this->callback = $callback;
}
/**
* Loads Remote Grav package available
*/
public function loadRemoteGrav()
{
$this->grav = new Remote\GravCore($this->refresh, $this->callback);
}
/**
@@ -268,6 +289,7 @@ class GPM extends Iterator
*/
public function getLatestVersionOfPackage($package_name)
{
$this->retrieveRemoteRepository();
$repository = $this->repository['plugins'];
if (isset($repository[$package_name])) {
return $repository[$package_name]->available ?: $repository[$package_name]->version;
@@ -310,6 +332,7 @@ class GPM extends Iterator
public function getUpdatableThemes()
{
$items = [];
$this->retrieveRemoteRepository();
$repository = $this->repository['themes'];
// local cache to speed things up
@@ -357,6 +380,7 @@ class GPM extends Iterator
*/
public function getReleaseType($package_name)
{
$this->retrieveRemoteRepository();
$repository = $this->repository['plugins'];
if (isset($repository[$package_name])) {
return $repository[$package_name]->release_type;
@@ -405,6 +429,7 @@ class GPM extends Iterator
*/
public function getRepositoryPlugin($slug)
{
$this->retrieveRemoteRepository();
return @$this->repository['plugins'][$slug];
}
@@ -443,6 +468,7 @@ class GPM extends Iterator
*/
public function getRepository()
{
$this->retrieveRemoteRepository();
return $this->repository;
}

View File

@@ -12,6 +12,7 @@ use Grav\Common\Grav;
use Grav\Common\Page\Page;
use Grav\Common\Uri;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Utils;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
@@ -321,7 +322,7 @@ class Excerpts
*/
protected static function parseUrl($url)
{
$url_parts = parse_url($url);
$url_parts = Utils::multibyteParseUrl($url);
if (isset($url_parts['scheme'])) {
/** @var UniformResourceLocator $locator */

View File

@@ -30,6 +30,114 @@ class AudioMedium extends Medium
];
}
/**
* Allows to set or remove the HTML5 default controls
*
* @param bool $display
* @return $this
*/
public function controls($display = true)
{
if($display)
{
$this->attributes['controls'] = true;
}
else
{
unset($this->attributes['controls']);
}
return $this;
}
/**
* Allows to set the preload behaviour
*
* @param $preload
* @return $this
*/
public function preload($preload)
{
$validPreloadAttrs = array('auto','metadata','none');
if (in_array($preload, $validPreloadAttrs))
{
$this->attributes['preload'] = $preload;
}
return $this;
}
/**
* Allows to set the controlsList behaviour
* Separate multiple values with a hyphen
*
* @param $controlsList
* @return $this
*/
public function controlsList($controlsList)
{
$controlsList = str_replace('-', ' ', $controlsList);
$this->attributes['controlsList'] = $controlsList;
return $this;
}
/**
* Allows to set the muted attribute
*
* @param bool $status
* @return $this
*/
public function muted($status = false)
{
if($status)
{
$this->attributes['muted'] = true;
}
else
{
unset($this->attributes['muted']);
}
return $this;
}
/**
* Allows to set the loop attribute
*
* @param bool $status
* @return $this
*/
public function loop($status = false)
{
if($status)
{
$this->attributes['loop'] = true;
}
else
{
unset($this->attributes['loop']);
}
return $this;
}
/**
* Allows to set the autoplay attribute
*
* @param bool $status
* @return $this
*/
public function autoplay($status = false)
{
if($status)
{
$this->attributes['autoplay'] = true;
}
else
{
unset($this->attributes['autoplay']);
}
return $this;
}
/**
* Reset medium.
*

View File

@@ -72,6 +72,16 @@ class Medium extends Data implements RenderableInterface
$this->reset();
}
/**
* Create a copy of this media object
*
* @return Medium
*/
public function copy()
{
return clone($this);
}
/**
* Return just metadata from the Medium object
*

View File

@@ -125,7 +125,7 @@ class Page
$config = Grav::instance()['config'];
$this->hide_home_route = $config->get('system.home.hide_in_urls', false);
$this->home_route = $config->get('system.home.alias');
$this->home_route = $this->adjustRouteCase($config->get('system.home.alias'));
$this->filePath($file->getPathName());
$this->modified($file->getMTime());
$this->id($this->modified() . md5($this->filePath()));
@@ -1558,7 +1558,7 @@ class Page
}
if (empty($this->slug)) {
$this->slug = strtolower(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
$this->slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
}
@@ -1748,7 +1748,7 @@ class Page
if (empty($this->raw_route)) {
$baseRoute = $this->parent ? (string)$this->parent()->rawRoute() : null;
$slug = preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder);
$slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
$this->raw_route = isset($baseRoute) ? $baseRoute . '/' . $slug : null;
}
@@ -2295,7 +2295,7 @@ class Page
*/
public function active()
{
$uri_path = rtrim(Grav::instance()['uri']->path(), '/') ?: '/';
$uri_path = rtrim(urldecode(Grav::instance()['uri']->path()), '/') ?: '/';
$routes = Grav::instance()['pages']->routes();
if (isset($routes[$uri_path])) {
@@ -2318,7 +2318,7 @@ class Page
{
$uri = Grav::instance()['uri'];
$pages = Grav::instance()['pages'];
$uri_path = rtrim($uri->path(), '/');
$uri_path = rtrim(urldecode($uri->path()), '/');
$routes = Grav::instance()['pages']->routes();
if (isset($routes[$uri_path])) {
@@ -2896,4 +2896,15 @@ class Page
}
}
}
protected function adjustRouteCase($route)
{
$case_insensitive = Grav::instance()['config']->get('system.force_lowercase_urls');
if ($case_insensitive) {
return mb_strtolower($route);
} else {
return $route;
}
}
}

View File

@@ -265,6 +265,8 @@ class Pages
$this->children[$page->parent()->path()][$page->path()] = ['slug' => $page->slug()];
}
$this->routes[$route] = $page->path();
$this->grav->fireEvent('onPageProcessed', new Event(['page' => $page]));
}
/**
@@ -1221,6 +1223,9 @@ class Pages
case 'basename':
$list[$key] = basename($key);
break;
case 'folder':
$list[$key] = $child->folder();
break;
case (is_string($header_query[0])):
$child_header = new Header((array)$child->header());
$header_value = $child_header->get($header_query[0]);
@@ -1250,7 +1255,7 @@ class Pages
$list = $this->arrayShuffle($list);
} else {
// else just sort the list according to specified key
if (extension_loaded('intl')) {
if (extension_loaded('intl') && $this->grav['config']->get('system.intl_enabled')) {
$locale = setlocale(LC_COLLATE, 0); //`setlocale` with a 0 param returns the current locale set
$col = Collator::create($locale);
if ($col) {
@@ -1258,6 +1263,13 @@ class Pages
$list = preg_replace_callback('~([0-9]+)\.~', function($number) {
return sprintf('%032d.', $number[0]);
}, $list);
$list_vals = array_values($list);
if (is_numeric(array_shift($list_vals))) {
$sort_flags = Collator::SORT_REGULAR;
} else {
$sort_flags = Collator::SORT_STRING;
}
}
$col->asort($list, $sort_flags);

View File

@@ -9,6 +9,7 @@
namespace Grav\Common\Processors;
use Grav\Common\Page\Page;
use RocketTheme\Toolbox\Event\Event;
class PagesProcessor extends ProcessorBase implements ProcessorInterface
{
@@ -21,15 +22,15 @@ class PagesProcessor extends ProcessorBase implements ProcessorInterface
$this->container['debugger']->addMessage($this->container['cache']->getCacheStatus());
$this->container['pages']->init();
$this->container->fireEvent('onPagesInitialized');
$this->container->fireEvent('onPageInitialized');
$this->container->fireEvent('onPagesInitialized', new Event(['pages' => $this->container['pages']]));
$this->container->fireEvent('onPageInitialized', new Event(['page' => $this->container['page']]));
/** @var Page $page */
$page = $this->container['page'];
if (!$page->routable()) {
// If no page found, fire event
$event = $this->container->fireEvent('onPageNotFound');
$event = $this->container->fireEvent('onPageNotFound', new Event(['page' => $page]));
if (isset($event->page)) {
unset ($this->container['page']);

View File

@@ -105,4 +105,20 @@ class Session extends BaseSession
return $object;
}
// Store something in cookie temporarily
public function setFlashCookieObject($name, $object, $time = 60)
{
setcookie($name, json_encode($object), time() + $time, '/');
}
// Return object and remove it from the cookie
public function getFlashCookieObject($name)
{
if (isset($_COOKIE[$name])) {
$object = json_decode($_COOKIE[$name]);
setcookie($name, '', time() - 3600, '/');
return $object;
}
}
}

View File

@@ -97,6 +97,9 @@ class Twig
$this->grav->fireEvent('onTwigTemplatePaths');
// Add Grav core templates location
$this->twig_paths = array_merge($this->twig_paths, $locator->findResources('system://templates'));
$this->loader = new \Twig_Loader_Filesystem($this->twig_paths);
$this->grav->fireEvent('onTwigLoader');

View File

@@ -107,7 +107,9 @@ class Uri
// Build fragment.
$this->fragment = null;
// Filter path and query string.
// Filter userinfo, path and query string.
$this->user = $this->user !== null ? static::filterUserInfo($this->user) : null;
$this->password = $this->password !== null ? static::filterUserInfo($this->password) : null;
$this->path = empty($this->path) ? '/' : static::filterPath($this->path);
$this->query = static::filterQuery($this->query);
@@ -148,7 +150,9 @@ class Uri
$this->host = $this->validateHostname($this->host) ? $this->host : 'unknown';
}
// Filter path, query string and fragment.
// Filter userinfo, path, query string and fragment.
$this->user = $this->user !== null ? static::filterUserInfo($this->user) : null;
$this->password = $this->password !== null ? static::filterUserInfo($this->password) : null;
$this->path = empty($this->path) ? '/' : static::filterPath($this->path);
$this->query = static::filterQuery($this->query);
$this->fragment = $this->fragment !== null ? static::filterQuery($this->fragment) : null;
@@ -245,7 +249,8 @@ class Uri
*/
private function buildRootPath()
{
$scriptPath = $_SERVER['PHP_SELF'];
// In Windows script path uses backslash, convert it:
$scriptPath = str_replace('\\', '/', $_SERVER['PHP_SELF']);
$rootPath = str_replace(' ', '%20', rtrim(substr($scriptPath, 0, strpos($scriptPath, 'index.php')), '/'));
// check if userdir in the path and workaround PHP bug with PHP_SELF
@@ -281,22 +286,21 @@ class Uri
$this->base .= ':' . (string)$this->port;
}
// Set some defaults
if ($grav['config']->get('system.custom_base_url')) {
$this->root_path = parse_url($grav['config']->get('system.custom_base_url'), PHP_URL_PATH);
$this->root = $grav['config']->get('system.custom_base_url');
// Handle custom base
$custom_base = rtrim($grav['config']->get('system.custom_base_url'), '/');
if ($custom_base) {
$custom_parts = parse_url($custom_base);
$orig_root_path = $this->root_path;
$this->root_path = isset($custom_parts['path']) ? rtrim($custom_parts['path'], '/') : '';
$this->root = isset($custom_parts['scheme']) ? $custom_base : $this->base . $this->root_path;
$this->uri = Utils::replaceFirstOccurrence($orig_root_path, $this->root_path, $this->uri);
} else {
$this->root = $this->base . $this->root_path;
}
$this->url = $this->base . $this->uri;
// if case insensitive urls is enabled, lowercase the url
if( $grav['config']->get('system.case_insensitive_urls') ){
$this->url = strtolower($this->url);
}
// get any params and remove them
$uri = str_replace($this->root, '', $this->url);
// remove the setup.php based base if set:
@@ -306,8 +310,9 @@ class Uri
}
// If configured to, redirect trailing slash URI's with a 302 redirect
if ($uri !== '/' && $config->get('system.pages.redirect_trailing_slash', false) && Utils::endsWith($uri, '/')) {
$grav->redirect(str_replace($this->root, '', rtrim($uri, '/')), 302);
$redirect = str_replace($this->root, '', rtrim($uri, '/'));
if ($redirect && $uri !== '/' && $redirect !== $this->base() && $config->get('system.pages.redirect_trailing_slash', false) && Utils::endsWith($uri, '/')) {
$grav->redirect($redirect, 302);
}
// process params
@@ -1138,11 +1143,20 @@ class Uri
*/
public static function addNonce($url, $action, $nonceParamName = 'nonce')
{
$fake = $url && $url[0] === '/';
if ($fake) {
$url = 'http://domain.com' . $url;
}
$uri = new static($url);
$parts = $uri->toArray();
$nonce = Utils::getNonce($action);
$parts['params'] = (isset($parts['params']) ? $parts['params'] : []) + [$nonceParamName => $nonce];
if ($fake) {
unset($parts['scheme'], $parts['host']);
}
return static::buildUrl($parts);
}
@@ -1177,6 +1191,23 @@ class Uri
return $path;
}
/**
* Filters the user info string.
*
* @param string $info The raw user or password.
* @return string The percent-encoded user or password string.
*/
public static function filterUserInfo($info)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},
$info
);
}
/**
* Filter Uri path.
*
@@ -1192,7 +1223,7 @@ class Uri
public static function filterPath($path)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
'/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},
@@ -1209,7 +1240,7 @@ class Uri
public static function filterQuery($query)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},

View File

@@ -29,7 +29,6 @@ class User extends Data
{
$grav = Grav::instance();
$locator = $grav['locator'];
$config = $grav['config'];
// force lowercase of username
$username = strtolower($username);
@@ -38,7 +37,7 @@ class User extends Data
$blueprint = $blueprints->get('user/account');
$file_path = $locator->findResource('account://' . $username . YAML_EXT);
$file = CompiledYamlFile::instance($file_path);
$content = $file->content();
$content = (array)$file->content();
if (!isset($content['username'])) {
$content['username'] = $username;
}
@@ -48,9 +47,6 @@ class User extends Data
$user = new User($content, $blueprint);
$user->file($file);
// add user to config
$config->set("user", $user);
return $user;
}

View File

@@ -80,7 +80,7 @@ abstract class Utils
}
/**
* Returns the substring of a string up to a specified needle. if not found, return the whole haytack
* Returns the substring of a string up to a specified needle. if not found, return the whole haystack
*
* @param $haystack
* @param $needle
@@ -96,6 +96,46 @@ abstract class Utils
return $haystack;
}
/**
* Utility method to replace only the first occurrence in a string
*
* @param $search
* @param $replace
* @param $subject
* @return mixed
*/
public static function replaceFirstOccurrence($search, $replace, $subject)
{
if (!$search) {
return $subject;
}
$pos = strpos($subject, $search);
if ($pos !== false) {
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
/**
* Utility method to replace only the last occurrence in a string
*
* @param $search
* @param $replace
* @param $subject
* @return mixed
*/
public static function replaceLastOccurrence($search, $replace, $subject)
{
$pos = strrpos($subject, $search);
if($pos !== false)
{
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
/**
* Merge two objects into one.
*
@@ -957,4 +997,36 @@ abstract class Utils
return intval($size);
}
}
/**
* Multibyte-safe Parse URL function
*
* @param $url
* @return mixed
*/
public static function multibyteParseUrl($url)
{
$enc_url = preg_replace_callback(
'%[^:/@?&=#]+%usD',
function ($matches)
{
return urlencode($matches[0]);
},
$url
);
$parts = parse_url($enc_url);
if($parts === false)
{
throw new \InvalidArgumentException('Malformed URL: ' . $url);
}
foreach($parts as $name => $value)
{
$parts[$name] = urldecode($value);
}
return $parts;
}
}

View File

@@ -0,0 +1,14 @@
{% set status_mapping = {'info':'green', 'error': 'red', 'warning': 'yellow'} %}
{% if grav.messages.all %}
<div id="messages">
{% for message in grav.messages.fetch %}
{% set scope = message.scope|e %}
{% set color = status_mapping[scope] %}
<div class="notices {{ scope }} {{ color }}"><p>{{ message.message|raw }}</p></div>
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,3 @@
{% for meta in page.metadata %}
<meta {% if meta.name %}name="{{ meta.name }}" {% endif %}{% if meta.http_equiv %}http-equiv="{{ meta.http_equiv }}" {% endif %}{% if meta.charset %}charset="{{ meta.charset }}" {% endif %}{% if meta.property %}property="{{ meta.property }}" {% endif %}{% if meta.content %}content="{{ meta.content }}" {% endif %}/>
{% endfor %}

View File

@@ -320,4 +320,47 @@ class GpmTest extends \Codeception\TestCase\Test
$this->assertSame(null, $this->gpm->calculateVersionNumberFromDependencyVersion('*'));
$this->assertSame('2.0.2', $this->gpm->calculateVersionNumberFromDependencyVersion('2.0.2'));
}
public function testRemoteRepositoryIsEmptyAfterConstruct()
{
$gpm = new GPM();
$reflection = new \ReflectionClass(get_class($gpm));
$repository = $reflection->getProperty('repository');
$repository->setAccessible(true);
$this->assertSame(null, $repository->getValue($gpm));
}
public function testLocalRepositoryIsNotEmptyAfterConstruct()
{
$gpm = new GPM();
$reflection = new \ReflectionClass(get_class($gpm));
$repository = $reflection->getProperty('installed');
$repository->setAccessible(true);
$this->assertInstanceOf( '\Grav\Common\GPM\Local\Packages', $repository->getValue($gpm));
}
public function testGetRepository()
{
$this->assertInstanceOf('\Grav\Common\GPM\Remote\Packages', $this->gpm->getRepository());
}
public function testLatestVersionOfPackage()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getLatestVersionOfPackage('admin'));
}
public function testReleaseType()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getReleaseType('admin'));
}
public function testGetRepositoryPlugin()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getRepositoryPlugin('admin'));
}
}