mirror of
https://github.com/getgrav/grav.git
synced 2025-10-26 07:56:07 +01:00
Added stream support for images ()
Added stream support for links (`[Download PDF](user://data/pdf/my.pdf)`)
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
* Add `ignore_empty` property to be used on array fields, if positive only save options with a value
|
||||
* Use new `permissions` field in user account
|
||||
* Add `range(int start, int end, int step)` twig function to generate an array of numbers between start and end, inclusive
|
||||
* New retina Media image derivatives array support (` [#1147](https://github.com/getgrav/grav/pull/1147)
|
||||
* New retina Media image derivatives array support (``) [#1147](https://github.com/getgrav/grav/pull/1147)
|
||||
* Added stream support for images (``)
|
||||
* Added stream support for links (`[Download PDF](user://data/pdf/my.pdf)`)
|
||||
1. [](#improved)
|
||||
* Added alias `selfupdate` to the `self-upgrade` `bin/gpm` CLI command
|
||||
* Synced `webserver-configs/htaccess.txt` with `.htaccess`
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace Grav\Common\Helpers;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Common\Page\Medium\Medium;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class Excerpts
|
||||
{
|
||||
@@ -115,11 +115,11 @@ class Excerpts
|
||||
*/
|
||||
public static function processLinkExcerpt($excerpt, $page, $type = 'link')
|
||||
{
|
||||
$url = $excerpt['element']['attributes']['href'];
|
||||
$url = htmlspecialchars_decode(urldecode($excerpt['element']['attributes']['href']));
|
||||
|
||||
$url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
|
||||
$url_parts = static::parseUrl($url);
|
||||
|
||||
// if there is a query, then parse it and build action calls
|
||||
// If there is a query, then parse it and build action calls.
|
||||
if (isset($url_parts['query'])) {
|
||||
$actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
|
||||
$parts = explode('=', $item, 2);
|
||||
@@ -129,19 +129,19 @@ class Excerpts
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
// valid attributes supported
|
||||
// Valid attributes supported.
|
||||
$valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];
|
||||
|
||||
// Unless told to not process, go through actions
|
||||
// Unless told to not process, go through actions.
|
||||
if (array_key_exists('noprocess', $actions)) {
|
||||
unset($actions['noprocess']);
|
||||
} else {
|
||||
// loop through actions for the image and call them
|
||||
// Loop through actions for the image and call them.
|
||||
foreach ($actions as $attrib => $value) {
|
||||
$key = $attrib;
|
||||
|
||||
if (in_array($attrib, $valid_attributes)) {
|
||||
// support both class and classes
|
||||
// support both class and classes.
|
||||
if ($attrib == 'classes') {
|
||||
$attrib = 'class';
|
||||
}
|
||||
@@ -154,25 +154,33 @@ class Excerpts
|
||||
$url_parts['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
// if no query elements left, unset query
|
||||
// If no query elements left, unset query.
|
||||
if (empty($url_parts['query'])) {
|
||||
unset ($url_parts['query']);
|
||||
}
|
||||
|
||||
// set path to / if not set
|
||||
// Set path to / if not set.
|
||||
if (empty($url_parts['path'])) {
|
||||
$url_parts['path'] = '';
|
||||
}
|
||||
|
||||
// if special scheme, just return
|
||||
if(isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) {
|
||||
// If scheme isn't http(s)..
|
||||
if (!empty($url_parts['scheme']) && !in_array($url_parts['scheme'], ['http', 'https'])) {
|
||||
// Handle custom streams.
|
||||
if ($type !== 'image' && !empty($url_parts['stream']) && !empty($url_parts['path'])) {
|
||||
$url_parts['path'] = Grav::instance()['base_url_relative'] . '/' . static::resolveStream("{$url_parts['scheme']}://{$url_parts['path']}");
|
||||
unset($url_parts['stream'], $url_parts['scheme']);
|
||||
|
||||
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
// handle paths and such
|
||||
// Handle paths and such.
|
||||
$url_parts = Uri::convertUrl($page, $url_parts, $type);
|
||||
|
||||
// build the URL from the component parts and set it on the element
|
||||
// Build the URL from the component parts and set it on the element.
|
||||
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
|
||||
|
||||
return $excerpt;
|
||||
@@ -187,62 +195,65 @@ class Excerpts
|
||||
*/
|
||||
public static function processImageExcerpt($excerpt, $page)
|
||||
{
|
||||
$url = $excerpt['element']['attributes']['src'];
|
||||
$url = htmlspecialchars_decode(urldecode($excerpt['element']['attributes']['src']));
|
||||
$url_parts = static::parseUrl($url);
|
||||
|
||||
$url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
|
||||
$media = null;
|
||||
$filename = null;
|
||||
|
||||
if (isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) {
|
||||
$stream_path = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];
|
||||
$url_parts['path'] = $stream_path;
|
||||
unset($url_parts['host']);
|
||||
unset($url_parts['scheme']);
|
||||
}
|
||||
if (!empty($url_parts['stream'])) {
|
||||
$filename = $url_parts['scheme'] . '://' . (isset($url_parts['path']) ? $url_parts['path'] : '');
|
||||
|
||||
$this_host = isset($url_parts['host']) && $url_parts['host'] == Grav::instance()['uri']->host();
|
||||
$media = $page->media();
|
||||
|
||||
// if there is no host set but there is a path, the file is local
|
||||
if ((!isset($url_parts['host']) || $this_host) && isset($url_parts['path'])) {
|
||||
} else {
|
||||
// File is also local if scheme is http(s) and host matches.
|
||||
$local_file = isset($url_parts['path'])
|
||||
&& (empty($url_parts['scheme']) || in_array($url_parts['scheme'], ['http', 'https']))
|
||||
&& (empty($url_parts['host']) || $url_parts['host'] == Grav::instance()['uri']->host());
|
||||
|
||||
$path_parts = pathinfo($url_parts['path']);
|
||||
$media = null;
|
||||
if ($local_file) {
|
||||
$filename = basename($url_parts['path']);
|
||||
$folder = dirname($url_parts['path']);
|
||||
|
||||
// get the local path to page media if possible
|
||||
if ($path_parts['dirname'] == $page->url(false, false, false)) {
|
||||
// get the media objects for this page
|
||||
$media = $page->media();
|
||||
} else {
|
||||
// see if this is an external page to this one
|
||||
$base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
|
||||
$page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/');
|
||||
|
||||
$ext_page = Grav::instance()['pages']->dispatch($page_route, true);
|
||||
if ($ext_page) {
|
||||
$media = $ext_page->media();
|
||||
// Get the local path to page media if possible.
|
||||
if ($folder === $page->url(false, false, false)) {
|
||||
// Get the media objects for this page.
|
||||
$media = $page->media();
|
||||
} else {
|
||||
Grav::instance()->fireEvent('onMediaLocate', new Event(['route' => $page_route, 'media' => &$media]));
|
||||
// see if this is an external page to this one
|
||||
$base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
|
||||
$page_route = '/' . ltrim(str_replace($base_url, '', $folder), '/');
|
||||
|
||||
$ext_page = Grav::instance()['pages']->dispatch($page_route, true);
|
||||
if ($ext_page) {
|
||||
$media = $ext_page->media();
|
||||
} else {
|
||||
Grav::instance()->fireEvent('onMediaLocate', new Event(['route' => $page_route, 'media' => &$media]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a media file that matches the path referenced..
|
||||
if ($media && isset($media->all()[$path_parts['basename']])) {
|
||||
// get the medium object
|
||||
/** @var Medium $medium */
|
||||
$medium = $media->all()[$path_parts['basename']];
|
||||
// If there is a media file that matches the path referenced..
|
||||
if ($media && $filename && isset($media[$filename])) {
|
||||
// Get the medium object.
|
||||
/** @var Medium $medium */
|
||||
$medium = $media[$filename];
|
||||
|
||||
// Process operations
|
||||
$medium = static::processMediaActions($medium, $url_parts);
|
||||
// Process operations
|
||||
$medium = static::processMediaActions($medium, $url_parts);
|
||||
|
||||
$alt = isset($excerpt['element']['attributes']['alt']) ? $excerpt['element']['attributes']['alt'] : '';
|
||||
$title = isset($excerpt['element']['attributes']['title']) ? $excerpt['element']['attributes']['title'] : '';
|
||||
$class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
|
||||
$id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
|
||||
$alt = isset($excerpt['element']['attributes']['alt']) ? $excerpt['element']['attributes']['alt'] : '';
|
||||
$title = isset($excerpt['element']['attributes']['title']) ? $excerpt['element']['attributes']['title'] : '';
|
||||
$class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
|
||||
$id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
|
||||
|
||||
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
|
||||
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
|
||||
|
||||
} else {
|
||||
// not a current page media file, see if it needs converting to relative
|
||||
$excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
} else {
|
||||
// Not a current page media file, see if it needs converting to relative.
|
||||
$excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts);
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
@@ -300,4 +311,40 @@ class Excerpts
|
||||
return $medium;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of parse_url() which works also with local streams.
|
||||
*
|
||||
* @param string $url
|
||||
* @return array|bool
|
||||
*/
|
||||
protected static function parseUrl($url)
|
||||
{
|
||||
$url_parts = parse_url($url);
|
||||
|
||||
if (isset($url_parts['scheme'])) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
// Special handling for the streams.
|
||||
if ($locator->schemeExists($url_parts['scheme'])) {
|
||||
if (isset($url_parts['host'])) {
|
||||
// Merge host and path into a path.
|
||||
$url_parts['path'] = $url_parts['host'] . (isset($url_parts['path']) ? '/' . $url_parts['path'] : '');
|
||||
unset($url_parts['host']);
|
||||
}
|
||||
|
||||
$url_parts['stream'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $url_parts;
|
||||
}
|
||||
|
||||
protected static function resolveStream($url)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
return $locator->isStream($url) ? ($locator->findResource($url, false) ?: $locator->findResource($url, false, true)) : $url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,51 +8,78 @@
|
||||
|
||||
namespace Grav\Common\Page;
|
||||
|
||||
use Grav\Common\Getters;
|
||||
use Grav\Common\Page\Medium\Medium;
|
||||
use Grav\Common\Page\Medium\AbstractMedia;
|
||||
use Grav\Common\Page\Medium\GlobalMedia;
|
||||
use Grav\Common\Page\Medium\MediumFactory;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class Media extends Getters
|
||||
class Media extends AbstractMedia
|
||||
{
|
||||
protected $gettersVariable = 'instances';
|
||||
protected static $global;
|
||||
|
||||
protected $path;
|
||||
|
||||
protected $instances = [];
|
||||
protected $images = [];
|
||||
protected $videos = [];
|
||||
protected $audios = [];
|
||||
protected $files = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
*/
|
||||
public function __construct($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
if (!isset(static::$global)) {
|
||||
// Add fallback to global media.
|
||||
static::$global = new GlobalMedia($path);
|
||||
}
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return parent::offsetExists($offset) ?: isset(static::$global[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return parent::offsetGet($offset) ?: static::$global[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize class.
|
||||
*/
|
||||
protected function init()
|
||||
{
|
||||
|
||||
// Handle special cases where page doesn't exist in filesystem.
|
||||
if (!is_dir($path)) {
|
||||
if (!is_dir($this->path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
$iterator = new \FilesystemIterator($path, \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS);
|
||||
$iterator = new \FilesystemIterator($this->path, \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS);
|
||||
|
||||
$media = [];
|
||||
|
||||
/** @var \DirectoryIterator $info */
|
||||
foreach ($iterator as $path => $info) {
|
||||
// Ignore folders and Markdown files.
|
||||
if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename() === '.DS_Store') {
|
||||
if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename()[0] === '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find out what type we're dealing with
|
||||
list($basename, $ext, $type, $extra) = $this->getFileParts($info->getFilename());
|
||||
|
||||
$media["{$basename}.{$ext}"] = isset($media["{$basename}.{$ext}"]) ? $media["{$basename}.{$ext}"] : [];
|
||||
|
||||
if ($type === 'alternative') {
|
||||
$media["{$basename}.{$ext}"][$type] = isset($media["{$basename}.{$ext}"][$type]) ? $media["{$basename}.{$ext}"][$type] : [];
|
||||
$media["{$basename}.{$ext}"][$type][$extra] = [ 'file' => $path, 'size' => $info->getSize() ];
|
||||
} else {
|
||||
$media["{$basename}.{$ext}"][$type] = [ 'file' => $path, 'size' => $info->getSize() ];
|
||||
@@ -124,134 +151,4 @@ class Media extends Getters
|
||||
$this->add($name, $medium);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get medium by filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return Medium|null
|
||||
*/
|
||||
public function get($filename)
|
||||
{
|
||||
return isset($this->instances[$filename]) ? $this->instances[$filename] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all image media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function images()
|
||||
{
|
||||
ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all video media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all audio media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->audios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all file media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function add($name, $file)
|
||||
{
|
||||
$this->instances[$name] = $file;
|
||||
switch ($file->type) {
|
||||
case 'image':
|
||||
$this->images[$name] = $file;
|
||||
break;
|
||||
case 'video':
|
||||
$this->videos[$name] = $file;
|
||||
break;
|
||||
case 'audio':
|
||||
$this->audios[$name] = $file;
|
||||
break;
|
||||
default:
|
||||
$this->files[$name] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename, extension and meta part.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileParts($filename)
|
||||
{
|
||||
$fileParts = explode('.', $filename);
|
||||
|
||||
$name = array_shift($fileParts);
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
|
||||
if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
|
||||
$name = $matches[1];
|
||||
$extension = $matches[3];
|
||||
$extra = (int) $matches[2];
|
||||
$type = 'alternative';
|
||||
|
||||
if ($extra === 1) {
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
}
|
||||
} else {
|
||||
$extension = null;
|
||||
while (($part = array_shift($fileParts)) !== null) {
|
||||
if ($part != 'meta' && $part != 'thumb') {
|
||||
if (isset($extension)) {
|
||||
$name .= '.' . $extension;
|
||||
}
|
||||
$extension = $part;
|
||||
} else {
|
||||
$type = $part;
|
||||
$extra = '.' . $part . '.' . implode('.', $fileParts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($name, $extension, $type, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
154
system/src/Grav/Common/Page/Medium/AbstractMedia.php
Normal file
154
system/src/Grav/Common/Page/Medium/AbstractMedia.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Page
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Getters;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
abstract class AbstractMedia extends Getters
|
||||
{
|
||||
protected $gettersVariable = 'instances';
|
||||
|
||||
protected $instances = [];
|
||||
protected $images = [];
|
||||
protected $videos = [];
|
||||
protected $audios = [];
|
||||
protected $files = [];
|
||||
|
||||
/**
|
||||
* Get medium by filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return Medium|null
|
||||
*/
|
||||
public function get($filename)
|
||||
{
|
||||
return $this->offsetGet($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all image media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function images()
|
||||
{
|
||||
ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all video media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all audio media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->audios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all file media.
|
||||
*
|
||||
* @return array|Medium[]
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param Medium $file
|
||||
*/
|
||||
protected function add($name, $file)
|
||||
{
|
||||
$this->instances[$name] = $file;
|
||||
switch ($file->type) {
|
||||
case 'image':
|
||||
$this->images[$name] = $file;
|
||||
break;
|
||||
case 'video':
|
||||
$this->videos[$name] = $file;
|
||||
break;
|
||||
case 'audio':
|
||||
$this->audios[$name] = $file;
|
||||
break;
|
||||
default:
|
||||
$this->files[$name] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename, extension and meta part.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileParts($filename)
|
||||
{
|
||||
if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
|
||||
$name = $matches[1];
|
||||
$extension = $matches[3];
|
||||
$extra = (int) $matches[2];
|
||||
$type = 'alternative';
|
||||
|
||||
if ($extra === 1) {
|
||||
$type = 'base';
|
||||
$extra = null;
|
||||
}
|
||||
} else {
|
||||
$fileParts = explode('.', $filename);
|
||||
|
||||
$name = array_shift($fileParts);
|
||||
$extension = null;
|
||||
$extra = null;
|
||||
$type = 'base';
|
||||
|
||||
while (($part = array_shift($fileParts)) !== null) {
|
||||
if ($part != 'meta' && $part != 'thumb') {
|
||||
if (isset($extension)) {
|
||||
$name .= '.' . $extension;
|
||||
}
|
||||
$extension = $part;
|
||||
} else {
|
||||
$type = $part;
|
||||
$extra = '.' . $part . '.' . implode('.', $fileParts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($name, $extension, $type, $extra);
|
||||
}
|
||||
}
|
||||
117
system/src/Grav/Common/Page/Medium/GlobalMedia.php
Normal file
117
system/src/Grav/Common/Page/Medium/GlobalMedia.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav.Common.Page
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2016 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class GlobalMedia extends AbstractMedia
|
||||
{
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return parent::offsetExists($offset) ?: !empty($this->resolveStream($offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return parent::offsetGet($offset) ?: $this->addMedium($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string|null
|
||||
*/
|
||||
protected function resolveStream($filename)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
return $locator->isStream($filename) ? ($locator->findResource($filename) ?: null) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $stream
|
||||
* @return Medium|null
|
||||
*/
|
||||
protected function addMedium($stream)
|
||||
{
|
||||
$filename = $this->resolveStream($stream);
|
||||
if (!$filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = dirname($filename);
|
||||
list($basename, $ext,, $extra) = $this->getFileParts(basename($filename));
|
||||
$medium = MediumFactory::fromFile($filename);
|
||||
|
||||
if (empty($medium)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$medium->set('size', filesize($filename));
|
||||
$scale = (int) ($extra ?: 1);
|
||||
|
||||
if ($scale !== 1) {
|
||||
$altMedium = $medium;
|
||||
|
||||
// Create scaled down regular sized image.
|
||||
$medium = MediumFactory::scaledFromMedium($altMedium, $scale, 1)['file'];
|
||||
|
||||
if (empty($medium)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add original sized image as alternative.
|
||||
$medium->addAlternative($scale, $altMedium['file']);
|
||||
|
||||
// Locate or generate smaller retina images.
|
||||
for ($i = $scale-1; $i > 1; $i--) {
|
||||
$altFilename = "{$path}/{$basename}@{$i}x.{$ext}";
|
||||
|
||||
if (file_exists($altFilename)) {
|
||||
$scaled = MediumFactory::fromFile($altFilename);
|
||||
} else {
|
||||
$scaled = MediumFactory::scaledFromMedium($altMedium, $scale, $i)['file'];
|
||||
}
|
||||
|
||||
if ($scaled) {
|
||||
$medium->addAlternative($i, $scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$meta = "{$path}/{$basename}.{$ext}.yaml";
|
||||
if (file_exists($meta)) {
|
||||
$medium->addMetaFile($meta);
|
||||
}
|
||||
$meta = "{$path}/{$basename}.{$ext}.meta.yaml";
|
||||
if (file_exists($meta)) {
|
||||
$medium->addMetaFile($meta);
|
||||
}
|
||||
|
||||
$thumb = "{$path}/{$basename}.thumb.{$ext}";
|
||||
if (file_exists($thumb)) {
|
||||
$medium->set('thumbnails.page', $thumb);
|
||||
}
|
||||
|
||||
$this->add($stream, $medium);
|
||||
|
||||
return $medium;
|
||||
}
|
||||
}
|
||||
@@ -150,8 +150,8 @@ class Medium extends Data implements RenderableInterface
|
||||
/**
|
||||
* Get/set querystring for the file's url
|
||||
*
|
||||
* @param string $hash
|
||||
* @param boolean $withHash
|
||||
* @param string $querystring
|
||||
* @param boolean $withQuestionmark
|
||||
* @return string
|
||||
*/
|
||||
public function querystring($querystring = null, $withQuestionmark = true)
|
||||
|
||||
Reference in New Issue
Block a user