dokuwiki/inc/StyleUtils.php

194 lines
6.6 KiB
PHP

<?php
namespace dokuwiki;
/**
* Class StyleUtils
*
* Reads and applies the template's style.ini settings
*/
class StyleUtils
{
/** @var string current template */
protected $tpl;
/** @var bool reinitialize styles config */
protected $reinit;
/** @var bool $preview preview mode */
protected $preview;
/** @var array default replacements to be merged with custom style configs */
protected $defaultReplacements = [
'__text__' => "#000",
'__background__' => "#fff",
'__text_alt__' => "#999",
'__background_alt__' => "#eee",
'__text_neu__' => "#666",
'__background_neu__' => "#ddd",
'__border__' => "#ccc",
'__highlight__' => "#ff9",
'__link__' => "#00f"
];
/**
* StyleUtils constructor.
* @param string $tpl template name: if not passed as argument, the default value from $conf will be used
* @param bool $preview
* @param bool $reinit whether static style conf should be reinitialized
*/
public function __construct($tpl = '', $preview = false, $reinit = false)
{
if (!$tpl) {
global $conf;
$tpl = $conf['template'];
}
$this->tpl = $tpl;
$this->reinit = $reinit;
$this->preview = $preview;
}
/**
* Load style ini contents
*
* Loads and merges style.ini files from template and config and prepares
* the stylesheet modes
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Anna Dabrowska <info@cosmocode.de>
*
* @return array with keys 'stylesheets' and 'replacements'
*/
public function cssStyleini()
{
static $combined = [];
if (!empty($combined) && !$this->reinit) {
return $combined;
}
global $conf;
global $config_cascade;
$stylesheets = []; // mode, file => base
// guaranteed placeholder => value
$replacements = $this->defaultReplacements;
// merge all styles from config cascade
if (!is_array($config_cascade['styleini'])) {
trigger_error('Missing config cascade for styleini', E_USER_WARNING);
}
// allow replacement overwrites in preview mode
if ($this->preview) {
$config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
}
$combined['stylesheets'] = [];
$combined['replacements'] = [];
foreach (['default', 'local', 'protected'] as $config_group) {
if (empty($config_cascade['styleini'][$config_group])) continue;
// set proper server dirs
$webbase = $this->getWebbase($config_group);
foreach ($config_cascade['styleini'][$config_group] as $inifile) {
// replace the placeholder with the name of the current template
$inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
$incbase = dirname($inifile) . '/';
if (file_exists($inifile)) {
$config = parse_ini_file($inifile, true);
if (isset($config['stylesheets']) && is_array($config['stylesheets'])) {
foreach ($config['stylesheets'] as $inifile => $mode) {
// validate and include style files
$stylesheets = array_merge(
$stylesheets,
$this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase)
);
$combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
}
}
if (isset($config['replacements']) && is_array($config['replacements'])) {
$replacements = array_replace(
$replacements,
$this->cssFixreplacementurls($config['replacements'], $webbase)
);
$combined['replacements'] = array_merge($combined['replacements'], $replacements);
}
}
}
}
return $combined;
}
/**
* Checks if configured style files exist and, if necessary, adjusts file extensions in config
*
* @param array $stylesheets
* @param string $file
* @param string $mode
* @param string $incbase
* @param string $webbase
* @return mixed
*/
protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
{
global $conf;
if (!file_exists($incbase . $file)) {
[$extension, $basename] = array_map('strrev', sexplode('.', strrev($file), 2, ''));
$newExtension = $extension === 'css' ? 'less' : 'css';
if (file_exists($incbase . $basename . '.' . $newExtension)) {
$stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
if ($conf['allowdebug']) {
msg("Stylesheet $file not found, using $basename.$newExtension instead. " .
"Please contact developer of \"$this->tpl\" template.", 2);
}
} elseif ($conf['allowdebug']) {
msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
}
}
$stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
return $stylesheets;
}
/**
* Returns the web base path for the given level/group in config cascade.
* Style resources are relative to the template directory for the main (default) styles
* but relative to DOKU_BASE for everything else"
*
* @param string $config_group
* @return string
*/
protected function getWebbase($config_group)
{
if ($config_group === 'default') {
return tpl_basedir($this->tpl);
} else {
return DOKU_BASE;
}
}
/**
* Amend paths used in replacement relative urls, refer FS#2879
*
* @author Chris Smith <chris@jalakai.co.uk>
*
* @param array $replacements with key-value pairs
* @param string $location
* @return array
*/
protected function cssFixreplacementurls($replacements, $location)
{
foreach ($replacements as $key => $value) {
$replacements[$key] = preg_replace(
'#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#',
'\\1' . $location,
$value
);
}
return $replacements;
}
}