aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/phpbb/template')
-rw-r--r--phpBB/phpbb/template/asset.php13
-rw-r--r--phpBB/phpbb/template/base.php22
-rw-r--r--phpBB/phpbb/template/twig/extension/icon.php321
-rw-r--r--phpBB/phpbb/template/twig/loader.php18
-rw-r--r--phpBB/phpbb/template/twig/node/includeasset.php2
-rw-r--r--phpBB/phpbb/template/twig/twig.php6
6 files changed, 333 insertions, 49 deletions
diff --git a/phpBB/phpbb/template/asset.php b/phpBB/phpbb/template/asset.php
index d6b46234f0..5fc3e4acaf 100644
--- a/phpBB/phpbb/template/asset.php
+++ b/phpBB/phpbb/template/asset.php
@@ -13,6 +13,8 @@
namespace phpbb\template;
+use phpbb\filesystem\helper as filesystem_helper;
+
class asset
{
protected $components = array();
@@ -20,20 +22,15 @@ class asset
/** @var \phpbb\path_helper **/
protected $path_helper;
- /** @var \phpbb\filesystem\filesystem */
- protected $filesystem;
-
/**
* Constructor
*
* @param string $url URL
* @param \phpbb\path_helper $path_helper Path helper object
- * @param \phpbb\filesystem\filesystem $filesystem
*/
- public function __construct($url, \phpbb\path_helper $path_helper, \phpbb\filesystem\filesystem $filesystem)
+ public function __construct($url, \phpbb\path_helper $path_helper)
{
$this->path_helper = $path_helper;
- $this->filesystem = $filesystem;
$this->set_url($url);
}
@@ -151,7 +148,7 @@ class asset
public function set_path($path, $urlencode = false)
{
// Since 1.7.0 Twig returns the real path of the file. We need it to be relative.
- $real_root_path = $this->filesystem->realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
+ $real_root_path = filesystem_helper::realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
// If the asset is under the phpBB root path we need to remove its path and then prepend $phpbb_root_path
if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
@@ -161,7 +158,7 @@ class asset
else
{
// Else we make the path relative to the current working directory
- $real_root_path = $this->filesystem->realpath('.') . DIRECTORY_SEPARATOR;
+ $real_root_path = filesystem_helper::realpath('.') . DIRECTORY_SEPARATOR;
if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
{
$path = str_replace('\\', '/', substr($path, strlen($real_root_path)));
diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php
index d502aceab8..314cdc4796 100644
--- a/phpBB/phpbb/template/base.php
+++ b/phpBB/phpbb/template/base.php
@@ -168,26 +168,4 @@ abstract class base implements template
{
return $this->context->find_key_index($blockname, $key);
}
-
- /**
- * Calls hook if any is defined.
- *
- * @param string $handle Template handle being displayed.
- * @param string $method Method name of the caller.
- */
- protected function call_hook($handle, $method)
- {
- global $phpbb_hook;
-
- if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array('template', $method), $handle, $this))
- {
- if ($phpbb_hook->hook_return(array('template', $method)))
- {
- $result = $phpbb_hook->hook_return_result(array('template', $method));
- return array($result);
- }
- }
-
- return false;
- }
}
diff --git a/phpBB/phpbb/template/twig/extension/icon.php b/phpBB/phpbb/template/twig/extension/icon.php
new file mode 100644
index 0000000000..f96ed94821
--- /dev/null
+++ b/phpBB/phpbb/template/twig/extension/icon.php
@@ -0,0 +1,321 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\template\twig\extension;
+
+use phpbb\template\twig\environment;
+
+class icon extends \Twig\Extension\AbstractExtension
+{
+ /** @var \phpbb\user */
+ protected $user;
+
+ /**
+ * Constructor.
+ *
+ * @param \phpbb\user $user User object
+ */
+ public function __construct(\phpbb\user $user)
+ {
+ $this->user = $user;
+ }
+
+ /**
+ * Returns the name of this extension.
+ *
+ * @return string The extension name
+ */
+ public function getName()
+ {
+ return 'icon';
+ }
+
+ /**
+ * Returns a list of functions to add to the existing list.
+ *
+ * @return \Twig\TwigFunction[] Array of twig functions
+ */
+ public function getFunctions()
+ {
+ return [
+ new \Twig\TwigFunction('Icon', [$this, 'icon'], ['needs_environment' => true]),
+ ];
+ }
+
+ /**
+ * Generate icon HTML for use in the template, depending on the mode.
+ *
+ * @param environment $environment Twig environment object
+ * @param string $type Icon type (font|iconify|png|svg)
+ * @param string $icon Icon name (eg. "bold")
+ * @param string $title Icon title
+ * @param bool $hidden Hide the icon title from view
+ * @param string $classes Additional classes (eg. "fa-fw")
+ * @param array $attributes Additional attributes for the icon, where the key is the attribute.
+ * {'data-ajax': 'mark_forums'} results in ' data-ajax="mark_forums"'
+ * @return string
+ */
+ public function icon(environment $environment, $type, $icon, $title = '', $hidden = false, $classes = '', array $attributes = [])
+ {
+ $type = strtolower($type);
+ $icon = is_array($icon) ? $this->get_first_icon($icon) : $icon;
+
+ if (empty($icon))
+ {
+ return '';
+ }
+
+ $not_found = false;
+ $source = '';
+ $view_box = '';
+
+ switch ($type)
+ {
+ case 'font':
+ // Nothing to do here..
+ break;
+
+ case 'iconify':
+ $source = explode(':', $icon);
+ $source = $source[0];
+ break;
+
+ case 'png':
+ $filesystem = $environment->get_filesystem();
+ $root_path = $environment->get_web_root_path();
+
+ $board_url = defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH;
+ $base_path = $board_url ? generate_board_url() . '/' : $root_path;
+
+ // Iterate over the user's styles and check for icon existance
+ foreach ($this->get_style_list() as $style_path)
+ {
+ if ($filesystem->exists("{$root_path}styles/{$style_path}/theme/png/{$icon}.png"))
+ {
+ $source = "{$base_path}styles/{$style_path}/theme/png/{$icon}.png";
+
+ break;
+ }
+ }
+
+ // Check if the icon was found or not
+ $not_found = empty($source);
+ break;
+
+ case 'svg':
+ try
+ {
+ // Try to load and prepare the SVG icon
+ $file = $environment->load('svg/' . $icon . '.svg');
+ $source = $this->prepare_svg($file, $view_box);
+
+ if (empty($view_box))
+ {
+ return '';
+ }
+ }
+ catch (\Twig\Error\LoaderError $e)
+ {
+ // Icon was not found
+ $not_found = true;
+ }
+ catch (\Twig\Error\Error $e)
+ {
+ return '';
+ }
+ break;
+
+ default:
+ return '';
+ break;
+ }
+
+ // If no PNG or SVG icon was found, display a default 404 SVG icon.
+ if ($not_found)
+ {
+ try
+ {
+ $file = $environment->load('svg/404.svg');
+ $source = $this->prepare_svg($file, $view_box);
+ }
+ catch (\Twig\Error\Error $e)
+ {
+ return '';
+ }
+
+ $type = 'svg';
+ $icon = '404';
+ }
+
+ try
+ {
+ return $environment->render("macros/icons/{$type}.twig", [
+ 'ATTRIBUTES' => (string) $this->implode_attributes($attributes),
+ 'CLASSES' => (string) $classes,
+ 'ICON' => (string) $icon,
+ 'SOURCE' => (string) $source,
+ 'TITLE' => (string) $title,
+ 'VIEW_BOX' => (string) $view_box,
+ 'S_HIDDEN' => (bool) $hidden,
+ ]);
+ }
+ catch (\Twig\Error\Error $e)
+ {
+ return '';
+ }
+ }
+
+ /**
+ * Prepare an SVG for usage in the template icon.
+ *
+ * This removes any <?xml ?> and <!DOCTYPE> elements,
+ * aswell as the root <svg> and any <title> elements.
+ *
+ * @param \Twig\TemplateWrapper $file The SVG file loaded from the environment
+ * @param string $view_box The viewBox attribute value
+ * @return string The cleaned SVG
+ */
+ protected function prepare_svg(\Twig\TemplateWrapper $file, &$view_box = '')
+ {
+ $code = $file->render();
+ $code = preg_replace( "/<\?xml.+?\?>/", '', $code);
+
+ $doc = new \DOMDocument();
+ $doc->preserveWhiteSpace = false;
+
+ /**
+ * Suppression is needed as DOMDocument does not like HTML5 and SVGs.
+ * Options parameter prevents $dom->saveHTML() from adding an <html> element.
+ */
+ @$doc->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
+
+ // Remove any DOCTYPE
+ foreach ($doc->childNodes as $child)
+ {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE)
+ {
+ $child->parentNode->removeChild($child);
+ }
+ }
+
+ $xpath = new \DOMXPath($doc);
+
+ /**
+ * Remove the root <svg> element
+ * and all <title> elements.
+ *
+ * @var \DOMElement $element
+ */
+ foreach ($xpath->query('/svg | //title') as $element)
+ {
+ if ($element->nodeName === 'svg')
+ {
+ // Return the viewBox attribute value of the root SVG element by reference
+ $view_box = $element->getAttribute('viewbox');
+
+ $width = $element->getAttribute('width');
+ $height = $element->getAttribute('height');
+
+ if (empty($view_box) && $width && $height)
+ {
+ $view_box = "0 0 {$width} {$height}";
+ }
+
+ while (isset($element->firstChild))
+ {
+ $element->parentNode->insertBefore($element->firstChild, $element);
+ }
+ }
+
+ $element->parentNode->removeChild($element);
+ }
+
+ $string = $doc->saveHTML();
+ $string = preg_replace('/\s+/', ' ', $string);
+
+ return $string;
+ }
+
+ /**
+ * Finds the first icon that has a "true" value and returns it.
+ *
+ * This allows sending an array to the Icon() function,
+ * where the keys are the icon names and the values are their checks.
+ *
+ * {{ Icon('font', {
+ * 'bullhorn': topicrow.S_POST_GLOBAL or topicrow.S_POST_ANNOUNCE,
+ * 'star': topicrow.S_POST_STICKY,
+ * 'lock': topicrow.S_TOPIC_LOCKED,
+ * 'fire': topicrow.S_TOPIC_HOT,
+ * 'file': true,
+ * }, 'MY_TITLE', true) }}
+ *
+ * @param array $icons Array of icons and their booleans
+ * @return string The first 'true' icon
+ */
+ protected function get_first_icon(array $icons)
+ {
+ foreach ($icons as $icon => $boolean)
+ {
+ // In case the key is not a string,
+ // this icon does not have a check
+ // so instantly return it
+ if (!is_string($icon))
+ {
+ return $boolean;
+ }
+
+ if ($boolean)
+ {
+ return $icon;
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Implode an associated array of attributes to a string for usage in a template.
+ *
+ * @param array $attributes Associated array of attributes
+ * @return string
+ */
+ protected function implode_attributes(array $attributes)
+ {
+ $string = '';
+
+ foreach ($attributes as $key => $value)
+ {
+ $string .= ' ' . $key . '="' . $value . '"';
+ }
+
+ return $string;
+ }
+
+ /**
+ * Get the style tree of the style preferred by the current user.
+ *
+ * @return array Style tree, most specific first
+ */
+ protected function get_style_list()
+ {
+ $style_list = [$this->user->style['style_path']];
+
+ if ($this->user->style['style_parent_id'])
+ {
+ $style_list = array_merge($style_list, array_reverse(explode('/', $this->user->style['style_parent_tree'])));
+ }
+
+ return $style_list;
+ }
+}
diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php
index 0f193dbe59..cddcf33146 100644
--- a/phpBB/phpbb/template/twig/loader.php
+++ b/phpBB/phpbb/template/twig/loader.php
@@ -13,6 +13,8 @@
namespace phpbb\template\twig;
+use phpbb\filesystem\helper as filesystem_helper;
+
/**
* Twig Template loader
*/
@@ -21,20 +23,12 @@ class loader extends \Twig_Loader_Filesystem
protected $safe_directories = array();
/**
- * @var \phpbb\filesystem\filesystem_interface
- */
- protected $filesystem;
-
- /**
* Constructor
*
- * @param \phpbb\filesystem\filesystem_interface $filesystem
* @param string|array $paths
*/
- public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $paths = array())
+ public function __construct($paths = array())
{
- $this->filesystem = $filesystem;
-
parent::__construct($paths, __DIR__);
}
@@ -67,7 +61,7 @@ class loader extends \Twig_Loader_Filesystem
*/
public function addSafeDirectory($directory)
{
- $directory = $this->filesystem->realpath($directory);
+ $directory = filesystem_helper::realpath($directory);
if ($directory !== false)
{
@@ -107,7 +101,7 @@ class loader extends \Twig_Loader_Filesystem
*/
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{
- return parent::addPath($this->filesystem->realpath($path), $namespace);
+ return parent::addPath(filesystem_helper::realpath($path), $namespace);
}
/**
@@ -147,7 +141,7 @@ class loader extends \Twig_Loader_Filesystem
// can now check if we're within a "safe" directory
// Find the real path of the directory the file is in
- $directory = $this->filesystem->realpath(dirname($file));
+ $directory = filesystem_helper::realpath(dirname($file));
if ($directory === false)
{
diff --git a/phpBB/phpbb/template/twig/node/includeasset.php b/phpBB/phpbb/template/twig/node/includeasset.php
index 69bfd58803..bf29fa7277 100644
--- a/phpBB/phpbb/template/twig/node/includeasset.php
+++ b/phpBB/phpbb/template/twig/node/includeasset.php
@@ -49,7 +49,7 @@ abstract class includeasset extends \Twig_Node
->write("\n")
->write("if (\$asset->is_relative()) {\n")
->indent()
- ->write("\$asset->add_assets_version(\$this->env->get_phpbb_config()['assets_version']);\n")
+ ->write("\$asset->add_assets_version(\$this->env->get_phpbb_config()['assets_version']);\n")
->outdent()
->write("}\n")
->write("\$this->env->get_assets_bag()->add_{$this->get_setters_name()}(\$asset);")
diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php
index f322778eda..f0736045de 100644
--- a/phpBB/phpbb/template/twig/twig.php
+++ b/phpBB/phpbb/template/twig/twig.php
@@ -308,12 +308,6 @@ class twig extends \phpbb\template\base
*/
public function display($handle)
{
- $result = $this->call_hook($handle, __FUNCTION__);
- if ($result !== false)
- {
- return $result[0];
- }
-
$this->twig->display($this->get_filename_from_handle($handle), $this->get_template_vars());
return $this;