mirror of
https://github.com/getgrav/grav.git
synced 2025-02-20 19:56:53 +01:00
Split Medium classes into traits, define Media interfaces
This commit is contained in:
parent
d25014779d
commit
8b47608cc0
|
|
@ -103,9 +103,9 @@
|
|||
"api-16": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.16.md",
|
||||
"api-15": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.md",
|
||||
"post-create-project-cmd": "bin/grav install",
|
||||
"phpstan": "vendor/bin/phpstan analyse -l 3 -c ./tests/phpstan/phpstan.neon system/src --memory-limit=340M",
|
||||
"phpstan-framework": "vendor/bin/phpstan analyse -l 7 -c ./tests/phpstan/phpstan.neon system/src/Grav/Framework --memory-limit=128M",
|
||||
"phpstan-plugins": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/plugins.neon user/plugins --memory-limit=300M",
|
||||
"phpstan": "vendor/bin/phpstan analyse -l 3 -c ./tests/phpstan/phpstan.neon --memory-limit=340M system/src",
|
||||
"phpstan-framework": "vendor/bin/phpstan analyse -l 7 -c ./tests/phpstan/phpstan.neon --memory-limit=128M system/src/Grav/Framework",
|
||||
"phpstan-plugins": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/plugins.neon --memory-limit=300M user/plugins",
|
||||
"test": "vendor/bin/codecept run unit",
|
||||
"test-windows": "vendor\\bin\\codecept run unit"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements audio media interface.
|
||||
*/
|
||||
interface AudioMediaInterface extends MediaObjectInterface, MediaPlayerInterface
|
||||
{
|
||||
/**
|
||||
* Allows to set the controlsList behaviour
|
||||
* Separate multiple values with a hyphen
|
||||
*
|
||||
* @param string $controlsList
|
||||
* @return $this
|
||||
*/
|
||||
public function controlsList($controlsList);
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements image manipulation interface.
|
||||
*/
|
||||
interface ImageManipulateInterface
|
||||
{
|
||||
/**
|
||||
* Allows the ability to override the image's pretty name stored in cache
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setImagePrettyName($name);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getImagePrettyName();
|
||||
|
||||
/**
|
||||
* Simply processes with no extra methods. Useful for triggering events.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cache();
|
||||
|
||||
/**
|
||||
* Generate alternative image widths, using either an array of integers, or
|
||||
* a min width, a max width, and a step parameter to fill out the necessary
|
||||
* widths. Existing image alternatives won't be overwritten.
|
||||
*
|
||||
* @param int|int[] $min_width
|
||||
* @param int $max_width
|
||||
* @param int $step
|
||||
* @return $this
|
||||
*/
|
||||
public function derivatives($min_width, $max_width = 2500, $step = 200);
|
||||
|
||||
/**
|
||||
* Clear out the alternatives.
|
||||
*/
|
||||
public function clearAlternatives();
|
||||
|
||||
/**
|
||||
* Sets or gets the quality of the image
|
||||
*
|
||||
* @param int $quality 0-100 quality
|
||||
* @return int|$this
|
||||
*/
|
||||
public function quality($quality = null);
|
||||
|
||||
/**
|
||||
* Sets image output format.
|
||||
*
|
||||
* @param string $format
|
||||
* @return $this
|
||||
*/
|
||||
public function format($format);
|
||||
|
||||
/**
|
||||
* Set or get sizes parameter for srcset media action
|
||||
*
|
||||
* @param string $sizes
|
||||
* @return string
|
||||
*/
|
||||
public function sizes($sizes = null);
|
||||
|
||||
/**
|
||||
* Allows to set the width attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the width of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function width($value = 'auto');
|
||||
|
||||
/**
|
||||
* Allows to set the height attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the height of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function height($value = 'auto');
|
||||
|
||||
/* *
|
||||
* Filter image by using user defined filter parameters.
|
||||
*
|
||||
* @param string $filter Filter to be used.
|
||||
* @return $this
|
||||
* FIXME: Conflicts against Data class
|
||||
*/
|
||||
//public function filter($filter = 'image.filters.default');
|
||||
|
||||
/**
|
||||
* Return the image higher quality version
|
||||
*
|
||||
* @return ImageMediaInterface the alternative version with higher quality
|
||||
*/
|
||||
public function higherQualityAlternative();
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements image media interface.
|
||||
*/
|
||||
interface ImageMediaInterface extends MediaObjectInterface
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements media file interface.
|
||||
*/
|
||||
interface MediaFileInterface extends MediaObjectInterface
|
||||
{
|
||||
/**
|
||||
* Check if this medium exists or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists();
|
||||
|
||||
/**
|
||||
* Get file modification time for the medium.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function modified();
|
||||
|
||||
/**
|
||||
* Get size of the medium.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function size();
|
||||
|
||||
/**
|
||||
* Return the path to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string path to file
|
||||
*/
|
||||
public function path($reset = true);
|
||||
|
||||
/**
|
||||
* Return the relative path to file
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return mixed
|
||||
*/
|
||||
public function relativePath($reset = true);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements media file interface.
|
||||
*/
|
||||
interface MediaLinkInterface
|
||||
{
|
||||
}
|
||||
|
|
@ -9,9 +9,219 @@
|
|||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
/**
|
||||
* Class implements media object interface.
|
||||
*/
|
||||
interface MediaObjectInterface extends \Grav\Framework\Media\Interfaces\MediaObjectInterface
|
||||
{
|
||||
/**
|
||||
* Create a copy of this media object
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function copy();
|
||||
|
||||
/**
|
||||
* Return just metadata from the Medium object
|
||||
*
|
||||
* @return Data
|
||||
*/
|
||||
public function meta();
|
||||
|
||||
/**
|
||||
* Set querystring to file modification timestamp (or value provided as a parameter).
|
||||
*
|
||||
* @param string|int|null $timestamp
|
||||
* @return $this
|
||||
*/
|
||||
public function setTimestamp($timestamp = null);
|
||||
|
||||
/**
|
||||
* Returns an array containing just the metadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function metadata();
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
* @param string $filepath
|
||||
*/
|
||||
public function addMetaFile($filepath);
|
||||
|
||||
/**
|
||||
* Add alternative Medium to this Medium.
|
||||
*
|
||||
* @param int|float $ratio
|
||||
* @param MediaObjectInterface $alternative
|
||||
*/
|
||||
public function addAlternative($ratio, MediaObjectInterface $alternative);
|
||||
|
||||
/**
|
||||
* Return string representation of the object (html).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Get/set querystring for the file's url
|
||||
*
|
||||
* @param string|null $querystring
|
||||
* @param bool $withQuestionmark
|
||||
* @return string
|
||||
*/
|
||||
public function querystring($querystring = null, $withQuestionmark = true);
|
||||
|
||||
/**
|
||||
* Get the URL with full querystring
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function urlQuerystring($url);
|
||||
|
||||
/**
|
||||
* Get/set hash for the file's url
|
||||
*
|
||||
* @param string $hash
|
||||
* @param bool $withHash
|
||||
* @return string
|
||||
*/
|
||||
public function urlHash($hash = null, $withHash = true);
|
||||
|
||||
/**
|
||||
* Get an element (is array) that can be rendered by the Parsedown engine
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function parsedownElement($title = null, $alt = null, $class = null, $id = null, $reset = true);
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reset();
|
||||
|
||||
/**
|
||||
* Switch display mode.
|
||||
*
|
||||
* @param string $mode
|
||||
*
|
||||
* @return MediaObjectInterface|null
|
||||
*/
|
||||
public function display($mode = 'source');
|
||||
|
||||
/**
|
||||
* Helper method to determine if this media item has a thumbnail or not
|
||||
*
|
||||
* @param string $type;
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function thumbnailExists($type = 'page');
|
||||
|
||||
/**
|
||||
* Switch thumbnail.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function thumbnail($type = 'auto');
|
||||
|
||||
/**
|
||||
* Return URL to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function url($reset = true);
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function link($reset = true, array $attributes = []);
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link with lightbox enabled
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true);
|
||||
|
||||
/**
|
||||
* Add a class to the element from Markdown or Twig
|
||||
* Example:  or 
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function classes();
|
||||
|
||||
/**
|
||||
* Add an id to the element from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $id
|
||||
* @return $this
|
||||
*/
|
||||
public function id($id);
|
||||
|
||||
/**
|
||||
* Allows to add an inline style attribute from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $style
|
||||
* @return $this
|
||||
*/
|
||||
public function style($style);
|
||||
|
||||
/**
|
||||
* Allow any action to be called on this medium from twig or markdown
|
||||
*
|
||||
* @param string $method
|
||||
* @param mixed $args
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $args);
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $this->get('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function get($name, $default = null, $separator = null);
|
||||
|
||||
/**
|
||||
* Set value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->set('this.is.my.nested.variable', $value);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function set($name, $value, $separator = null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements media player interface.
|
||||
*/
|
||||
interface MediaPlayerInterface extends MediaObjectInterface
|
||||
{
|
||||
/**
|
||||
* Allows to set or remove the HTML5 default controls
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function controls($status = true);
|
||||
|
||||
/**
|
||||
* Allows to set the loop attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function loop($status = false);
|
||||
|
||||
/**
|
||||
* Allows to set the autoplay attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function autoplay($status = false);
|
||||
|
||||
/**
|
||||
* Allows to set the muted attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function muted($status = false);
|
||||
|
||||
/**
|
||||
* Allows to set the preload behaviour
|
||||
*
|
||||
* @param string|null $preload
|
||||
* @return $this
|
||||
*/
|
||||
public function preload($preload = null);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Interfaces;
|
||||
|
||||
/**
|
||||
* Class implements video media interface.
|
||||
*/
|
||||
interface VideoMediaInterface extends MediaObjectInterface, MediaPlayerInterface
|
||||
{
|
||||
/**
|
||||
* Allows to set the video's poster image
|
||||
*
|
||||
* @param string $urlImage
|
||||
* @return $this
|
||||
*/
|
||||
public function poster($urlImage);
|
||||
|
||||
/**
|
||||
* Allows to set the playsinline attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function playsinline($status = false);
|
||||
}
|
||||
49
system/src/Grav/Common/Media/Traits/AudioMediaTrait.php
Normal file
49
system/src/Grav/Common/Media/Traits/AudioMediaTrait.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
trait AudioMediaTrait
|
||||
{
|
||||
use StaticResizeTrait;
|
||||
use MediaPlayerTrait;
|
||||
|
||||
/**
|
||||
* Allows to set the controlsList behaviour
|
||||
* Separate multiple values with a hyphen
|
||||
*
|
||||
* @param string $controlsList
|
||||
* @return $this
|
||||
*/
|
||||
public function controlsList($controlsList)
|
||||
{
|
||||
$controlsList = str_replace('-', ' ', $controlsList);
|
||||
$this->attributes['controlsList'] = $controlsList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
$location = $this->url($reset);
|
||||
|
||||
return [
|
||||
'name' => 'audio',
|
||||
'rawHtml' => '<source src="' . $location . '">Your browser does not support the audio tag.',
|
||||
'attributes' => $attributes
|
||||
];
|
||||
}
|
||||
}
|
||||
381
system/src/Grav/Common/Media/Traits/ImageMediaTrait.php
Normal file
381
system/src/Grav/Common/Media/Traits/ImageMediaTrait.php
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Media\Interfaces\ImageMediaInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface;
|
||||
use Grav\Common\Page\Medium\ImageFile;
|
||||
use Grav\Common\Page\Medium\ImageMedium;
|
||||
use Grav\Common\Page\Medium\MediumFactory;
|
||||
|
||||
trait ImageMediaTrait
|
||||
{
|
||||
/** @var ImageFile|null */
|
||||
protected $image;
|
||||
|
||||
/** @var string */
|
||||
protected $format = 'guess';
|
||||
|
||||
/** @var int */
|
||||
protected $quality;
|
||||
|
||||
/** @var int */
|
||||
protected $default_quality;
|
||||
|
||||
/** @var bool */
|
||||
protected $debug_watermarked = false;
|
||||
|
||||
/** @var array */
|
||||
public static $magic_actions = [
|
||||
'resize', 'forceResize', 'cropResize', 'crop', 'zoomCrop',
|
||||
'negate', 'brightness', 'contrast', 'grayscale', 'emboss',
|
||||
'smooth', 'sharp', 'edge', 'colorize', 'sepia', 'enableProgressive',
|
||||
'rotate', 'flip', 'fixOrientation', 'gaussianBlur'
|
||||
];
|
||||
|
||||
/** @var array */
|
||||
public static $magic_resize_actions = [
|
||||
'resize' => [0, 1],
|
||||
'forceResize' => [0, 1],
|
||||
'cropResize' => [0, 1],
|
||||
'crop' => [0, 1, 2, 3],
|
||||
'zoomCrop' => [0, 1]
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
protected $sizes = '100vw';
|
||||
|
||||
|
||||
/**
|
||||
* Allows the ability to override the image's pretty name stored in cache
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setImagePrettyName($name)
|
||||
{
|
||||
$this->set('prettyname', $name);
|
||||
if ($this->image) {
|
||||
$this->image->setPrettyName($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getImagePrettyName()
|
||||
{
|
||||
if ($this->get('prettyname')) {
|
||||
return $this->get('prettyname');
|
||||
}
|
||||
|
||||
$basename = $this->get('basename');
|
||||
if (preg_match('/[a-z0-9]{40}-(.*)/', $basename, $matches)) {
|
||||
$basename = $matches[1];
|
||||
}
|
||||
return $basename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply processes with no extra methods. Useful for triggering events.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cache()
|
||||
{
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alternative image widths, using either an array of integers, or
|
||||
* a min width, a max width, and a step parameter to fill out the necessary
|
||||
* widths. Existing image alternatives won't be overwritten.
|
||||
*
|
||||
* @param int|int[] $min_width
|
||||
* @param int $max_width
|
||||
* @param int $step
|
||||
* @return $this
|
||||
*/
|
||||
public function derivatives($min_width, $max_width = 2500, $step = 200)
|
||||
{
|
||||
if (!empty($this->alternatives)) {
|
||||
$max = max(array_keys($this->alternatives));
|
||||
$base = $this->alternatives[$max];
|
||||
} else {
|
||||
$base = $this;
|
||||
}
|
||||
|
||||
$widths = [];
|
||||
|
||||
if (func_num_args() === 1) {
|
||||
foreach ((array) func_get_arg(0) as $width) {
|
||||
if ($width < $base->get('width')) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$max_width = min($max_width, $base->get('width'));
|
||||
|
||||
for ($width = $min_width; $width < $max_width; $width += $step) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($widths as $width) {
|
||||
// Only generate image alternatives that don't already exist
|
||||
if (array_key_exists((int) $width, $this->alternatives)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$derivative = MediumFactory::fromFile($base->get('filepath'));
|
||||
|
||||
// It's possible that MediumFactory::fromFile returns null if the
|
||||
// original image file no longer exists and this class instance was
|
||||
// retrieved from the page cache
|
||||
if (null !== $derivative) {
|
||||
$index = 2;
|
||||
$alt_widths = array_keys($this->alternatives);
|
||||
sort($alt_widths);
|
||||
|
||||
foreach ($alt_widths as $i => $key) {
|
||||
if ($width > $key) {
|
||||
$index += max($i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$basename = preg_replace('/(@\d+x)?$/', "@{$width}w", $base->get('basename'), 1);
|
||||
$derivative->setImagePrettyName($basename);
|
||||
|
||||
$ratio = $base->get('width') / $width;
|
||||
$height = $derivative->get('height') / $ratio;
|
||||
|
||||
$derivative->resize($width, $height);
|
||||
$derivative->set('width', $width);
|
||||
$derivative->set('height', $height);
|
||||
|
||||
$this->addAlternative($ratio, $derivative);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out the alternatives.
|
||||
*/
|
||||
public function clearAlternatives()
|
||||
{
|
||||
$this->alternatives = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the quality of the image
|
||||
*
|
||||
* @param int $quality 0-100 quality
|
||||
* @return int|$this
|
||||
*/
|
||||
public function quality($quality = null)
|
||||
{
|
||||
if ($quality) {
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
$this->quality = $quality;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->quality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets image output format.
|
||||
*
|
||||
* @param string $format
|
||||
* @return $this
|
||||
*/
|
||||
public function format($format)
|
||||
{
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
$this->format = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get sizes parameter for srcset media action
|
||||
*
|
||||
* @param string $sizes
|
||||
* @return string
|
||||
*/
|
||||
public function sizes($sizes = null)
|
||||
{
|
||||
if ($sizes) {
|
||||
$this->sizes = $sizes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return empty($this->sizes) ? '100vw' : $this->sizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the width attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the width of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function width($value = 'auto')
|
||||
{
|
||||
if (!$value || $value === 'auto') {
|
||||
$this->attributes['width'] = $this->get('width');
|
||||
} else {
|
||||
$this->attributes['width'] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the height attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the height of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function height($value = 'auto')
|
||||
{
|
||||
if (!$value || $value === 'auto') {
|
||||
$this->attributes['height'] = $this->get('height');
|
||||
} else {
|
||||
$this->attributes['height'] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter image by using user defined filter parameters.
|
||||
*
|
||||
* @param string $filter Filter to be used.
|
||||
* @return $this
|
||||
*/
|
||||
public function filter($filter = 'image.filters.default')
|
||||
{
|
||||
$filters = (array) $this->get($filter, []);
|
||||
foreach ($filters as $params) {
|
||||
$params = (array) $params;
|
||||
$method = array_shift($params);
|
||||
$this->__call($method, $params);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image higher quality version
|
||||
*
|
||||
* @return ImageMediaInterface the alternative version with higher quality
|
||||
*/
|
||||
public function higherQualityAlternative()
|
||||
{
|
||||
if ($this->alternatives) {
|
||||
/** @var ImageMedium $max */
|
||||
$max = reset($this->alternatives);
|
||||
/** @var ImageMedium $alternative */
|
||||
foreach ($this->alternatives as $alternative) {
|
||||
if ($alternative->quality() > $max->quality()) {
|
||||
$max = $alternative;
|
||||
}
|
||||
}
|
||||
|
||||
return $max;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets medium image, resets image manipulation operations.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function image()
|
||||
{
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$file = $this->get('filepath');
|
||||
|
||||
// Use existing cache folder or if it doesn't exist, create it.
|
||||
$cacheDir = $locator->findResource('cache://images', true) ?: $locator->findResource('cache://images', true, true);
|
||||
|
||||
// Make sure we free previous image.
|
||||
unset($this->image);
|
||||
|
||||
$this->image = ImageFile::open($file)
|
||||
->setCacheDir($cacheDir)
|
||||
->setActualCacheDir($cacheDir)
|
||||
->setPrettyName($this->getImagePrettyName());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the image with cache.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function saveImage()
|
||||
{
|
||||
if (!$this->image) {
|
||||
return parent::path(false);
|
||||
}
|
||||
|
||||
$this->filter();
|
||||
|
||||
if (isset($this->result)) {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
$this->format($this->get('extension'));
|
||||
|
||||
if (!$this->debug_watermarked && $this->get('debug')) {
|
||||
$ratio = $this->get('ratio');
|
||||
if (!$ratio) {
|
||||
$ratio = 1;
|
||||
}
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
$overlay = $locator->findResource("system://assets/responsive-overlays/{$ratio}x.png") ?: $locator->findResource('system://assets/responsive-overlays/unknown.png');
|
||||
$this->image->merge(ImageFile::open($overlay));
|
||||
}
|
||||
|
||||
return $this->image->cacheFile($this->format, $this->quality, false, [$this->get('width'), $this->get('height'), $this->get('modified')]);
|
||||
}
|
||||
}
|
||||
134
system/src/Grav/Common/Media/Traits/MediaFileTrait.php
Normal file
134
system/src/Grav/Common/Media/Traits/MediaFileTrait.php
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* Trait MediaFileTrait
|
||||
* @package Grav\Common\Media\Traits
|
||||
*/
|
||||
trait MediaFileTrait
|
||||
{
|
||||
/**
|
||||
* Check if this medium exists or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
$path = $this->path(false);
|
||||
|
||||
return file_exists($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file modification time for the medium.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$path = $this->path(false);
|
||||
if (!file_exists($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return filemtime($path) ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of the medium.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function size()
|
||||
{
|
||||
$path = $this->path(false);
|
||||
if (!file_exists($path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return filesize($path) ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PATH to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string path to file
|
||||
*/
|
||||
public function path($reset = true)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return $this->get('filepath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path to file
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function relativePath($reset = true)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
$path = $this->path(false);
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $path) ?: $path;
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->getGrav()['locator'];
|
||||
if ($locator->isStream($output)) {
|
||||
$output = (string)($locator->findResource($output, false) ?: $locator->findResource($output, false, true));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
$path = $this->relativePath($reset);
|
||||
|
||||
return trim($this->getGrav()['base_url'] . '/' . $this->urlQuerystring($path), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL with full querystring
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
abstract public function urlQuerystring($url);
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
abstract public function reset();
|
||||
|
||||
/**
|
||||
* @return Grav
|
||||
*/
|
||||
abstract protected function getGrav(): Grav;
|
||||
}
|
||||
591
system/src/Grav/Common/Media/Traits/MediaObjectTrait.php
Normal file
591
system/src/Grav/Common/Media/Traits/MediaObjectTrait.php
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Media\Interfaces\MediaFileInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface;
|
||||
use Grav\Common\Page\Medium\ThumbnailImageMedium;
|
||||
use Grav\Common\Utils;
|
||||
|
||||
/**
|
||||
* Class Medium
|
||||
* @package Grav\Common\Page\Medium
|
||||
*
|
||||
* @property string $mime
|
||||
*/
|
||||
trait MediaObjectTrait
|
||||
{
|
||||
/** @var string */
|
||||
protected $mode = 'source';
|
||||
|
||||
/** @var MediaObjectInterface|null */
|
||||
protected $_thumbnail;
|
||||
|
||||
/** @var array */
|
||||
protected $thumbnailTypes = ['page', 'default'];
|
||||
|
||||
/** @var string|null */
|
||||
protected $thumbnailType;
|
||||
|
||||
/** @var MediaObjectInterface[] */
|
||||
protected $alternatives = [];
|
||||
|
||||
/** @var array */
|
||||
protected $attributes = [];
|
||||
|
||||
/** @var array */
|
||||
protected $styleAttributes = [];
|
||||
|
||||
/** @var array */
|
||||
protected $metadata = [];
|
||||
|
||||
/** @var array */
|
||||
protected $medium_querystring = [];
|
||||
|
||||
/** @var string */
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Create a copy of this media object
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return just metadata from the Medium object
|
||||
*
|
||||
* @return Data
|
||||
*/
|
||||
public function meta()
|
||||
{
|
||||
return new Data($this->getItems());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set querystring to file modification timestamp (or value provided as a parameter).
|
||||
*
|
||||
* @param string|int|null $timestamp
|
||||
* @return $this
|
||||
*/
|
||||
public function setTimestamp($timestamp = null)
|
||||
{
|
||||
if (null !== $timestamp) {
|
||||
$this->timestamp = (string)($timestamp);
|
||||
} elseif ($this instanceof MediaFileInterface) {
|
||||
$this->timestamp = (string)$this->modified();
|
||||
} else {
|
||||
$this->timestamp = '';
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing just the metadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
* @param string $filepath
|
||||
*/
|
||||
abstract public function addMetaFile($filepath);
|
||||
|
||||
/**
|
||||
* Add alternative Medium to this Medium.
|
||||
*
|
||||
* @param int|float $ratio
|
||||
* @param MediaObjectInterface $alternative
|
||||
*/
|
||||
public function addAlternative($ratio, MediaObjectInterface $alternative)
|
||||
{
|
||||
if (!is_numeric($ratio) || $ratio === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$alternative->set('ratio', $ratio);
|
||||
$width = $alternative->get('width');
|
||||
|
||||
$this->alternatives[$width] = $alternative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of the object (html).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function __toString();
|
||||
|
||||
/**
|
||||
* Get/set querystring for the file's url
|
||||
*
|
||||
* @param string|null $querystring
|
||||
* @param bool $withQuestionmark
|
||||
* @return string
|
||||
*/
|
||||
public function querystring($querystring = null, $withQuestionmark = true)
|
||||
{
|
||||
if (null !== $querystring) {
|
||||
$this->medium_querystring[] = ltrim($querystring, '?&');
|
||||
foreach ($this->alternatives as $alt) {
|
||||
$alt->querystring($querystring, $withQuestionmark);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->medium_querystring)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// join the strings
|
||||
$querystring = implode('&', $this->medium_querystring);
|
||||
// explode all strings
|
||||
$query_parts = explode('&', $querystring);
|
||||
// Join them again now ensure the elements are unique
|
||||
$querystring = implode('&', array_unique($query_parts));
|
||||
|
||||
return $withQuestionmark ? ('?' . $querystring) : $querystring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL with full querystring
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function urlQuerystring($url)
|
||||
{
|
||||
$querystring = $this->querystring();
|
||||
if (isset($this->timestamp) && !Utils::contains($querystring, $this->timestamp)) {
|
||||
$querystring = empty($querystring) ? ('?' . $this->timestamp) : ($querystring . '&' . $this->timestamp);
|
||||
}
|
||||
|
||||
return ltrim($url . $querystring . $this->urlHash(), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set hash for the file's url
|
||||
*
|
||||
* @param string $hash
|
||||
* @param bool $withHash
|
||||
* @return string
|
||||
*/
|
||||
public function urlHash($hash = null, $withHash = true)
|
||||
{
|
||||
if ($hash) {
|
||||
$this->set('urlHash', ltrim($hash, '#'));
|
||||
}
|
||||
|
||||
$hash = $this->get('urlHash', '');
|
||||
|
||||
return $withHash && !empty($hash) ? '#' . $hash : $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element (is array) that can be rendered by the Parsedown engine
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function parsedownElement($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
$attributes = $this->attributes;
|
||||
$items = $this->getItems();
|
||||
|
||||
$style = '';
|
||||
foreach ($this->styleAttributes as $key => $value) {
|
||||
if (is_numeric($key)) { // Special case for inline style attributes, refer to style() method
|
||||
$style .= $value;
|
||||
} else {
|
||||
$style .= $key . ': ' . $value . ';';
|
||||
}
|
||||
}
|
||||
if ($style) {
|
||||
$attributes['style'] = $style;
|
||||
}
|
||||
|
||||
if (empty($attributes['title'])) {
|
||||
if (!empty($title)) {
|
||||
$attributes['title'] = $title;
|
||||
} elseif (!empty($items['title'])) {
|
||||
$attributes['title'] = $items['title'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['alt'])) {
|
||||
if (!empty($alt)) {
|
||||
$attributes['alt'] = $alt;
|
||||
} elseif (!empty($items['alt'])) {
|
||||
$attributes['alt'] = $items['alt'];
|
||||
} elseif (!empty($items['alt_text'])) {
|
||||
$attributes['alt'] = $items['alt_text'];
|
||||
} else {
|
||||
$attributes['alt'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['class'])) {
|
||||
if (!empty($class)) {
|
||||
$attributes['class'] = $class;
|
||||
} elseif (!empty($items['class'])) {
|
||||
$attributes['class'] = $items['class'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['id'])) {
|
||||
if (!empty($id)) {
|
||||
$attributes['id'] = $id;
|
||||
} elseif (!empty($items['id'])) {
|
||||
$attributes['id'] = $items['id'];
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->mode) {
|
||||
case 'text':
|
||||
$element = $this->textParsedownElement($attributes, false);
|
||||
break;
|
||||
case 'thumbnail':
|
||||
$thumbnail = $this->getThumbnail();
|
||||
$element = $thumbnail ? $thumbnail->sourceParsedownElement($attributes, false) : [];
|
||||
break;
|
||||
case 'source':
|
||||
$element = $this->sourceParsedownElement($attributes, false);
|
||||
break;
|
||||
default:
|
||||
$element = [];
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
$this->display('source');
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->attributes = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch display mode.
|
||||
*
|
||||
* @param string $mode
|
||||
*
|
||||
* @return MediaObjectInterface|null
|
||||
*/
|
||||
public function display($mode = 'source')
|
||||
{
|
||||
if ($this->mode === $mode) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
if ($mode === 'thumbnail') {
|
||||
$thumbnail = $this->getThumbnail();
|
||||
|
||||
return $thumbnail ? $thumbnail->reset() : null;
|
||||
}
|
||||
|
||||
return $this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine if this media item has a thumbnail or not
|
||||
*
|
||||
* @param string $type;
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function thumbnailExists($type = 'page')
|
||||
{
|
||||
$thumbs = $this->get('thumbnails');
|
||||
|
||||
return isset($thumbs[$type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch thumbnail.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function thumbnail($type = 'auto')
|
||||
{
|
||||
if ($type !== 'auto' && !\in_array($type, $this->thumbnailTypes, true)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->thumbnailType !== $type) {
|
||||
$this->_thumbnail = null;
|
||||
}
|
||||
|
||||
$this->thumbnailType = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
abstract public function url($reset = true);
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function link($reset = true, array $attributes = [])
|
||||
{
|
||||
if ($this->mode !== 'source') {
|
||||
$this->display('source');
|
||||
}
|
||||
|
||||
foreach ($this->attributes as $key => $value) {
|
||||
empty($attributes['data-' . $key]) && $attributes['data-' . $key] = $value;
|
||||
}
|
||||
|
||||
empty($attributes['href']) && $attributes['href'] = $this->url();
|
||||
|
||||
return $this->createLink($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link with lightbox enabled
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true)
|
||||
{
|
||||
$attributes = ['rel' => 'lightbox'];
|
||||
|
||||
if ($width && $height) {
|
||||
$attributes['data-width'] = $width;
|
||||
$attributes['data-height'] = $height;
|
||||
}
|
||||
|
||||
return $this->link($reset, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the element from Markdown or Twig
|
||||
* Example:  or 
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function classes()
|
||||
{
|
||||
$classes = func_get_args();
|
||||
if (!empty($classes)) {
|
||||
$this->attributes['class'] = implode(',', $classes);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an id to the element from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $id
|
||||
* @return $this
|
||||
*/
|
||||
public function id($id)
|
||||
{
|
||||
if (is_string($id)) {
|
||||
$this->attributes['id'] = trim($id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add an inline style attribute from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $style
|
||||
* @return $this
|
||||
*/
|
||||
public function style($style)
|
||||
{
|
||||
$this->styleAttributes[] = rtrim($style, ';') . ';';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow any action to be called on this medium from twig or markdown
|
||||
*
|
||||
* @param string $method
|
||||
* @param mixed $args
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$count = \count($args);
|
||||
if ($count > 1 || ($count === 1 && !empty($args[0]))) {
|
||||
$method .= '=' . implode(',', array_map(static function ($a) {
|
||||
if (is_array($a)) {
|
||||
$a = '[' . implode(',', $a) . ']';
|
||||
}
|
||||
|
||||
return rawurlencode($a);
|
||||
}, $args));
|
||||
}
|
||||
|
||||
if (!empty($method)) {
|
||||
$this->querystring($this->querystring(null, false) . '&' . $method);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
return $this->textParsedownElement($attributes, $reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for text display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function textParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
$text = $attributes['title'] ?? '';
|
||||
if ($text === '') {
|
||||
$text = $attributes['alt'] ?? '';
|
||||
if ($text === '') {
|
||||
$text = $this->get('filename');
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => 'p',
|
||||
'attributes' => $attributes,
|
||||
'text' => $text
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thumbnail Medium object
|
||||
*
|
||||
* @return ThumbnailImageMedium|null
|
||||
*/
|
||||
protected function getThumbnail()
|
||||
{
|
||||
if (null === $this->_thumbnail) {
|
||||
$types = $this->thumbnailTypes;
|
||||
|
||||
if ($this->thumbnailType !== 'auto') {
|
||||
array_unshift($types, $this->thumbnailType);
|
||||
}
|
||||
|
||||
foreach ($types as $type) {
|
||||
$thumb = $this->get("thumbnails.{$type}", false);
|
||||
|
||||
if ($thumb) {
|
||||
$thumb = $thumb instanceof ThumbnailImageMedium ? $thumb : $this->createThumbnail($thumb);
|
||||
$thumb->parent = $this;
|
||||
$this->_thumbnail = $thumb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_thumbnail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $this->get('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
abstract public function get($name, $default = null, $separator = null);
|
||||
|
||||
/**
|
||||
* Set value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->set('this.is.my.nested.variable', $value);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
abstract public function set($name, $value, $separator = null);
|
||||
|
||||
/**
|
||||
* @param string $thumb
|
||||
*/
|
||||
abstract protected function createThumbnail($thumb);
|
||||
|
||||
/**
|
||||
* @param array $attributes
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
abstract protected function createLink(array $attributes);
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getItems(): array;
|
||||
}
|
||||
111
system/src/Grav/Common/Media/Traits/MediaPlayerTrait.php
Normal file
111
system/src/Grav/Common/Media/Traits/MediaPlayerTrait.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
/**
|
||||
* Class implements audio object interface.
|
||||
*/
|
||||
trait MediaPlayerTrait
|
||||
{
|
||||
/**
|
||||
* Allows to set or remove the HTML5 default controls
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function controls($status = true)
|
||||
{
|
||||
if ($status) {
|
||||
$this->attributes['controls'] = true;
|
||||
} else {
|
||||
unset($this->attributes['controls']);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 preload behaviour
|
||||
*
|
||||
* @param string|null $preload
|
||||
* @return $this
|
||||
*/
|
||||
public function preload($preload = null)
|
||||
{
|
||||
$validPreloadAttrs = ['auto', 'metadata', 'none'];
|
||||
|
||||
if (null === $preload) {
|
||||
unset($this->attributes['preload']);
|
||||
} elseif (\in_array($preload, $validPreloadAttrs, true)) {
|
||||
$this->attributes['preload'] = $preload;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset player.
|
||||
*/
|
||||
public function resetPlayer()
|
||||
{
|
||||
$this->attributes['controls'] = true;
|
||||
}
|
||||
}
|
||||
28
system/src/Grav/Common/Media/Traits/StaticResizeTrait.php
Normal file
28
system/src/Grav/Common/Media/Traits/StaticResizeTrait.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
trait StaticResizeTrait
|
||||
{
|
||||
/**
|
||||
* Resize media by setting attributes
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @return $this
|
||||
*/
|
||||
public function resize($width = null, $height = null)
|
||||
{
|
||||
$this->styleAttributes['width'] = $width . 'px';
|
||||
$this->styleAttributes['height'] = $height . 'px';
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
142
system/src/Grav/Common/Media/Traits/ThumbnailMediaTrait.php
Normal file
142
system/src/Grav/Common/Media/Traits/ThumbnailMediaTrait.php
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface;
|
||||
|
||||
trait ThumbnailMediaTrait
|
||||
{
|
||||
/** @var MediaObjectInterface|null */
|
||||
public $parent;
|
||||
|
||||
/** @var bool */
|
||||
public $linked = false;
|
||||
|
||||
/**
|
||||
* Return srcset string for this Medium and its alternatives.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function srcset($reset = true)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element (is array) that can be rendered by the Parsedown engine
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function parsedownElement($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('parsedownElement', [$title, $alt, $class, $id, $reset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML markup from the medium.
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function html($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('html', [$title, $alt, $class, $id, $reset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch display mode.
|
||||
*
|
||||
* @param string $mode
|
||||
*
|
||||
* @return MediaLinkInterface|MediaObjectInterface|null
|
||||
*/
|
||||
public function display($mode = 'source')
|
||||
{
|
||||
return $this->bubble('display', [$mode], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch thumbnail.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return MediaLinkInterface|MediaObjectInterface
|
||||
*/
|
||||
public function thumbnail($type = 'auto')
|
||||
{
|
||||
$this->bubble('thumbnail', [$type], false);
|
||||
|
||||
return $this->bubble('getThumbnail', [], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function link($reset = true, array $attributes = [])
|
||||
{
|
||||
return $this->bubble('link', [$reset, $attributes], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link with lightbox enabled
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('lightbox', [$width, $height, $reset], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bubble a function call up to either the superclass function or the parent Medium instance
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
* @param bool $testLinked
|
||||
* @return mixed
|
||||
*/
|
||||
protected function bubble($method, array $arguments = [], $testLinked = true)
|
||||
{
|
||||
if (!$testLinked || $this->linked) {
|
||||
$parent = $this->parent;
|
||||
if (null === $parent) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$closure = [$parent, $method];
|
||||
|
||||
if (!is_callable($closure)) {
|
||||
throw new \BadMethodCallException(get_class($parent) . '::' . $method . '() not found.');
|
||||
}
|
||||
|
||||
return $closure(...$arguments);
|
||||
}
|
||||
|
||||
return parent::{$method}(...$arguments);
|
||||
}
|
||||
}
|
||||
64
system/src/Grav/Common/Media/Traits/VideoMediaTrait.php
Normal file
64
system/src/Grav/Common/Media/Traits/VideoMediaTrait.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
trait VideoMediaTrait
|
||||
{
|
||||
use StaticResizeTrait;
|
||||
use MediaPlayerTrait;
|
||||
|
||||
/**
|
||||
* Allows to set the video's poster image
|
||||
*
|
||||
* @param string $urlImage
|
||||
* @return $this
|
||||
*/
|
||||
public function poster($urlImage)
|
||||
{
|
||||
$this->attributes['poster'] = $urlImage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the playsinline attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function playsinline($status = false)
|
||||
{
|
||||
if ($status) {
|
||||
$this->attributes['playsinline'] = true;
|
||||
} else {
|
||||
unset($this->attributes['playsinline']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
$location = $this->url($reset);
|
||||
|
||||
return [
|
||||
'name' => 'video',
|
||||
'rawHtml' => '<source src="' . $location . '">Your browser does not support the video tag.',
|
||||
'attributes' => $attributes
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac
|
|||
|
||||
/** @var array */
|
||||
protected $items = [];
|
||||
/** @var string */
|
||||
/** @var string|null */
|
||||
protected $path;
|
||||
/** @var array */
|
||||
protected $images = [];
|
||||
|
|
@ -45,7 +45,7 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac
|
|||
/**
|
||||
* Return media path.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
|
|
@ -192,12 +192,14 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac
|
|||
protected function orderMedia($media)
|
||||
{
|
||||
if (null === $this->media_order) {
|
||||
/** @var Pages $pages */
|
||||
$pages = Grav::instance()['pages'];
|
||||
$page = $pages->get($this->getPath());
|
||||
|
||||
if ($page && isset($page->header()->media_order)) {
|
||||
$this->media_order = array_map('trim', explode(',', $page->header()->media_order));
|
||||
$path = $this->getPath();
|
||||
if (null !== $path) {
|
||||
/** @var Pages $pages */
|
||||
$pages = Grav::instance()['pages'];
|
||||
$page = $pages->get($path);
|
||||
if ($page && isset($page->header()->media_order)) {
|
||||
$this->media_order = array_map('trim', explode(',', $page->header()->media_order));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,127 +9,12 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
class AudioMedium extends Medium
|
||||
use Grav\Common\Media\Interfaces\AudioMediaInterface;
|
||||
use Grav\Common\Media\Traits\AudioMediaTrait;
|
||||
|
||||
class AudioMedium extends Medium implements AudioMediaInterface
|
||||
{
|
||||
use StaticResizeTrait;
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
$location = $this->url($reset);
|
||||
|
||||
return [
|
||||
'name' => 'audio',
|
||||
'rawHtml' => '<source src="' . $location . '">Your browser does not support the audio tag.',
|
||||
'attributes' => $attributes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 string $preload
|
||||
* @return $this
|
||||
*/
|
||||
public function preload($preload)
|
||||
{
|
||||
$validPreloadAttrs = ['auto', 'metadata', 'none'];
|
||||
|
||||
if (\in_array($preload, $validPreloadAttrs, true)) {
|
||||
$this->attributes['preload'] = $preload;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the controlsList behaviour
|
||||
* Separate multiple values with a hyphen
|
||||
*
|
||||
* @param string $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;
|
||||
}
|
||||
use AudioMediaTrait;
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
|
|
@ -140,7 +25,7 @@ class AudioMedium extends Medium
|
|||
{
|
||||
parent::reset();
|
||||
|
||||
$this->attributes['controls'] = true;
|
||||
$this->resetPlayer();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,49 +10,16 @@
|
|||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Media\Interfaces\ImageManipulateInterface;
|
||||
use Grav\Common\Media\Interfaces\ImageMediaInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Traits\ImageMediaTrait;
|
||||
use Grav\Common\Utils;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
class ImageMedium extends Medium
|
||||
class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulateInterface
|
||||
{
|
||||
/** @var array */
|
||||
protected $thumbnailTypes = ['page', 'media', 'default'];
|
||||
|
||||
/** @var ImageFile|null */
|
||||
protected $image;
|
||||
|
||||
/** @var string */
|
||||
protected $format = 'guess';
|
||||
|
||||
/** @var int */
|
||||
protected $quality;
|
||||
|
||||
/** @var int */
|
||||
protected $default_quality;
|
||||
|
||||
/** @var bool */
|
||||
protected $debug_watermarked = false;
|
||||
|
||||
/** @var array */
|
||||
public static $magic_actions = [
|
||||
'resize', 'forceResize', 'cropResize', 'crop', 'zoomCrop',
|
||||
'negate', 'brightness', 'contrast', 'grayscale', 'emboss',
|
||||
'smooth', 'sharp', 'edge', 'colorize', 'sepia', 'enableProgressive',
|
||||
'rotate', 'flip', 'fixOrientation', 'gaussianBlur'
|
||||
];
|
||||
|
||||
/** @var array */
|
||||
public static $magic_resize_actions = [
|
||||
'resize' => [0, 1],
|
||||
'forceResize' => [0, 1],
|
||||
'cropResize' => [0, 1],
|
||||
'crop' => [0, 1, 2, 3],
|
||||
'zoomCrop' => [0, 1]
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
protected $sizes = '100vw';
|
||||
use ImageMediaTrait;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
|
|
@ -64,13 +31,15 @@ class ImageMedium extends Medium
|
|||
{
|
||||
parent::__construct($items, $blueprint);
|
||||
|
||||
$config = Grav::instance()['config'];
|
||||
$this->thumbnailTypes = ['page', 'media', 'default'];
|
||||
|
||||
$path = $this->get('filepath');
|
||||
if (!$path || !file_exists($path) || !filesize($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = $this->getGrav()['config'];
|
||||
|
||||
$image_info = getimagesize($path);
|
||||
|
||||
$this->def('width', $image_info[0]);
|
||||
|
|
@ -96,243 +65,13 @@ class ImageMedium extends Medium
|
|||
|
||||
public function __clone()
|
||||
{
|
||||
$this->image = $this->image ? clone $this->image : null;
|
||||
if ($this->image) {
|
||||
$this->image = clone $this->image;
|
||||
}
|
||||
|
||||
parent::__clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
* @param string $filepath
|
||||
* @return $this
|
||||
*/
|
||||
public function addMetaFile($filepath)
|
||||
{
|
||||
parent::addMetaFile($filepath);
|
||||
|
||||
// Apply filters in meta file
|
||||
$this->reset();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out the alternatives
|
||||
*/
|
||||
public function clearAlternatives()
|
||||
{
|
||||
$this->alternatives = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PATH to image.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string path to image
|
||||
*/
|
||||
public function path($reset = true)
|
||||
{
|
||||
$output = $this->saveImage();
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to image.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$image_path = $locator->findResource('cache://images', true) ?: $locator->findResource('cache://images', true, true);
|
||||
$saved_image_path = $this->saveImage();
|
||||
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $saved_image_path);
|
||||
|
||||
if ($locator->isStream($output)) {
|
||||
$output = $locator->findResource($output, false);
|
||||
}
|
||||
|
||||
if (Utils::startsWith($output, $image_path)) {
|
||||
$image_dir = $locator->findResource('cache://images', false);
|
||||
$output = '/' . $image_dir . preg_replace('|^' . preg_quote($image_path, '|') . '|', '', $output);
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return trim(Grav::instance()['base_url'] . '/' . $this->urlQuerystring($output), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply processes with no extra methods. Useful for triggering events.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cache()
|
||||
{
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return srcset string for this Medium and its alternatives.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function srcset($reset = true)
|
||||
{
|
||||
if (empty($this->alternatives)) {
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
$srcset = [];
|
||||
foreach ($this->alternatives as $ratio => $medium) {
|
||||
$srcset[] = $medium->url($reset) . ' ' . $medium->get('width') . 'w';
|
||||
}
|
||||
$srcset[] = str_replace(' ', '%20', $this->url($reset)) . ' ' . $this->get('width') . 'w';
|
||||
|
||||
return implode(', ', $srcset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the ability to override the image's pretty name stored in cache
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setImagePrettyName($name)
|
||||
{
|
||||
$this->set('prettyname', $name);
|
||||
if ($this->image) {
|
||||
$this->image->setPrettyName($name);
|
||||
}
|
||||
}
|
||||
|
||||
public function getImagePrettyName()
|
||||
{
|
||||
if ($this->get('prettyname')) {
|
||||
return $this->get('prettyname');
|
||||
}
|
||||
|
||||
$basename = $this->get('basename');
|
||||
if (preg_match('/[a-z0-9]{40}-(.*)/', $basename, $matches)) {
|
||||
$basename = $matches[1];
|
||||
}
|
||||
return $basename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alternative image widths, using either an array of integers, or
|
||||
* a min width, a max width, and a step parameter to fill out the necessary
|
||||
* widths. Existing image alternatives won't be overwritten.
|
||||
*
|
||||
* @param int|int[] $min_width
|
||||
* @param int $max_width
|
||||
* @param int $step
|
||||
* @return $this
|
||||
*/
|
||||
public function derivatives($min_width, $max_width = 2500, $step = 200)
|
||||
{
|
||||
if (!empty($this->alternatives)) {
|
||||
$max = max(array_keys($this->alternatives));
|
||||
$base = $this->alternatives[$max];
|
||||
} else {
|
||||
$base = $this;
|
||||
}
|
||||
|
||||
$widths = [];
|
||||
|
||||
if (func_num_args() === 1) {
|
||||
foreach ((array) func_get_arg(0) as $width) {
|
||||
if ($width < $base->get('width')) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$max_width = min($max_width, $base->get('width'));
|
||||
|
||||
for ($width = $min_width; $width < $max_width; $width = $width + $step) {
|
||||
$widths[] = $width;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($widths as $width) {
|
||||
// Only generate image alternatives that don't already exist
|
||||
if (array_key_exists((int) $width, $this->alternatives)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$derivative = MediumFactory::fromFile($base->get('filepath'));
|
||||
|
||||
// It's possible that MediumFactory::fromFile returns null if the
|
||||
// original image file no longer exists and this class instance was
|
||||
// retrieved from the page cache
|
||||
if (null !== $derivative) {
|
||||
$index = 2;
|
||||
$alt_widths = array_keys($this->alternatives);
|
||||
sort($alt_widths);
|
||||
|
||||
foreach ($alt_widths as $i => $key) {
|
||||
if ($width > $key) {
|
||||
$index += max($i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$basename = preg_replace('/(@\d+x){0,1}$/', "@{$width}w", $base->get('basename'), 1);
|
||||
$derivative->setImagePrettyName($basename);
|
||||
|
||||
$ratio = $base->get('width') / $width;
|
||||
$height = $derivative->get('height') / $ratio;
|
||||
|
||||
$derivative->resize($width, $height);
|
||||
$derivative->set('width', $width);
|
||||
$derivative->set('height', $height);
|
||||
|
||||
$this->addAlternative($ratio, $derivative);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
empty($attributes['src']) && $attributes['src'] = $this->url(false);
|
||||
|
||||
$srcset = $this->srcset($reset);
|
||||
if ($srcset) {
|
||||
empty($attributes['srcset']) && $attributes['srcset'] = $srcset;
|
||||
$attributes['sizes'] = $this->sizes();
|
||||
}
|
||||
|
||||
return ['name' => 'img', 'attributes' => $attributes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset image.
|
||||
*
|
||||
|
|
@ -357,12 +96,123 @@ class ImageMedium extends Medium
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
* @param string $filepath
|
||||
* @return $this
|
||||
*/
|
||||
public function addMetaFile($filepath)
|
||||
{
|
||||
parent::addMetaFile($filepath);
|
||||
|
||||
// Apply filters in meta file
|
||||
$this->reset();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PATH to image.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string path to image
|
||||
*/
|
||||
public function path($reset = true)
|
||||
{
|
||||
$output = $this->saveImage();
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to image.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
$grav = $this->getGrav();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$image_path = (string)($locator->findResource('cache://images', true) ?: $locator->findResource('cache://images', true, true));
|
||||
$saved_image_path = $this->saveImage();
|
||||
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $saved_image_path) ?: $saved_image_path;
|
||||
|
||||
if ($locator->isStream($output)) {
|
||||
$output = (string)($locator->findResource($output, false) ?: $locator->findResource($output, false, true));
|
||||
}
|
||||
|
||||
if (Utils::startsWith($output, $image_path)) {
|
||||
$image_dir = $locator->findResource('cache://images', false);
|
||||
$output = '/' . $image_dir . preg_replace('|^' . preg_quote($image_path, '|') . '|', '', $output);
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return trim($grav['base_url'] . '/' . $this->urlQuerystring($output), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return srcset string for this Medium and its alternatives.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function srcset($reset = true)
|
||||
{
|
||||
if (empty($this->alternatives)) {
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
$srcset = [];
|
||||
foreach ($this->alternatives as $ratio => $medium) {
|
||||
$srcset[] = $medium->url($reset) . ' ' . $medium->get('width') . 'w';
|
||||
}
|
||||
$srcset[] = str_replace(' ', '%20', $this->url($reset)) . ' ' . $this->get('width') . 'w';
|
||||
|
||||
return implode(', ', $srcset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
empty($attributes['src']) && $attributes['src'] = $this->url(false);
|
||||
|
||||
$srcset = $this->srcset($reset);
|
||||
if ($srcset) {
|
||||
empty($attributes['srcset']) && $attributes['srcset'] = $srcset;
|
||||
$attributes['sizes'] = $this->sizes();
|
||||
}
|
||||
|
||||
return ['name' => 'img', 'attributes' => $attributes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return Link
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function link($reset = true, array $attributes = [])
|
||||
{
|
||||
|
|
@ -381,7 +231,7 @@ class ImageMedium extends Medium
|
|||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return Link
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true)
|
||||
{
|
||||
|
|
@ -396,108 +246,6 @@ class ImageMedium extends Medium
|
|||
return parent::lightbox($width, $height, $reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the quality of the image
|
||||
*
|
||||
* @param int $quality 0-100 quality
|
||||
* @return int|$this
|
||||
*/
|
||||
public function quality($quality = null)
|
||||
{
|
||||
if ($quality) {
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
$this->quality = $quality;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->quality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets image output format.
|
||||
*
|
||||
* @param string $format
|
||||
* @return $this
|
||||
*/
|
||||
public function format($format)
|
||||
{
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
$this->format = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get sizes parameter for srcset media action
|
||||
*
|
||||
* @param string $sizes
|
||||
* @return string
|
||||
*/
|
||||
public function sizes($sizes = null)
|
||||
{
|
||||
|
||||
if ($sizes) {
|
||||
$this->sizes = $sizes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return empty($this->sizes) ? '100vw' : $this->sizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the width attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the width of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function width($value = 'auto')
|
||||
{
|
||||
if (!$value || $value === 'auto') {
|
||||
$this->attributes['width'] = $this->get('width');
|
||||
} else {
|
||||
$this->attributes['width'] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the height attribute from Markdown or Twig
|
||||
* Examples: 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* {{ page.media['myimg.png'].width().height().html }}
|
||||
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
|
||||
*
|
||||
* @param mixed $value A value or 'auto' or empty to use the height of the image
|
||||
* @return $this
|
||||
*/
|
||||
public function height($value = 'auto')
|
||||
{
|
||||
if (!$value || $value === 'auto') {
|
||||
$this->attributes['height'] = $this->get('height');
|
||||
} else {
|
||||
$this->attributes['height'] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward the call to the image processing method.
|
||||
*
|
||||
|
|
@ -511,7 +259,7 @@ class ImageMedium extends Medium
|
|||
$method = 'zoomCrop';
|
||||
}
|
||||
|
||||
if (!\in_array($method, self::$magic_actions, true)) {
|
||||
if (!\in_array($method, static::$magic_actions, true)) {
|
||||
return parent::__call($method, $args);
|
||||
}
|
||||
|
||||
|
|
@ -521,127 +269,28 @@ class ImageMedium extends Medium
|
|||
}
|
||||
|
||||
try {
|
||||
call_user_func_array([$this->image, $method], $args);
|
||||
$this->image->{$method}(...$args);
|
||||
|
||||
/** @var ImageMediaInterface $medium */
|
||||
foreach ($this->alternatives as $medium) {
|
||||
if (!$medium->image) {
|
||||
$medium->image();
|
||||
}
|
||||
|
||||
$args_copy = $args;
|
||||
|
||||
// regular image: resize 400x400 -> 200x200
|
||||
// --> @2x: resize 800x800->400x400
|
||||
if (isset(self::$magic_resize_actions[$method])) {
|
||||
foreach (self::$magic_resize_actions[$method] as $param) {
|
||||
if (isset(static::$magic_resize_actions[$method])) {
|
||||
foreach (static::$magic_resize_actions[$method] as $param) {
|
||||
if (isset($args_copy[$param])) {
|
||||
$args_copy[$param] *= $medium->get('ratio');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_user_func_array([$medium, $method], $args_copy);
|
||||
// Do the same call for alternative media.
|
||||
$medium->__call($method, $args_copy);
|
||||
}
|
||||
} catch (\BadFunctionCallException $e) {
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets medium image, resets image manipulation operations.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function image()
|
||||
{
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$file = $this->get('filepath');
|
||||
|
||||
// Use existing cache folder or if it doesn't exist, create it.
|
||||
$cacheDir = $locator->findResource('cache://images', true) ?: $locator->findResource('cache://images', true, true);
|
||||
|
||||
// Make sure we free previous image.
|
||||
unset($this->image);
|
||||
|
||||
$this->image = ImageFile::open($file)
|
||||
->setCacheDir($cacheDir)
|
||||
->setActualCacheDir($cacheDir)
|
||||
->setPrettyName($this->getImagePrettyName());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the image with cache.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function saveImage()
|
||||
{
|
||||
if (!$this->image) {
|
||||
return parent::path(false);
|
||||
}
|
||||
|
||||
$this->filter();
|
||||
|
||||
if (isset($this->result)) {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
$this->format($this->get('extension'));
|
||||
|
||||
if (!$this->debug_watermarked && $this->get('debug')) {
|
||||
$ratio = $this->get('ratio');
|
||||
if (!$ratio) {
|
||||
$ratio = 1;
|
||||
}
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
$overlay = $locator->findResource("system://assets/responsive-overlays/{$ratio}x.png") ?: $locator->findResource('system://assets/responsive-overlays/unknown.png');
|
||||
$this->image->merge(ImageFile::open($overlay));
|
||||
}
|
||||
|
||||
return $this->image->cacheFile($this->format, $this->quality, false, [$this->get('width'), $this->get('height'), $this->get('modified')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter image by using user defined filter parameters.
|
||||
*
|
||||
* @param string $filter Filter to be used.
|
||||
* @return $this
|
||||
*/
|
||||
public function filter($filter = 'image.filters.default')
|
||||
{
|
||||
$filters = (array) $this->get($filter, []);
|
||||
foreach ($filters as $params) {
|
||||
$params = (array) $params;
|
||||
$method = array_shift($params);
|
||||
$this->__call($method, $params);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image higher quality version
|
||||
*
|
||||
* @return Medium|ImageMedium the alternative version with higher quality
|
||||
*/
|
||||
public function higherQualityAlternative()
|
||||
{
|
||||
if ($this->alternatives) {
|
||||
$max = reset($this->alternatives);
|
||||
foreach ($this->alternatives as $alternative) {
|
||||
if ($alternative->quality() > $max->quality()) {
|
||||
$max = $alternative;
|
||||
}
|
||||
}
|
||||
|
||||
return $max;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,25 +9,37 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
class Link implements RenderableInterface
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface;
|
||||
|
||||
class Link implements RenderableInterface, MediaLinkInterface
|
||||
{
|
||||
use ParsedownHtmlTrait;
|
||||
|
||||
/** @var array */
|
||||
protected $attributes = [];
|
||||
/** @var Medium|null */
|
||||
/** @var MediaObjectInterface */
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
* @param array $attributes
|
||||
* @param Medium $medium
|
||||
* @param MediaObjectInterface $medium
|
||||
*/
|
||||
public function __construct(array $attributes, Medium $medium)
|
||||
public function __construct(array $attributes, MediaObjectInterface $medium)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
$this->source = $medium->reset()->thumbnail('auto')->display('thumbnail');
|
||||
$this->source->linked = true;
|
||||
|
||||
$source = $medium->reset()->thumbnail('auto')->display('thumbnail');
|
||||
|
||||
// FIXME: Thumbnail can be null, maybe we should not allow that?
|
||||
if (null === $source) {
|
||||
throw new \RuntimeException('Media has no thumbnail set');
|
||||
}
|
||||
|
||||
$source->set('linked', true);
|
||||
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,7 +59,7 @@ class Link implements RenderableInterface
|
|||
return [
|
||||
'name' => 'a',
|
||||
'attributes' => $this->attributes,
|
||||
'handler' => is_string($innerElement) ? 'line' : 'element',
|
||||
'handler' => is_array($innerElement) ? 'element' : 'line',
|
||||
'text' => $innerElement
|
||||
];
|
||||
}
|
||||
|
|
@ -61,10 +73,16 @@ class Link implements RenderableInterface
|
|||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$this->source = call_user_func_array(array($this->source, $method), $args);
|
||||
$object = $this->source;
|
||||
$callable = [$object, $method];
|
||||
if (!is_callable($callable)) {
|
||||
throw new \BadMethodCallException(get_class($object) . '::' . $method . '() not found.');
|
||||
}
|
||||
|
||||
$this->source = call_user_func_array($callable, $args);
|
||||
|
||||
// Don't start nesting links, if user has multiple link calls in his
|
||||
// actions, we will drop the previous links.
|
||||
return $this->source instanceof Link ? $this->source : $this;
|
||||
return $this->source instanceof MediaLinkInterface ? $this->source : $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ use Grav\Common\File\CompiledYamlFile;
|
|||
use Grav\Common\Grav;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Media\Interfaces\MediaObjectInterface;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Common\Media\Interfaces\MediaFileInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Traits\MediaFileTrait;
|
||||
use Grav\Common\Media\Traits\MediaObjectTrait;
|
||||
|
||||
/**
|
||||
* Class Medium
|
||||
|
|
@ -22,40 +24,12 @@ use Grav\Common\Utils;
|
|||
*
|
||||
* @property string $mime
|
||||
*/
|
||||
class Medium extends Data implements RenderableInterface, MediaObjectInterface
|
||||
class Medium extends Data implements RenderableInterface, MediaFileInterface
|
||||
{
|
||||
use MediaObjectTrait;
|
||||
use MediaFileTrait;
|
||||
use ParsedownHtmlTrait;
|
||||
|
||||
/** @var string */
|
||||
protected $mode = 'source';
|
||||
|
||||
/** @var Medium|null */
|
||||
protected $_thumbnail;
|
||||
|
||||
/** @var array */
|
||||
protected $thumbnailTypes = ['page', 'default'];
|
||||
|
||||
/** @var string|null */
|
||||
protected $thumbnailType;
|
||||
|
||||
/** @var Medium[] */
|
||||
protected $alternatives = [];
|
||||
|
||||
/** @var array */
|
||||
protected $attributes = [];
|
||||
|
||||
/** @var array */
|
||||
protected $styleAttributes = [];
|
||||
|
||||
/** @var array */
|
||||
protected $metadata = [];
|
||||
|
||||
/** @var array */
|
||||
protected $medium_querystring = [];
|
||||
|
||||
/** @var string */
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
|
|
@ -79,93 +53,6 @@ class Medium extends Data implements RenderableInterface, MediaObjectInterface
|
|||
// Allows future compatibility as parent::__clone() works.
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this media object
|
||||
*
|
||||
* @return Medium
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return just metadata from the Medium object
|
||||
*
|
||||
* @return Data
|
||||
*/
|
||||
public function meta()
|
||||
{
|
||||
return new Data($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this medium exists or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
$path = $this->get('filepath');
|
||||
if (file_exists($path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file modification time for the medium.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$path = $this->get('filepath');
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return filemtime($path) ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function size()
|
||||
{
|
||||
$path = $this->get('filepath');
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return filesize($path) ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set querystring to file modification timestamp (or value provided as a parameter).
|
||||
*
|
||||
* @param string|int|null $timestamp
|
||||
* @return $this
|
||||
*/
|
||||
public function setTimestamp($timestamp = null)
|
||||
{
|
||||
$this->timestamp = (string)($timestamp ?? $this->modified());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing just the metadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta file for the medium.
|
||||
*
|
||||
|
|
@ -177,24 +64,6 @@ class Medium extends Data implements RenderableInterface, MediaObjectInterface
|
|||
$this->merge($this->metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add alternative Medium to this Medium.
|
||||
*
|
||||
* @param int|float $ratio
|
||||
* @param Medium $alternative
|
||||
*/
|
||||
public function addAlternative($ratio, Medium $alternative)
|
||||
{
|
||||
if (!is_numeric($ratio) || $ratio === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$alternative->set('ratio', $ratio);
|
||||
$width = $alternative->get('width');
|
||||
|
||||
$this->alternatives[$width] = $alternative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of the object (html).
|
||||
*
|
||||
|
|
@ -206,465 +75,35 @@ class Medium extends Data implements RenderableInterface, MediaObjectInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Return PATH to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string path to file
|
||||
* @param string $thumb
|
||||
*/
|
||||
public function path($reset = true)
|
||||
protected function createThumbnail($thumb)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return $this->get('filepath');
|
||||
return MediumFactory::fromFile($thumb, ['type' => 'thumbnail']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path to file
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return mixed
|
||||
* @param array $attributes
|
||||
* @return MediaLinkInterface
|
||||
*/
|
||||
public function relativePath($reset = true)
|
||||
protected function createLink(array $attributes)
|
||||
{
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $this->get('filepath'));
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($output)) {
|
||||
$output = $locator->findResource($output, false);
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return str_replace(GRAV_ROOT, '', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to file.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $this->get('filepath'));
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($output)) {
|
||||
$output = $locator->findResource($output, false);
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return trim(Grav::instance()['base_url'] . '/' . $this->urlQuerystring($output), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set querystring for the file's url
|
||||
*
|
||||
* @param string|null $querystring
|
||||
* @param bool $withQuestionmark
|
||||
* @return string
|
||||
*/
|
||||
public function querystring($querystring = null, $withQuestionmark = true)
|
||||
{
|
||||
if (null !== $querystring) {
|
||||
$this->medium_querystring[] = ltrim($querystring, '?&');
|
||||
foreach ($this->alternatives as $alt) {
|
||||
$alt->querystring($querystring, $withQuestionmark);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->medium_querystring)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// join the strings
|
||||
$querystring = implode('&', $this->medium_querystring);
|
||||
// explode all strings
|
||||
$query_parts = explode('&', $querystring);
|
||||
// Join them again now ensure the elements are unique
|
||||
$querystring = implode('&', array_unique($query_parts));
|
||||
|
||||
return $withQuestionmark ? ('?' . $querystring) : $querystring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL with full querystring
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function urlQuerystring($url)
|
||||
{
|
||||
$querystring = $this->querystring();
|
||||
if (isset($this->timestamp) && !Utils::contains($querystring, $this->timestamp)) {
|
||||
$querystring = empty($querystring) ? ('?' . $this->timestamp) : ($querystring . '&' . $this->timestamp);
|
||||
}
|
||||
|
||||
return ltrim($url . $querystring . $this->urlHash(), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set hash for the file's url
|
||||
*
|
||||
* @param string $hash
|
||||
* @param bool $withHash
|
||||
* @return string
|
||||
*/
|
||||
public function urlHash($hash = null, $withHash = true)
|
||||
{
|
||||
if ($hash) {
|
||||
$this->set('urlHash', ltrim($hash, '#'));
|
||||
}
|
||||
|
||||
$hash = $this->get('urlHash', '');
|
||||
|
||||
return $withHash && !empty($hash) ? '#' . $hash : $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element (is array) that can be rendered by the Parsedown engine
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function parsedownElement($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
$attributes = $this->attributes;
|
||||
|
||||
$style = '';
|
||||
foreach ($this->styleAttributes as $key => $value) {
|
||||
if (is_numeric($key)) { // Special case for inline style attributes, refer to style() method
|
||||
$style .= $value;
|
||||
} else {
|
||||
$style .= $key . ': ' . $value . ';';
|
||||
}
|
||||
}
|
||||
if ($style) {
|
||||
$attributes['style'] = $style;
|
||||
}
|
||||
|
||||
if (empty($attributes['title'])) {
|
||||
if (!empty($title)) {
|
||||
$attributes['title'] = $title;
|
||||
} elseif (!empty($this->items['title'])) {
|
||||
$attributes['title'] = $this->items['title'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['alt'])) {
|
||||
if (!empty($alt)) {
|
||||
$attributes['alt'] = $alt;
|
||||
} elseif (!empty($this->items['alt'])) {
|
||||
$attributes['alt'] = $this->items['alt'];
|
||||
} elseif (!empty($this->items['alt_text'])) {
|
||||
$attributes['alt'] = $this->items['alt_text'];
|
||||
} else {
|
||||
$attributes['alt'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['class'])) {
|
||||
if (!empty($class)) {
|
||||
$attributes['class'] = $class;
|
||||
} elseif (!empty($this->items['class'])) {
|
||||
$attributes['class'] = $this->items['class'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($attributes['id'])) {
|
||||
if (!empty($id)) {
|
||||
$attributes['id'] = $id;
|
||||
} elseif (!empty($this->items['id'])) {
|
||||
$attributes['id'] = $this->items['id'];
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->mode) {
|
||||
case 'text':
|
||||
$element = $this->textParsedownElement($attributes, false);
|
||||
break;
|
||||
case 'thumbnail':
|
||||
$element = $this->getThumbnail()->sourceParsedownElement($attributes, false);
|
||||
break;
|
||||
case 'source':
|
||||
$element = $this->sourceParsedownElement($attributes, false);
|
||||
break;
|
||||
default:
|
||||
$element = [];
|
||||
}
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
$this->display('source');
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
return $this->textParsedownElement($attributes, $reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsedown element for text display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function textParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
$text = empty($attributes['title']) ? empty($attributes['alt']) ? $this->get('filename') : $attributes['alt'] : $attributes['title'];
|
||||
|
||||
$element = [
|
||||
'name' => 'p',
|
||||
'attributes' => $attributes,
|
||||
'text' => $text
|
||||
];
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->attributes = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch display mode.
|
||||
*
|
||||
* @param string $mode
|
||||
*
|
||||
* @return self|null
|
||||
*/
|
||||
public function display($mode = 'source')
|
||||
{
|
||||
if ($this->mode === $mode) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
$this->mode = $mode;
|
||||
if ($mode === 'thumbnail') {
|
||||
$thumbnail = $this->getThumbnail();
|
||||
|
||||
return $thumbnail ? $thumbnail->reset() : null;
|
||||
}
|
||||
|
||||
return $this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine if this media item has a thumbnail or not
|
||||
*
|
||||
* @param string $type;
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function thumbnailExists($type = 'page')
|
||||
{
|
||||
$thumbs = $this->get('thumbnails');
|
||||
if (isset($thumbs[$type])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch thumbnail.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function thumbnail($type = 'auto')
|
||||
{
|
||||
if ($type !== 'auto' && !\in_array($type, $this->thumbnailTypes, true)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->thumbnailType !== $type) {
|
||||
$this->_thumbnail = null;
|
||||
}
|
||||
|
||||
$this->thumbnailType = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return Link
|
||||
*/
|
||||
public function link($reset = true, array $attributes = [])
|
||||
{
|
||||
if ($this->mode !== 'source') {
|
||||
$this->display('source');
|
||||
}
|
||||
|
||||
foreach ($this->attributes as $key => $value) {
|
||||
empty($attributes['data-' . $key]) && $attributes['data-' . $key] = $value;
|
||||
}
|
||||
|
||||
empty($attributes['href']) && $attributes['href'] = $this->url();
|
||||
|
||||
return new Link($attributes, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link with lightbox enabled
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return Link
|
||||
* @return Grav
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true)
|
||||
protected function getGrav(): Grav
|
||||
{
|
||||
$attributes = ['rel' => 'lightbox'];
|
||||
|
||||
if ($width && $height) {
|
||||
$attributes['data-width'] = $width;
|
||||
$attributes['data-height'] = $height;
|
||||
}
|
||||
|
||||
return $this->link($reset, $attributes);
|
||||
return Grav::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the element from Markdown or Twig
|
||||
* Example:  or 
|
||||
*
|
||||
* @return $this
|
||||
* @return array
|
||||
*/
|
||||
public function classes()
|
||||
protected function getItems(): array
|
||||
{
|
||||
$classes = func_get_args();
|
||||
if (!empty($classes)) {
|
||||
$this->attributes['class'] = implode(',', $classes);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an id to the element from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $id
|
||||
* @return $this
|
||||
*/
|
||||
public function id($id)
|
||||
{
|
||||
if (is_string($id)) {
|
||||
$this->attributes['id'] = trim($id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add an inline style attribute from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param string $style
|
||||
* @return $this
|
||||
*/
|
||||
public function style($style)
|
||||
{
|
||||
$this->styleAttributes[] = rtrim($style, ';') . ';';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow any action to be called on this medium from twig or markdown
|
||||
*
|
||||
* @param string $method
|
||||
* @param mixed $args
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$qs = $method;
|
||||
if (\count($args) > 1 || (\count($args) === 1 && !empty($args[0]))) {
|
||||
$qs .= '=' . implode(',', array_map(function ($a) {
|
||||
if (is_array($a)) {
|
||||
$a = '[' . implode(',', $a) . ']';
|
||||
}
|
||||
return rawurlencode($a);
|
||||
}, $args));
|
||||
}
|
||||
|
||||
if (!empty($qs)) {
|
||||
$this->querystring($this->querystring(null, false) . '&' . $qs);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thumbnail Medium object
|
||||
*
|
||||
* @return ThumbnailImageMedium|null
|
||||
*/
|
||||
protected function getThumbnail()
|
||||
{
|
||||
if (null === $this->_thumbnail) {
|
||||
$types = $this->thumbnailTypes;
|
||||
|
||||
if ($this->thumbnailType !== 'auto') {
|
||||
array_unshift($types, $this->thumbnailType);
|
||||
}
|
||||
|
||||
foreach ($types as $type) {
|
||||
$thumb = $this->get('thumbnails.' . $type, false);
|
||||
|
||||
if ($thumb) {
|
||||
$thumb = $thumb instanceof ThumbnailImageMedium ? $thumb : MediumFactory::fromFile($thumb, ['type' => 'thumbnail']);
|
||||
$thumb->parent = $this;
|
||||
}
|
||||
|
||||
if ($thumb) {
|
||||
$this->_thumbnail = $thumb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_thumbnail;
|
||||
return $this->items;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
class StaticImageMedium extends Medium
|
||||
use Grav\Common\Media\Interfaces\ImageMediaInterface;
|
||||
use Grav\Common\Media\Traits\StaticResizeTrait;
|
||||
|
||||
class StaticImageMedium extends Medium implements ImageMediaInterface
|
||||
{
|
||||
use StaticResizeTrait;
|
||||
|
||||
|
|
@ -22,7 +25,9 @@ class StaticImageMedium extends Medium
|
|||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
empty($attributes['src']) && $attributes['src'] = $this->url($reset);
|
||||
if (empty($attributes['src'])) {
|
||||
$attributes['src'] = $this->url($reset);
|
||||
}
|
||||
|
||||
return ['name' => 'img', 'attributes' => $attributes];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,13 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
user_error('Grav\Common\Page\Medium\StaticResizeTrait is deprecated since Grav 1.7, use Grav\Common\Media\Traits\StaticResizeTrait instead', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Trait StaticResizeTrait
|
||||
* @package Grav\Common\Page\Medium
|
||||
* @deprecated 1.7 Use `Grav\Common\Media\Traits\StaticResizeTrait` instead
|
||||
*/
|
||||
trait StaticResizeTrait
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,120 +9,9 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\Media\Traits\ThumbnailMediaTrait;
|
||||
|
||||
class ThumbnailImageMedium extends ImageMedium
|
||||
{
|
||||
/** @var Medium|null */
|
||||
public $parent;
|
||||
|
||||
/** @var bool */
|
||||
public $linked = false;
|
||||
|
||||
/**
|
||||
* Return srcset string for this Medium and its alternatives.
|
||||
*
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function srcset($reset = true)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element (is array) that can be rendered by the Parsedown engine
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
public function parsedownElement($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('parsedownElement', [$title, $alt, $class, $id, $reset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML markup from the medium.
|
||||
*
|
||||
* @param string|null $title
|
||||
* @param string|null $alt
|
||||
* @param string|null $class
|
||||
* @param string|null $id
|
||||
* @param bool $reset
|
||||
* @return string
|
||||
*/
|
||||
public function html($title = null, $alt = null, $class = null, $id = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('html', [$title, $alt, $class, $id, $reset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch display mode.
|
||||
*
|
||||
* @param string $mode
|
||||
*
|
||||
* @return array|Link|Medium
|
||||
*/
|
||||
public function display($mode = 'source')
|
||||
{
|
||||
return $this->bubble('display', [$mode], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch thumbnail.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return array|Link|Medium
|
||||
*/
|
||||
public function thumbnail($type = 'auto')
|
||||
{
|
||||
$this->bubble('thumbnail', [$type], false);
|
||||
|
||||
return $this->bubble('getThumbnail', [], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link
|
||||
*
|
||||
* @param bool $reset
|
||||
* @param array $attributes
|
||||
* @return Link
|
||||
*/
|
||||
public function link($reset = true, array $attributes = [])
|
||||
{
|
||||
return $this->bubble('link', [$reset, $attributes], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the current Medium into a Link with lightbox enabled
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param bool $reset
|
||||
* @return Link
|
||||
*/
|
||||
public function lightbox($width = null, $height = null, $reset = true)
|
||||
{
|
||||
return $this->bubble('lightbox', [$width, $height, $reset], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bubble a function call up to either the superclass function or the parent Medium instance
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
* @param bool $testLinked
|
||||
* @return array|Link|Medium
|
||||
*/
|
||||
protected function bubble($method, array $arguments = [], $testLinked = true)
|
||||
{
|
||||
if (!$testLinked || $this->linked) {
|
||||
return $this->parent ? call_user_func_array(array($this->parent, $method), $arguments) : $this;
|
||||
}
|
||||
|
||||
return call_user_func_array(array($this, 'parent::' . $method), $arguments);
|
||||
}
|
||||
use ThumbnailMediaTrait;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,142 +9,12 @@
|
|||
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
class VideoMedium extends Medium
|
||||
use Grav\Common\Media\Interfaces\VideoMediaInterface;
|
||||
use Grav\Common\Media\Traits\VideoMediaTrait;
|
||||
|
||||
class VideoMedium extends Medium implements VideoMediaInterface
|
||||
{
|
||||
use StaticResizeTrait;
|
||||
|
||||
/**
|
||||
* Parsedown element for source display mode
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param bool $reset
|
||||
* @return array
|
||||
*/
|
||||
protected function sourceParsedownElement(array $attributes, $reset = true)
|
||||
{
|
||||
$location = $this->url($reset);
|
||||
|
||||
return [
|
||||
'name' => 'video',
|
||||
'rawHtml' => '<source src="' . $location . '">Your browser does not support the video tag.',
|
||||
'attributes' => $attributes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 video's poster image
|
||||
*
|
||||
* @param string $urlImage
|
||||
* @return $this
|
||||
*/
|
||||
public function poster($urlImage)
|
||||
{
|
||||
$this->attributes['poster'] = $urlImage;
|
||||
|
||||
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'] = '';
|
||||
} else {
|
||||
unset($this->attributes['autoplay']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows ability to set the preload option
|
||||
*
|
||||
* @param string|null $status
|
||||
* @return $this
|
||||
*/
|
||||
public function preload($status = null)
|
||||
{
|
||||
if ($status) {
|
||||
$this->attributes['preload'] = $status;
|
||||
} else {
|
||||
unset($this->attributes['preload']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the playsinline attribute
|
||||
*
|
||||
* @param bool $status
|
||||
* @return $this
|
||||
*/
|
||||
public function playsinline($status = false)
|
||||
{
|
||||
if ($status) {
|
||||
$this->attributes['playsinline'] = true;
|
||||
} else {
|
||||
unset($this->attributes['playsinline']);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
use VideoMediaTrait;
|
||||
|
||||
/**
|
||||
* Reset medium.
|
||||
|
|
@ -155,7 +25,7 @@ class VideoMedium extends Medium
|
|||
{
|
||||
parent::reset();
|
||||
|
||||
$this->attributes['controls'] = true;
|
||||
$this->resetPlayer();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user