mirror of
https://github.com/getgrav/grav.git
synced 2026-05-06 11:56:09 +02:00
Merge branch 'release/0.9.14'
This commit is contained in:
22
.htaccess
22
.htaccess
@@ -2,6 +2,17 @@
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
## Begin RewriteBase
|
||||
# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# You should change the '/' to your appropriate subfolder. For example if you have
|
||||
# your Grav install at the root of your site '/' should work, else it might be something
|
||||
# along the lines of: RewriteBase /<your_sub_folder>
|
||||
##
|
||||
|
||||
# RewriteBase /
|
||||
|
||||
## End - RewriteBase
|
||||
|
||||
## Begin - Exploits
|
||||
# If you experience problems on your site block out the operations listed below
|
||||
# This attempts to block the most common type of exploit `attempts` to Grav
|
||||
@@ -19,17 +30,6 @@ RewriteRule .* index.php [F]
|
||||
#
|
||||
## End - Exploits
|
||||
|
||||
## Begin RewriteBase
|
||||
# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# You should change the '/' to your appropriate subfolder. For example if you have
|
||||
# your Grav install at the root of your site '/' should work, else it might be something
|
||||
# along the lines of: RewriteBase /<your_sub_folder>
|
||||
##
|
||||
|
||||
# RewriteBase /
|
||||
|
||||
## End - RewriteBase
|
||||
|
||||
## Begin - Index
|
||||
# If the requested path and file is not /index.php and the request
|
||||
# has not already been internally rewritten to the index.php script
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,3 +1,30 @@
|
||||
# v0.9.14
|
||||
## 01/23/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added **GZip** support
|
||||
* Added multiple configurations via `setup.php`
|
||||
* Added base structure for unit tests
|
||||
* New `onPageContentRaw()` plugin event that processes before any page processing
|
||||
* Added ability to dynamically set Metadata on page
|
||||
* Added ability to dynamically configure Markdown processing via Parsedown options
|
||||
2. [](#improved)
|
||||
* Refactored `page.content()` method to be more flexible and reliable
|
||||
* Various updates and fixes for streams resulting in better multi-site support
|
||||
* Updated Twig, Parsedown, ParsedownExtra, DoctrineCache libraries
|
||||
* Refactored Parsedown trait
|
||||
* Force modular pages to be non-visible in menus
|
||||
* Moved RewriteBase before Exploits in `.htaccess`
|
||||
* Added standard video formats to Media support
|
||||
* Added priority for inline assets
|
||||
* Check for uniqueness when adding multiple inline assets
|
||||
* Improved support for Twig-based URLs inside Markdown links and images
|
||||
* Improved Twig `url()` function
|
||||
3. [](#bugfix)
|
||||
* Fix for HTML entities quotes in Metadata values
|
||||
* Fix for `published` setting to have precedent of `publish_date` and `unpublish_date`
|
||||
* Fix for `onShutdown()` events not closing connections properly in **php-fpm** environments
|
||||
|
||||
# v0.9.13
|
||||
## 01/09/2015
|
||||
|
||||
@@ -15,7 +42,7 @@
|
||||
* House-cleaning of some unused methods in Pages object
|
||||
3. [](#bugfix)
|
||||
* Fix `uninstall` GPM command that was broken in last release
|
||||
* Fix for intermitten `undefined index` error when working with Collections
|
||||
* Fix for intermittent `undefined index` error when working with Collections
|
||||
* Fix for date of some pages being set to incorrect future timestamps
|
||||
|
||||
# v0.9.12
|
||||
@@ -27,8 +54,8 @@
|
||||
* Added support for **in-page** Twig processing in **modular** pages
|
||||
* Added configurable support for `undefined` Twig functions and filters
|
||||
2. [](#improved)
|
||||
* Fallback to default `.html` template if error occurs on non-html pages
|
||||
* Added ability to have PSR-1 friendly plugin names (camelcase, no-dashes)
|
||||
* Fall back to default `.html` template if error occurs on non-html pages
|
||||
* Added ability to have PSR-1 friendly plugin names (CamelCase, no-dashes)
|
||||
* Fix to `composer.json` to deter API rate-limit errors
|
||||
* Added **non-exception-throwing** handler for undefined methods on `Medium` objects
|
||||
3. [](#bugfix)
|
||||
|
||||
Binary file not shown.
@@ -8,7 +8,7 @@
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.16",
|
||||
"erusev/parsedown-extra": "dev-master",
|
||||
"erusev/parsedown-extra": "~0.6",
|
||||
"symfony/yaml": "~2.6",
|
||||
"symfony/console": "~2.6",
|
||||
"symfony/event-dispatcher": "~2.6",
|
||||
|
||||
22
htaccess.txt
22
htaccess.txt
@@ -2,6 +2,17 @@
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
## Begin RewriteBase
|
||||
# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# You should change the '/' to your appropriate subfolder. For example if you have
|
||||
# your Grav install at the root of your site '/' should work, else it might be something
|
||||
# along the lines of: RewriteBase /<your_sub_folder>
|
||||
##
|
||||
|
||||
# RewriteBase /
|
||||
|
||||
## End - RewriteBase
|
||||
|
||||
## Begin - Exploits
|
||||
# If you experience problems on your site block out the operations listed below
|
||||
# This attempts to block the most common type of exploit `attempts` to Grav
|
||||
@@ -19,17 +30,6 @@ RewriteRule .* index.php [F]
|
||||
#
|
||||
## End - Exploits
|
||||
|
||||
## Begin RewriteBase
|
||||
# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
|
||||
# You should change the '/' to your appropriate subfolder. For example if you have
|
||||
# your Grav install at the root of your site '/' should work, else it might be something
|
||||
# along the lines of: RewriteBase /<your_sub_folder>
|
||||
##
|
||||
|
||||
# RewriteBase /
|
||||
|
||||
## End - RewriteBase
|
||||
|
||||
## Begin - Index
|
||||
# If the requested path and file is not /index.php and the request
|
||||
# has not already been internally rewritten to the index.php script
|
||||
|
||||
@@ -40,6 +40,31 @@ swf:
|
||||
type: video
|
||||
thumb: media/thumb-swf.png
|
||||
mime: video/x-flv
|
||||
flv:
|
||||
type: video
|
||||
thumb: media/thumb-flv.png
|
||||
mime: video/x-flv
|
||||
|
||||
mp3:
|
||||
type: audio
|
||||
thumb: media/thumb-mp3.png
|
||||
mime: audio/mp3
|
||||
ogg:
|
||||
type: audio
|
||||
thumb: media/thumb-ogg.png
|
||||
mine: audio/ogg
|
||||
wma:
|
||||
type: audio
|
||||
thumb: media/thumb-wma.png
|
||||
mine: audio/wma
|
||||
m4a:
|
||||
type: audio
|
||||
thumb: media/thumb-m4a.png
|
||||
mine: audio/m4a
|
||||
wav:
|
||||
type: audio
|
||||
thumb: media/thumb-wav.png
|
||||
mine: audio/wav
|
||||
|
||||
txt:
|
||||
type: file
|
||||
|
||||
@@ -5,7 +5,6 @@ home:
|
||||
|
||||
pages:
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
markdown_extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
order:
|
||||
by: defaults # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
@@ -21,6 +20,14 @@ pages:
|
||||
events:
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
markdown:
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
'>': 'gt'
|
||||
'<': 'lt'
|
||||
|
||||
cache:
|
||||
enabled: true # Set to true to enable caching
|
||||
@@ -29,6 +36,7 @@ cache:
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
|
||||
twig:
|
||||
cache: true # Set to true to enable twig caching
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '0.9.13');
|
||||
define('GRAV_VERSION', '0.9.14');
|
||||
define('DS', '/');
|
||||
|
||||
// Directories and Paths
|
||||
@@ -17,14 +17,16 @@ define('ASSETS_DIR', ROOT_DIR . 'assets/');
|
||||
define('CACHE_DIR', ROOT_DIR . 'cache/');
|
||||
define('IMAGES_DIR', ROOT_DIR . 'images/');
|
||||
define('LOG_DIR', ROOT_DIR .'logs/');
|
||||
define('VENDOR_DIR', ROOT_DIR .'vendor/');
|
||||
define('LIB_DIR', SYSTEM_DIR .'src/');
|
||||
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
|
||||
define('DATA_DIR', USER_DIR .'data/');
|
||||
define('PAGES_DIR', USER_DIR .'pages/');
|
||||
|
||||
// DEPRECATED: Do not use!
|
||||
define('DATA_DIR', USER_DIR .'data/');
|
||||
define('LIB_DIR', SYSTEM_DIR .'src/');
|
||||
define('PLUGINS_DIR', USER_DIR .'plugins/');
|
||||
define('THEMES_DIR', USER_DIR .'themes/');
|
||||
define('VENDOR_DIR', ROOT_DIR .'vendor/');
|
||||
// END DEPRECATED
|
||||
|
||||
// Some extensions
|
||||
define('CONTENT_EXT', '.md');
|
||||
|
||||
@@ -234,8 +234,9 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
if ($asset && !array_key_exists($asset, $this->css)) {
|
||||
$this->css[$asset] = [
|
||||
$key = md5($asset);
|
||||
if ($asset && !array_key_exists($key, $this->css)) {
|
||||
$this->css[$key] = [
|
||||
'asset' => $asset,
|
||||
'priority' => $priority,
|
||||
'order' => count($this->css),
|
||||
@@ -272,8 +273,9 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
if ($asset && !array_key_exists($asset, $this->js)) {
|
||||
$this->js[$asset] = [
|
||||
$key = md5($asset);
|
||||
if ($asset && !array_key_exists($key, $this->js)) {
|
||||
$this->js[$key] = [
|
||||
'asset' => $asset,
|
||||
'priority' => $priority,
|
||||
'order' => count($this->js),
|
||||
@@ -297,9 +299,13 @@ class Assets
|
||||
*/
|
||||
public function addInlineCss($asset, $priority = 10)
|
||||
{
|
||||
|
||||
if (is_string($asset) && !in_array($asset, $this->inline_css)) {
|
||||
$this->inline_css[] = $asset;
|
||||
$key = md5($asset);
|
||||
if (is_string($asset) && !array_key_exists($key, $this->inline_css)) {
|
||||
$this->inline_css[$key] = [
|
||||
'priority' => $priority,
|
||||
'order' => count($this->inline_css),
|
||||
'asset' => $asset
|
||||
];
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -312,14 +318,19 @@ class Assets
|
||||
* For adding chunks of string-based inline JS
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @param int $priority the priority, bigger comes first
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addInlineJs($asset)
|
||||
public function addInlineJs($asset, $priority = 10)
|
||||
{
|
||||
|
||||
if (is_string($asset) && !in_array($asset, $this->inline_js)) {
|
||||
$this->inline_js[] = $asset;
|
||||
$key = md5($asset);
|
||||
if (is_string($asset) && !array_key_exists($key, $this->inline_js)) {
|
||||
$this->inline_js[$key] = [
|
||||
'priority' => $priority,
|
||||
'order' => count($this->inline_js),
|
||||
'asset' => $asset
|
||||
];
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -346,8 +357,16 @@ class Assets
|
||||
}
|
||||
return $a['priority'] - $b['priority'];
|
||||
});
|
||||
|
||||
usort($this->inline_css, function ($a, $b) {
|
||||
if ($a['priority'] == $b['priority']) {
|
||||
return $b['order'] - $a['order'];
|
||||
}
|
||||
return $a['priority'] - $b['priority'];
|
||||
});
|
||||
}
|
||||
$this->css = array_reverse($this->css);
|
||||
$this->inline_css = array_reverse($this->inline_css);
|
||||
|
||||
$attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes));
|
||||
|
||||
@@ -368,7 +387,7 @@ class Assets
|
||||
if (count($this->inline_css) > 0) {
|
||||
$output .= "<style>\n";
|
||||
foreach ($this->inline_css as $inline) {
|
||||
$output .= $inline . "\n";
|
||||
$output .= $inline['asset'] . "\n";
|
||||
}
|
||||
$output .= "</style>\n";
|
||||
}
|
||||
@@ -397,7 +416,16 @@ class Assets
|
||||
}
|
||||
return $a['priority'] - $b['priority'];
|
||||
});
|
||||
|
||||
usort($this->inline_js, function ($a, $b) {
|
||||
if ($a['priority'] == $b['priority']) {
|
||||
return $b['order'] - $a['order'];
|
||||
}
|
||||
return $a['priority'] - $b['priority'];
|
||||
});
|
||||
|
||||
$this->js = array_reverse($this->js);
|
||||
$this->inline_js = array_reverse($this->inline_js);
|
||||
|
||||
$attributes = $this->attributes(array_merge(['type' => 'text/javascript'], $attributes));
|
||||
|
||||
@@ -417,7 +445,7 @@ class Assets
|
||||
if (count($this->inline_js) > 0) {
|
||||
$output .= "<script>\n";
|
||||
foreach ($this->inline_js as $inline) {
|
||||
$output .= $inline . "\n";
|
||||
$output .= $inline['asset'] . "\n";
|
||||
}
|
||||
$output .= "</script>\n";
|
||||
}
|
||||
|
||||
@@ -168,6 +168,8 @@ class Config extends Data
|
||||
|
||||
$this->loadCompiledBlueprints($this->blueprintLookup, $this->pluginLookup, 'master');
|
||||
$this->loadCompiledConfig($this->configLookup, $this->pluginLookup, 'master');
|
||||
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
public function checksum()
|
||||
@@ -331,4 +333,47 @@ class Config extends Data
|
||||
$this->join($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStreams()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,17 +33,41 @@ abstract class Folder
|
||||
return $last_modified;
|
||||
}
|
||||
|
||||
|
||||
public static function getRelativePath($to, $from = ROOT_DIR)
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePath($path, $base = GRAV_ROOT)
|
||||
{
|
||||
$from = preg_replace('![\\|/]+!', '/', $from);
|
||||
$to = preg_replace('![\\|/]+!', '/', $to);
|
||||
if (strpos($to, $from) === 0) {
|
||||
$to = substr($to, strlen($from));
|
||||
if ($base) {
|
||||
$base = preg_replace('![\\|/]+!', '/', $base);
|
||||
$path = preg_replace('![\\|/]+!', '/', $path);
|
||||
if (strpos($path, $base) === 0) {
|
||||
$path = ltrim(substr($path, strlen($base)), '/');
|
||||
}
|
||||
}
|
||||
|
||||
return $to;
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift first directory out of the path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public static function shift(&$path)
|
||||
{
|
||||
$parts = explode('/', trim($path, '/'), 2);
|
||||
$result = array_shift($parts);
|
||||
$path = array_shift($parts);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find the last modified time under given path by file.
|
||||
*
|
||||
@@ -208,8 +232,9 @@ abstract class Folder
|
||||
/**
|
||||
* Recursively delete directory from filesystem.
|
||||
*
|
||||
* @param string $target
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($target)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Page\Pages;
|
||||
use Grav\Common\Service\ConfigServiceProvider;
|
||||
use Grav\Common\Service\ErrorServiceProvider;
|
||||
@@ -97,13 +98,18 @@ class Grav extends Container
|
||||
$container['page'] = function ($c) {
|
||||
/** @var Pages $pages */
|
||||
$pages = $c['pages'];
|
||||
$page = $pages->dispatch($c['uri']->route());
|
||||
|
||||
// If base URI is set, we want to remove it from the URL.
|
||||
$path = '/' . ltrim(Folder::getRelativePath($c['uri']->route(), $pages->base()), '/');
|
||||
|
||||
$page = $pages->dispatch($path);
|
||||
|
||||
if (!$page || !$page->routable()) {
|
||||
|
||||
// special case where a media file is requested
|
||||
if (!$page) {
|
||||
$path_parts = pathinfo($c['uri']->route());
|
||||
$path_parts = pathinfo($path);
|
||||
|
||||
$page = $c['pages']->dispatch($path_parts['dirname']);
|
||||
if ($page) {
|
||||
$media = $page->media()->all();
|
||||
@@ -164,6 +170,10 @@ class Grav extends Container
|
||||
{
|
||||
// Use output buffering to prevent headers from being sent too early.
|
||||
ob_start();
|
||||
if ($this['config']->get('system.cache.gzip')) {
|
||||
ob_start('ob_gzhandler');
|
||||
}
|
||||
|
||||
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $this['debugger'];
|
||||
@@ -319,12 +329,21 @@ class Grav extends Container
|
||||
$this['session']->close();
|
||||
}
|
||||
|
||||
header('Content-length: ' . ob_get_length());
|
||||
if ($this['config']->get('system.cache.gzip')) {
|
||||
ob_end_flush(); // gzhandler buffer
|
||||
}
|
||||
|
||||
header('Content-Length: ' . ob_get_length());
|
||||
header("Connection: close\r\n");
|
||||
|
||||
ob_end_flush();
|
||||
ob_end_flush(); // regular buffer
|
||||
ob_flush();
|
||||
flush();
|
||||
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
@fastcgi_finish_request();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->fireEvent('onShutdown');
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Markdown;
|
||||
|
||||
class Markdown extends \Parsedown
|
||||
{
|
||||
use MarkdownGravLinkTrait;
|
||||
|
||||
public function __construct($page)
|
||||
{
|
||||
$this->page = $page;
|
||||
$this->BlockTypes['{'] [] = "TwigTag";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Markdown;
|
||||
|
||||
class MarkdownExtra extends \ParsedownExtra
|
||||
{
|
||||
use MarkdownGravLinkTrait;
|
||||
|
||||
public function __construct($page)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->page = $page;
|
||||
$this->BlockTypes['{'] [] = "TwigTag";
|
||||
}
|
||||
}
|
||||
13
system/src/Grav/Common/Markdown/Parsedown.php
Normal file
13
system/src/Grav/Common/Markdown/Parsedown.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace Grav\Common\Markdown;
|
||||
|
||||
class Parsedown extends \Parsedown
|
||||
{
|
||||
use ParsedownGravTrait;
|
||||
|
||||
public function __construct($page)
|
||||
{
|
||||
$this->init($page);
|
||||
}
|
||||
|
||||
}
|
||||
13
system/src/Grav/Common/Markdown/ParsedownExtra.php
Normal file
13
system/src/Grav/Common/Markdown/ParsedownExtra.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace Grav\Common\Markdown;
|
||||
|
||||
class ParsedownExtra extends \ParsedownExtra
|
||||
{
|
||||
use ParsedownGravTrait;
|
||||
|
||||
public function __construct($page)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->init($page);
|
||||
}
|
||||
}
|
||||
@@ -10,60 +10,109 @@ use Grav\Common\Uri;
|
||||
/**
|
||||
* A trait to add some custom processing to the identifyLink() method in Parsedown and ParsedownExtra
|
||||
*/
|
||||
trait MarkdownGravLinkTrait
|
||||
trait ParsedownGravTrait
|
||||
{
|
||||
use GravTrait;
|
||||
protected $page;
|
||||
protected $base_url;
|
||||
protected $pages_dir;
|
||||
protected $special_chars;
|
||||
|
||||
protected $twig_link_regex = '/\!*\[(?:.*)\]\(([{{|{%|{#].*[#}|%}|}}])\)/';
|
||||
|
||||
/**
|
||||
* Initialiazation function to setup key variables needed by the MarkdownGravLinkTrait
|
||||
*
|
||||
* @param $page
|
||||
*/
|
||||
protected function init($page)
|
||||
{
|
||||
$this->page = $page;
|
||||
$this->BlockTypes['{'] [] = "TwigTag";
|
||||
$this->base_url = rtrim(self::$grav['base_url'] . self::$grav['pages']->base(), '/');
|
||||
$this->pages_dir = self::$grav['locator']->findResource('page://');
|
||||
$this->special_chars = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for special chars
|
||||
*
|
||||
* @param $special_chars
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
function setSpecialChars($special_chars)
|
||||
{
|
||||
$this->special_chars = $special_chars;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure Twig tags are treated as block level items with no <p></p> tags
|
||||
*/
|
||||
protected function identifyTwigTag($Line)
|
||||
protected function blockTwigTag($Line)
|
||||
{
|
||||
if (preg_match('/[{%|{{|{#].*[#}|}}|%}]/', $Line['body'], $matches)) {
|
||||
$Block = array(
|
||||
'element' => $Line['body'],
|
||||
'markup' => $Line['body'],
|
||||
);
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyLink($Excerpt)
|
||||
protected function inlineSpecialCharacter($Excerpt)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = self::$grav['config'];
|
||||
|
||||
// Run the parent method to get the actual results
|
||||
$Excerpt = parent::identifyLink($Excerpt);
|
||||
$actions = array();
|
||||
$this->base_url = self::$grav['base_url'];
|
||||
|
||||
// if this is a link
|
||||
if (isset($Excerpt['element']['attributes']['href'])) {
|
||||
|
||||
$url = parse_url(htmlspecialchars_decode($Excerpt['element']['attributes']['href']));
|
||||
|
||||
// if there is no scheme, the file is local
|
||||
if (!isset($url['scheme'])) {
|
||||
|
||||
// convert the URl is required
|
||||
$Excerpt['element']['attributes']['href'] = $this->convertUrl(Uri::build_url($url));
|
||||
}
|
||||
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) {
|
||||
return array(
|
||||
'markup' => '&',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
// if this is an image
|
||||
if (isset($Excerpt['element']['attributes']['src'])) {
|
||||
if (isset($this->special_chars[$Excerpt['text'][0]])) {
|
||||
return array(
|
||||
'markup' => '&'.$this->special_chars[$Excerpt['text'][0]].';',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$alt = isset($Excerpt['element']['attributes']['alt']) ? $Excerpt['element']['attributes']['alt'] : '';
|
||||
$title = isset($Excerpt['element']['attributes']['title']) ? $Excerpt['element']['attributes']['title'] : '';
|
||||
protected function inlineImage($excerpt)
|
||||
{
|
||||
if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
|
||||
$excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
|
||||
$excerpt = parent::inlineImage($excerpt);
|
||||
$excerpt['element']['attributes']['src'] = $matches[1];
|
||||
$excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
|
||||
return $excerpt;
|
||||
} else {
|
||||
$excerpt = parent::inlineImage($excerpt);
|
||||
}
|
||||
|
||||
$actions = array();
|
||||
|
||||
// if this is an image
|
||||
if (isset($excerpt['element']['attributes']['src'])) {
|
||||
|
||||
$alt = $excerpt['element']['attributes']['alt'] ?: '';
|
||||
$title = $excerpt['element']['attributes']['title'] ?: '';
|
||||
|
||||
//get the url and parse it
|
||||
$url = parse_url(htmlspecialchars_decode($Excerpt['element']['attributes']['src']));
|
||||
$url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['src']));
|
||||
|
||||
//get back to current page if possible
|
||||
|
||||
// if there is no host set but there is a path, the file is local
|
||||
if (!isset($url['host']) && isset($url['path'])) {
|
||||
// get the media objects for this page
|
||||
$media = $this->page->media();
|
||||
|
||||
// get the local path to page media if possible
|
||||
if (strpos($url['path'], $this->page->url()) !== false) {
|
||||
$url['path'] = ltrim(str_replace($this->page->url(), '', $url['path']), '/');
|
||||
}
|
||||
|
||||
// if there is a media file that matches the path referenced..
|
||||
if (isset($media->images()[$url['path']])) {
|
||||
// get the medium object
|
||||
@@ -92,10 +141,10 @@ trait MarkdownGravLinkTrait
|
||||
|
||||
// set the src element with the new generated url
|
||||
if (!isset($actions['lightbox']) && !is_array($src)) {
|
||||
$Excerpt['element']['attributes']['src'] = $src;
|
||||
$excerpt['element']['attributes']['src'] = $src;
|
||||
} else {
|
||||
// Create the custom lightbox element
|
||||
$Element = array(
|
||||
$element = array(
|
||||
'name' => 'a',
|
||||
'attributes' => array('rel' => $src['a_rel'], 'href' => $src['a_url']),
|
||||
'handler' => 'element',
|
||||
@@ -106,20 +155,50 @@ trait MarkdownGravLinkTrait
|
||||
);
|
||||
|
||||
// Set any custom classes on the lightbox element
|
||||
if (isset($Excerpt['element']['attributes']['class'])) {
|
||||
$Element['attributes']['class'] = $Excerpt['element']['attributes']['class'];
|
||||
if (isset($excerpt['element']['attributes']['class'])) {
|
||||
$element['attributes']['class'] = $excerpt['element']['attributes']['class'];
|
||||
}
|
||||
|
||||
// Set the lightbox element on the Excerpt
|
||||
$Excerpt['element'] = $Element;
|
||||
$excerpt['element'] = $element;
|
||||
}
|
||||
} else {
|
||||
// not a current page media file, see if it needs converting to relative
|
||||
$Excerpt['element']['attributes']['src'] = $this->convertUrl(Uri::build_url($url));
|
||||
$excerpt['element']['attributes']['src'] = $this->convertUrl(Uri::build_url($url));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $Excerpt;
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
protected function inlineLink($excerpt)
|
||||
{
|
||||
// do some trickery to get around Parsedown requirement for valid URL if its Twig in there
|
||||
if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
|
||||
$excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
|
||||
$excerpt = parent::inlineLink($excerpt);
|
||||
$excerpt['element']['attributes']['href'] = $matches[1];
|
||||
$excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
|
||||
return $excerpt;
|
||||
} else {
|
||||
$excerpt = parent::inlineLink($excerpt);
|
||||
}
|
||||
|
||||
// if this is a link
|
||||
if (isset($excerpt['element']['attributes']['href'])) {
|
||||
|
||||
$url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href']));
|
||||
|
||||
// if there is no scheme, the file is local
|
||||
if (!isset($url['scheme'])) {
|
||||
|
||||
// convert the URl is required
|
||||
$excerpt['element']['attributes']['href'] = $this->convertUrl(Uri::build_url($url));
|
||||
}
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,18 +208,18 @@ trait MarkdownGravLinkTrait
|
||||
*/
|
||||
protected function convertUrl($markdown_url)
|
||||
{
|
||||
// if absolue and starts with a base_url move on
|
||||
// if absolute and starts with a base_url move on
|
||||
if ($this->base_url != '' && strpos($markdown_url, $this->base_url) === 0) {
|
||||
$new_url = $markdown_url;
|
||||
// if its absolute with /
|
||||
// if its absolute and starts with /
|
||||
} elseif (strpos($markdown_url, '/') === 0) {
|
||||
$new_url = rtrim($this->base_url, '/') . $markdown_url;
|
||||
$new_url = $this->base_url . $markdown_url;
|
||||
} else {
|
||||
$relative_path = rtrim($this->base_url, '/') . $this->page->route();
|
||||
$relative_path = $this->base_url . $this->page->route();
|
||||
|
||||
// If this is a 'real' filepath clean it up
|
||||
if (file_exists($this->page->path().'/'.parse_url($markdown_url, PHP_URL_PATH))) {
|
||||
$relative_path = rtrim($this->base_url, '/') . preg_replace('/\/([\d]+.)/', '/', str_replace(PAGES_DIR, '/', $this->page->path()));
|
||||
if (file_exists($this->page->path() . '/' . parse_url($markdown_url, PHP_URL_PATH))) {
|
||||
$relative_path = $this->base_url . preg_replace('/\/([\d]+.)/', '/', str_replace($this->pages_dir, '', $this->page->path()));
|
||||
$markdown_url = preg_replace('/^([\d]+.)/', '', preg_replace('/\/([\d]+.)/', '/', trim(preg_replace('/[^\/]+(\.md$)/', '', $markdown_url), '/')));
|
||||
}
|
||||
|
||||
@@ -226,15 +226,15 @@ class Collection extends Iterator
|
||||
$start = strtotime($startDate);
|
||||
$end = $endDate ? strtotime($endDate) : strtotime("now +1000 years");
|
||||
|
||||
$daterange = [];
|
||||
$date_range = [];
|
||||
|
||||
foreach ($this->items as $path => $slug) {
|
||||
$page = $this->pages->get($path);
|
||||
if ($page->date() > $start && $page->date() < $end) {
|
||||
$daterange[$path] = $slug;
|
||||
$date_range[$path] = $slug;
|
||||
}
|
||||
}
|
||||
$this->items = $daterange;
|
||||
$this->items = $date_range;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class Media extends Getters
|
||||
protected $instances = array();
|
||||
protected $images = array();
|
||||
protected $videos = array();
|
||||
protected $audios = array();
|
||||
protected $files = array();
|
||||
|
||||
/**
|
||||
@@ -155,6 +156,17 @@ class Media extends Getters
|
||||
return $this->videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all audio media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->audios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all file media.
|
||||
*
|
||||
@@ -179,6 +191,9 @@ class Media extends Getters
|
||||
case 'video':
|
||||
$this->videos[$file->filename] = $file;
|
||||
break;
|
||||
case 'audio':
|
||||
$this->audios[$file->filename] = $file;
|
||||
break;
|
||||
default:
|
||||
$this->files[$file->filename] = $file;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ use Grav\Common\Twig;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Taxonomy;
|
||||
use Grav\Common\Markdown\Markdown;
|
||||
use Grav\Common\Markdown\MarkdownExtra;
|
||||
use Grav\Common\Markdown\Parsedown;
|
||||
use Grav\Common\Markdown\ParsedownExtra;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\File\MarkdownFile;
|
||||
@@ -122,11 +122,9 @@ class Page
|
||||
$this->visible();
|
||||
$this->modularTwig($this->slug[0] == '_');
|
||||
|
||||
// Handle publishing dates
|
||||
$config = self::$grav['config'];
|
||||
|
||||
if ($config->get('system.pages.publish_dates')) {
|
||||
|
||||
// Handle publishing dates if no explict published option set
|
||||
if (self::$grav['config']->get('system.pages.publish_dates') && !isset($this->header->published)) {
|
||||
// unpublish if required, if not clear cache right before page should be unpublished
|
||||
if ($this->unpublishDate()) {
|
||||
if ($this->unpublishDate() < time()) {
|
||||
$this->published(false);
|
||||
@@ -135,14 +133,13 @@ class Page
|
||||
self::$grav['cache']->setLifeTime($this->unpublishDate());
|
||||
}
|
||||
}
|
||||
|
||||
// publish if required, if not clear cache right before page is published
|
||||
if ($this->publishDate() != $this->modified() && $this->publishDate() > time()) {
|
||||
$this->published(false);
|
||||
self::$grav['cache']->setLifeTime($this->publishDate());
|
||||
}
|
||||
}
|
||||
$this->published();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,38 +346,50 @@ class Page
|
||||
$cache_id = md5('page'.$this->id());
|
||||
$this->content = $cache->fetch($cache_id);
|
||||
|
||||
$update_cache = false;
|
||||
if ($this->content === false) {
|
||||
// Process Markdown
|
||||
$this->content = $this->processMarkdown();
|
||||
$update_cache = true;
|
||||
$process_markdown = $this->shouldProcess('markdown');
|
||||
$process_twig = $this->shouldProcess('twig');
|
||||
$cache_twig = isset($this->header->cache_enable) ? $this->header->cache_enable : true;
|
||||
$twig_first = isset($this->header->twig_first) ? $this->header->twig_first : false;
|
||||
$twig_already_processed = false;
|
||||
|
||||
// if no cached-content run everything
|
||||
if ($this->content == false) {
|
||||
|
||||
$this->content = $this->raw_content;
|
||||
self::$grav->fireEvent('onPageContentRaw', new Event(['page' => $this]));
|
||||
|
||||
if ($twig_first) {
|
||||
if ($process_twig) {
|
||||
$this->processTwig();
|
||||
$twig_already_processed = true;
|
||||
}
|
||||
if ($process_markdown) {
|
||||
$this->processMarkdown();
|
||||
}
|
||||
if ($cache_twig) {
|
||||
$this->cachePageContent();
|
||||
}
|
||||
} else {
|
||||
if ($process_markdown) {
|
||||
$this->processMarkdown();
|
||||
}
|
||||
if (!$cache_twig) {
|
||||
$this->cachePageContent();
|
||||
}
|
||||
if ($process_twig) {
|
||||
$this->processTwig();
|
||||
$twig_already_processed = true;
|
||||
}
|
||||
if ($cache_twig) {
|
||||
$this->cachePageContent();
|
||||
}
|
||||
}
|
||||
// content cached, but twig cache off
|
||||
}
|
||||
|
||||
// Process Twig if enabled
|
||||
if ($this->shouldProcess('twig')) {
|
||||
|
||||
// Always process twig if caching in the page is disabled
|
||||
$process_twig = (isset($this->header->cache_enable) && !$this->header->cache_enable);
|
||||
|
||||
// Do we want to cache markdown, but process twig in each page?
|
||||
if ($update_cache && $process_twig) {
|
||||
$cache->save($cache_id, $this->content);
|
||||
$update_cache = false;
|
||||
}
|
||||
|
||||
// Do we need to process twig this time?
|
||||
if ($update_cache || $process_twig) {
|
||||
/** @var Twig $twig */
|
||||
$twig = self::$grav['twig'];
|
||||
$this->content = $twig->processPage($this, $this->content);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the whole page, including processed content
|
||||
if ($update_cache) {
|
||||
// Process any post-processing but pre-caching functionality
|
||||
self::$grav->fireEvent('onPageContentProcessed', new Event(['page' => $this]));
|
||||
$cache->save($cache_id, $this->content);
|
||||
// only markdown content cached, process twig if required and not already processed
|
||||
if ($process_twig && !$cache_twig && !$twig_already_processed) {
|
||||
$this->processTwig();
|
||||
}
|
||||
|
||||
// Handle summary divider
|
||||
@@ -395,6 +404,61 @@ class Page
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the Markdown content. Uses Parsedown or Parsedown Extra depending on configuration
|
||||
*/
|
||||
protected function processMarkdown()
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = self::$grav['config'];
|
||||
|
||||
$defaults = (array) $config->get('system.pages.markdown');
|
||||
if (isset($this->header()->markdown)) {
|
||||
$defaults = array_merge($defaults, $this->header()->markdown);
|
||||
}
|
||||
|
||||
// pages.markdown_extra is deprecated, but still check it...
|
||||
if (isset($this->markdown_extra) || $config->get('system.pages.markdown_extra') !== null) {
|
||||
$defaults['extra'] = $this->markdown_extra;
|
||||
}
|
||||
|
||||
// Initialize the preferred variant of Parsedown
|
||||
if ($defaults['extra']) {
|
||||
$parsedown = new ParsedownExtra($this);
|
||||
} else {
|
||||
$parsedown = new Parsedown($this);
|
||||
}
|
||||
|
||||
$parsedown->setBreaksEnabled($defaults['auto_line_breaks']);
|
||||
$parsedown->setUrlsLinked($defaults['auto_url_links']);
|
||||
$parsedown->setMarkupEscaped($defaults['escape_markup']);
|
||||
$parsedown->setSpecialChars($defaults['special_chars']);
|
||||
|
||||
$this->content = $parsedown->text($this->content);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the Twig page content.
|
||||
*/
|
||||
private function processTwig()
|
||||
{
|
||||
$twig = self::$grav['twig'];
|
||||
$this->content = $twig->processPage($this, $this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the onPageContentProcessed event, and caches the page content using a unique ID for the page
|
||||
*/
|
||||
private function cachePageContent()
|
||||
{
|
||||
$cache = self::$grav['cache'];
|
||||
$cache_id = md5('page'.$this->id());
|
||||
|
||||
self::$grav->fireEvent('onPageContentProcessed', new Event(['page' => $this]));
|
||||
$cache->save($cache_id, $this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed by the onPageContentProcessed event to get the raw page content
|
||||
*
|
||||
@@ -453,6 +517,9 @@ class Page
|
||||
if ($name == 'media.image') {
|
||||
return $this->media()->images();
|
||||
}
|
||||
if ($name == 'media.audio') {
|
||||
return $this->media()->audios();
|
||||
}
|
||||
|
||||
$path = explode('.', $name);
|
||||
$scope = array_shift($path);
|
||||
@@ -848,9 +915,16 @@ class Page
|
||||
/**
|
||||
* Function to merge page metadata tags and build an array of Metadata objects
|
||||
* that can then be rendered in the page.
|
||||
*
|
||||
* @param array $var an Array of metadata values to set
|
||||
* @return array an Array of metadata values for the page
|
||||
*/
|
||||
public function metadata()
|
||||
public function metadata($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
$this->metadata = (array) $var;
|
||||
}
|
||||
|
||||
// if not metadata yet, process it.
|
||||
if (null === $this->metadata) {
|
||||
|
||||
@@ -879,14 +953,14 @@ class Page
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $property => $prop_value) {
|
||||
$prop_key = $key.":".$property;
|
||||
$this->metadata[$prop_key] = array('property'=>$prop_key, 'content'=>$prop_value);
|
||||
$this->metadata[$prop_key] = array('property'=>$prop_key, 'content'=>htmlspecialchars($prop_value, ENT_QUOTES));
|
||||
}
|
||||
// If it this is a standard meta data type
|
||||
} else {
|
||||
if (in_array($key, $header_tag_http_equivs)) {
|
||||
$this->metadata[$key] = array('http_equiv'=>$key, 'content'=>$value);
|
||||
$this->metadata[$key] = array('http_equiv'=>$key, 'content'=>htmlspecialchars($value, ENT_QUOTES));
|
||||
} else {
|
||||
$this->metadata[$key] = array('name'=>$key, 'content'=>$value);
|
||||
$this->metadata[$key] = array('name'=>$key, 'content'=>htmlspecialchars($value, ENT_QUOTES));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -966,9 +1040,13 @@ class Page
|
||||
*/
|
||||
public function url($include_host = false)
|
||||
{
|
||||
/** @var Pages $pages */
|
||||
$pages = self::$grav['pages'];
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = self::$grav['uri'];
|
||||
$rootUrl = $uri->rootUrl($include_host);
|
||||
|
||||
$rootUrl = $uri->rootUrl($include_host) . $pages->base();
|
||||
$url = $rootUrl.'/'.trim($this->route(), '/');
|
||||
|
||||
// trim trailing / if not root
|
||||
@@ -1209,6 +1287,7 @@ class Page
|
||||
$this->modular_twig = (bool) $var;
|
||||
if ($var) {
|
||||
$this->process['twig'] = true;
|
||||
$this->visible(false);
|
||||
}
|
||||
}
|
||||
return $this->modular_twig;
|
||||
@@ -1382,14 +1461,16 @@ class Page
|
||||
* Helper method to return a page.
|
||||
*
|
||||
* @param string $url the url of the page
|
||||
* @return Page page you were looking for if it exists
|
||||
* @param bool $all
|
||||
*
|
||||
* @return \Grav\Common\Page\Page page you were looking for if it exists
|
||||
* @deprecated
|
||||
*/
|
||||
public function find($url)
|
||||
public function find($url, $all = false)
|
||||
{
|
||||
/** @var Pages $pages */
|
||||
$pages = self::$grav['pages'];
|
||||
return $pages->dispatch($url);
|
||||
return $pages->dispatch($url, $all);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1585,53 +1666,6 @@ class Page
|
||||
return $file && $file->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the Markdown if processing is enabled for it. If not, process as 'raw' which simply strips the
|
||||
* header YAML from the raw, and sends back the content portion. i.e. the bit below the header.
|
||||
*
|
||||
* @return string the content for the page
|
||||
*/
|
||||
protected function processMarkdown()
|
||||
{
|
||||
// Process Markdown if required
|
||||
$process_method = $this->shouldProcess('markdown') ? 'parseMarkdownContent' : 'rawContent';
|
||||
$content = $this->$process_method($this->raw_content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the raw content. Basically just strips the headers out and returns the rest.
|
||||
*
|
||||
* @param string $content Input raw content
|
||||
* @return string Output content after headers have been stripped
|
||||
*/
|
||||
protected function rawContent($content)
|
||||
{
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the Markdown content. This strips the headers, the process the resulting content as Markdown.
|
||||
*
|
||||
* @param string $content Input raw content
|
||||
* @return string Output content that has been processed as Markdown
|
||||
*/
|
||||
protected function parseMarkdownContent($content)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = self::$grav['config'];
|
||||
|
||||
// get the appropriate setting for markdown extra
|
||||
if (isset($this->markdown_extra) ? $this->markdown_extra : $config->get('system.pages.markdown_extra')) {
|
||||
$parsedown = new MarkdownExtra($this);
|
||||
} else {
|
||||
$parsedown = new Markdown($this);
|
||||
}
|
||||
$content = $parsedown->text($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the path.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@ use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Data\Blueprints;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* GravPages is the class that is the entry point into the hierarchy of pages
|
||||
@@ -34,6 +35,11 @@ class Pages
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $base;
|
||||
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
@@ -67,6 +73,23 @@ class Pages
|
||||
public function __construct(Grav $c)
|
||||
{
|
||||
$this->grav = $c;
|
||||
$this->base = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set base path for the pages.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function base($path = null)
|
||||
{
|
||||
if ($path !== null) {
|
||||
$path = trim($path, '/');
|
||||
$this->base = $path ? '/' . $path : null;
|
||||
}
|
||||
|
||||
return $this->base;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,8 +259,6 @@ class Pages
|
||||
// Fetch page if there's a defined route to it.
|
||||
$page = isset($this->routes[$url]) ? $this->get($this->routes[$url]) : null;
|
||||
|
||||
|
||||
|
||||
// If the page cannot be reached, look into site wide redirects, routes + wildcards
|
||||
if (!$all && (!$page || !$page->routable())) {
|
||||
/** @var Config $config */
|
||||
@@ -278,7 +299,10 @@ class Pages
|
||||
*/
|
||||
public function root()
|
||||
{
|
||||
return $this->instances[rtrim(PAGES_DIR, DS)];
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
return $this->instances[rtrim($locator->findResource('page://'), DS)];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,6 +432,10 @@ class Pages
|
||||
/** @var Config $config */
|
||||
$config = $this->grav['config'];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
$pagesDir = $locator->findResource('page://');
|
||||
|
||||
if ($config->get('system.cache.enabled')) {
|
||||
/** @var Cache $cache */
|
||||
$cache = $this->grav['cache'];
|
||||
@@ -421,10 +449,10 @@ class Pages
|
||||
$last_modified = 0;
|
||||
break;
|
||||
case 'folder':
|
||||
$last_modified = Folder::lastModifiedFolder(PAGES_DIR);
|
||||
$last_modified = Folder::lastModifiedFolder($pagesDir);
|
||||
break;
|
||||
default:
|
||||
$last_modified = Folder::lastModifiedFile(PAGES_DIR);
|
||||
$last_modified = Folder::lastModifiedFile($pagesDir);
|
||||
}
|
||||
|
||||
$page_cache_id = md5(USER_DIR.$last_modified.$config->checksum());
|
||||
@@ -432,7 +460,7 @@ class Pages
|
||||
list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cache->fetch($page_cache_id);
|
||||
if (!$this->instances) {
|
||||
$this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..');
|
||||
$this->recurse();
|
||||
$this->recurse($pagesDir);
|
||||
$this->buildRoutes();
|
||||
|
||||
// save pages, routes, taxonomy, and sort to cache
|
||||
@@ -446,7 +474,7 @@ class Pages
|
||||
$taxonomy->taxonomy($taxonomy_map);
|
||||
}
|
||||
} else {
|
||||
$this->recurse();
|
||||
$this->recurse($pagesDir);
|
||||
$this->buildRoutes();
|
||||
}
|
||||
}
|
||||
@@ -460,7 +488,7 @@ class Pages
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function recurse($directory = PAGES_DIR, Page &$parent = null)
|
||||
protected function recurse($directory, Page &$parent = null)
|
||||
{
|
||||
$directory = rtrim($directory, DS);
|
||||
$iterator = new \DirectoryIterator($directory);
|
||||
|
||||
@@ -18,11 +18,17 @@ use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
class ConfigServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
private $environment;
|
||||
private $setup;
|
||||
|
||||
public function register(Container $container)
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
// Pre-load setup.php as it contains our initial configuration.
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$this->setup = is_file($file) ? (array) include $file : [];
|
||||
$this->environment = isset($this->setup['environment']) ? $this->setup['environment'] : null;
|
||||
|
||||
$container['blueprints'] = function ($c) use ($self) {
|
||||
return $self->loadMasterBlueprints($c);
|
||||
};
|
||||
@@ -45,9 +51,7 @@ class ConfigServiceProvider implements ServiceProviderInterface
|
||||
}
|
||||
|
||||
if (!isset($config)) {
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$data = is_file($file) ? (array) include $file : [];
|
||||
$config = new Config($data, $container, $environment);
|
||||
$config = new Config($this->setup, $container, $environment);
|
||||
}
|
||||
|
||||
return $config;
|
||||
|
||||
@@ -11,52 +11,32 @@ use RocketTheme\Toolbox\StreamWrapper\StreamBuilder;
|
||||
|
||||
class StreamsServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
protected $schemes = [];
|
||||
|
||||
public function register(Container $container)
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
$container['locator'] = function($c) use ($self) {
|
||||
$locator = new UniformResourceLocator(ROOT_DIR);
|
||||
$self->init($c, $locator);
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $c['config'];
|
||||
$config->initializeLocator($locator);
|
||||
|
||||
return $locator;
|
||||
};
|
||||
|
||||
$container['streams'] = function($c) use ($self) {
|
||||
/** @var Config $config */
|
||||
$config = $c['config'];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $c['locator'];
|
||||
|
||||
// Set locator to both streams.
|
||||
Stream::setLocator($locator);
|
||||
ReadOnlyStream::setLocator($locator);
|
||||
|
||||
return new StreamBuilder($this->schemes);
|
||||
return new StreamBuilder($config->getStreams($c));
|
||||
};
|
||||
}
|
||||
|
||||
protected function init(Container $container, UniformResourceLocator $locator)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = $container['config'];
|
||||
$schemes = (array) $config->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
}
|
||||
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$this->schemes[$scheme] = $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,9 +125,6 @@ class Twig
|
||||
|
||||
$this->grav->fireEvent('onTwigExtensions');
|
||||
|
||||
$theme = $config->get('system.pages.theme');
|
||||
$themeUrl = $this->grav['base_url'] .'/'. USER_PATH . basename(THEMES_DIR) .'/'. $theme;
|
||||
|
||||
// Set some standard variables for twig
|
||||
$this->twig_vars = array(
|
||||
'grav' => $this->grav,
|
||||
@@ -138,7 +135,7 @@ class Twig
|
||||
'base_url_absolute' => $this->grav['base_url_absolute'],
|
||||
'base_url_relative' => $this->grav['base_url_relative'],
|
||||
'theme_dir' => $locator->findResource('theme://'),
|
||||
'theme_url' => $themeUrl,
|
||||
'theme_url' => $this->grav['base_url'] .'/'. $locator->findResource('theme://', false),
|
||||
'site' => $config->get('site'),
|
||||
'assets' => $this->grav['assets'],
|
||||
'taxonomy' => $this->grav['taxonomy'],
|
||||
|
||||
@@ -331,19 +331,32 @@ class TwigExtension extends \Twig_Extension
|
||||
/**
|
||||
* Return URL to the resource.
|
||||
*
|
||||
* @param string $input
|
||||
* @param bool $domain
|
||||
* @return string
|
||||
* @example {{ url('theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4') }}
|
||||
*
|
||||
* @param string $input Resource to be located.
|
||||
* @param bool $domain True to include domain name.
|
||||
* @return string|null Returns url to the resource or null if resource was not found.
|
||||
*/
|
||||
public function urlFunc($input, $domain = false)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
if (!trim((string) $input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strpos((string) $input, '://')) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
// Get relative path to the resource (or false if not found).
|
||||
$resource = $locator->findResource((string) $input, false);
|
||||
} else {
|
||||
$resource = (string) $input;
|
||||
}
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = $this->grav['uri'];
|
||||
|
||||
return $uri->rootUrl($domain) .'/'. $locator->findResource($input, false);
|
||||
return $resource ? rtrim($uri->rootUrl($domain), '/') . '/' . $resource : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Grav\Common\User;
|
||||
use Grav\Common\Data\Blueprints;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
|
||||
/**
|
||||
* User object
|
||||
@@ -13,6 +14,8 @@ use Grav\Common\File\CompiledYamlFile;
|
||||
*/
|
||||
class User extends Data
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* Load user account.
|
||||
*
|
||||
@@ -23,10 +26,13 @@ class User extends Data
|
||||
*/
|
||||
public static function load($username)
|
||||
{
|
||||
$locator = self::$grav['locator'];
|
||||
|
||||
// FIXME: validate directory name
|
||||
$blueprints = new Blueprints('blueprints://user');
|
||||
$blueprint = $blueprints->get('account');
|
||||
$file = CompiledYamlFile::instance(ACCOUNTS_DIR . $username . YAML_EXT);
|
||||
$file_path = $locator->findResource('account://' . $username . YAML_EXT);
|
||||
$file = CompiledYamlFile::instance($file_path);
|
||||
$content = $file->content();
|
||||
if (!isset($content['username'])) {
|
||||
$content['username'] = $username;
|
||||
|
||||
@@ -73,6 +73,7 @@ class CleanCommand extends Command
|
||||
'vendor/gregwar/image/Gregwar/Image/phpunit.xml',
|
||||
'vendor/gregwar/image/Gregwar/Image/.gitignore',
|
||||
'vendor/gregwar/image/Gregwar/Image/.git',
|
||||
'vendor/gregwar/image/Gregwar/Image/doc',
|
||||
'vendor/gregwar/image/Gregwar/Image/demo',
|
||||
'vendor/gregwar/image/Gregwar/Image/tests',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/composer.json',
|
||||
@@ -90,6 +91,10 @@ class CleanCommand extends Command
|
||||
'vendor/maximebf/debugbar/composer.json',
|
||||
'vendor/maximebf/debugbar/.bowerrc',
|
||||
'vendor/maximebf/debugbar/src/Debugbar/Resources/vendor',
|
||||
'vendor/maximebf/debugbar/demo',
|
||||
'vendor/maximebf/debugbar/docs',
|
||||
'vendor/maximebf/debugbar/tests',
|
||||
'vendor/maximebf/debugbar/phpunit.xml.dist',
|
||||
'vendor/monolog/monolog/composer.json',
|
||||
'vendor/monolog/monolog/doc',
|
||||
'vendor/monolog/monolog/phpunit.xml.dist',
|
||||
|
||||
0
system/tests/Grav/Test/.gitkeep
Normal file
0
system/tests/Grav/Test/.gitkeep
Normal file
8
system/tests/Grav/TestCase.php
Normal file
8
system/tests/Grav/TestCase.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace Grav;
|
||||
|
||||
|
||||
class TestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
}
|
||||
6
system/tests/bootstrap.php
Normal file
6
system/tests/bootstrap.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
date_default_timezone_set(@date_default_timezone_get());
|
||||
require_once __DIR__.'/../../vendor/autoload.php';
|
||||
require_once __DIR__.'/Grav/TestCase.php';
|
||||
18
system/tests/phpunit.xml
Normal file
18
system/tests/phpunit.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="./bootstrap.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Full Grav Test Suite">
|
||||
<directory>./Grav/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
Reference in New Issue
Block a user