Merge pull request #4056 from dokuwiki-translate/lang_update_704_1694501527
[dokuwiki.git] / inc / StyleUtils.php
blobeb078562aca1c7eff6f9c02e46e67b6d333a6a72
1 <?php
3 namespace dokuwiki;
5 /**
6 * Class StyleUtils
8 * Reads and applies the template's style.ini settings
9 */
10 class StyleUtils
12 /** @var string current template */
13 protected $tpl;
14 /** @var bool reinitialize styles config */
15 protected $reinit;
16 /** @var bool $preview preview mode */
17 protected $preview;
18 /** @var array default replacements to be merged with custom style configs */
19 protected $defaultReplacements = [
20 '__text__' => "#000",
21 '__background__' => "#fff",
22 '__text_alt__' => "#999",
23 '__background_alt__' => "#eee",
24 '__text_neu__' => "#666",
25 '__background_neu__' => "#ddd",
26 '__border__' => "#ccc",
27 '__highlight__' => "#ff9",
28 '__link__' => "#00f"
31 /**
32 * StyleUtils constructor.
33 * @param string $tpl template name: if not passed as argument, the default value from $conf will be used
34 * @param bool $preview
35 * @param bool $reinit whether static style conf should be reinitialized
37 public function __construct($tpl = '', $preview = false, $reinit = false)
39 if (!$tpl) {
40 global $conf;
41 $tpl = $conf['template'];
43 $this->tpl = $tpl;
44 $this->reinit = $reinit;
45 $this->preview = $preview;
48 /**
49 * Load style ini contents
51 * Loads and merges style.ini files from template and config and prepares
52 * the stylesheet modes
54 * @author Andreas Gohr <andi@splitbrain.org>
55 * @author Anna Dabrowska <info@cosmocode.de>
57 * @return array with keys 'stylesheets' and 'replacements'
59 public function cssStyleini()
61 static $combined = [];
62 if (!empty($combined) && !$this->reinit) {
63 return $combined;
66 global $conf;
67 global $config_cascade;
68 $stylesheets = []; // mode, file => base
70 // guaranteed placeholder => value
71 $replacements = $this->defaultReplacements;
73 // merge all styles from config cascade
74 if (!is_array($config_cascade['styleini'])) {
75 trigger_error('Missing config cascade for styleini', E_USER_WARNING);
78 // allow replacement overwrites in preview mode
79 if ($this->preview) {
80 $config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
83 $combined['stylesheets'] = [];
84 $combined['replacements'] = [];
86 foreach (['default', 'local', 'protected'] as $config_group) {
87 if (empty($config_cascade['styleini'][$config_group])) continue;
89 // set proper server dirs
90 $webbase = $this->getWebbase($config_group);
92 foreach ($config_cascade['styleini'][$config_group] as $inifile) {
93 // replace the placeholder with the name of the current template
94 $inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
96 $incbase = dirname($inifile) . '/';
98 if (file_exists($inifile)) {
99 $config = parse_ini_file($inifile, true);
101 if (isset($config['stylesheets']) && is_array($config['stylesheets'])) {
102 foreach ($config['stylesheets'] as $inifile => $mode) {
103 // validate and include style files
104 $stylesheets = array_merge(
105 $stylesheets,
106 $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase)
108 $combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
112 if (isset($config['replacements']) && is_array($config['replacements'])) {
113 $replacements = array_replace(
114 $replacements,
115 $this->cssFixreplacementurls($config['replacements'], $webbase)
117 $combined['replacements'] = array_merge($combined['replacements'], $replacements);
123 return $combined;
127 * Checks if configured style files exist and, if necessary, adjusts file extensions in config
129 * @param array $stylesheets
130 * @param string $file
131 * @param string $mode
132 * @param string $incbase
133 * @param string $webbase
134 * @return mixed
136 protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
138 global $conf;
139 if (!file_exists($incbase . $file)) {
140 [$extension, $basename] = array_map('strrev', sexplode('.', strrev($file), 2, ''));
141 $newExtension = $extension === 'css' ? 'less' : 'css';
142 if (file_exists($incbase . $basename . '.' . $newExtension)) {
143 $stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
144 if ($conf['allowdebug']) {
145 msg("Stylesheet $file not found, using $basename.$newExtension instead. " .
146 "Please contact developer of \"$this->tpl\" template.", 2);
148 } elseif ($conf['allowdebug']) {
149 msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
152 $stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
153 return $stylesheets;
157 * Returns the web base path for the given level/group in config cascade.
158 * Style resources are relative to the template directory for the main (default) styles
159 * but relative to DOKU_BASE for everything else"
161 * @param string $config_group
162 * @return string
164 protected function getWebbase($config_group)
166 if ($config_group === 'default') {
167 return tpl_basedir($this->tpl);
168 } else {
169 return DOKU_BASE;
174 * Amend paths used in replacement relative urls, refer FS#2879
176 * @author Chris Smith <chris@jalakai.co.uk>
178 * @param array $replacements with key-value pairs
179 * @param string $location
180 * @return array
182 protected function cssFixreplacementurls($replacements, $location)
184 foreach ($replacements as $key => $value) {
185 $replacements[$key] = preg_replace(
186 '#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#',
187 '\\1' . $location,
188 $value
191 return $replacements;