xref: /dokuwiki/inc/StyleUtils.php (revision 4593dbd2856db337dc8104c2a5e0dcbe4e7f84e1)
1fb1f9089SMichael Große<?php
2fb1f9089SMichael Große
3fb1f9089SMichael Großenamespace dokuwiki;
4fb1f9089SMichael Große
5fb1f9089SMichael Großeclass StyleUtils
6fb1f9089SMichael Große{
7fb1f9089SMichael Große
8*4593dbd2SAnna Dabrowska    /** @var string current template */
9*4593dbd2SAnna Dabrowska    protected $tpl;
10*4593dbd2SAnna Dabrowska    /** @var bool reinitialize styles config */
11*4593dbd2SAnna Dabrowska    protected $reinit;
12*4593dbd2SAnna Dabrowska    /** @var bool $preview preview mode */
13*4593dbd2SAnna Dabrowska    protected $preview;
14*4593dbd2SAnna Dabrowska    /** @var array default replacements to be merged with custom style configs */
15*4593dbd2SAnna Dabrowska    protected $defaultReplacements = array(
16fb1f9089SMichael Große        '__text__' => "#000",
17fb1f9089SMichael Große        '__background__' => "#fff",
18fb1f9089SMichael Große        '__text_alt__' => "#999",
19fb1f9089SMichael Große        '__background_alt__' => "#eee",
20fb1f9089SMichael Große        '__text_neu__' => "#666",
21fb1f9089SMichael Große        '__background_neu__' => "#ddd",
22fb1f9089SMichael Große        '__border__' => "#ccc",
23fb1f9089SMichael Große        '__highlight__' => "#ff9",
24fb1f9089SMichael Große        '__link__' => "#00f",
25fb1f9089SMichael Große    );
26fb1f9089SMichael Große
27*4593dbd2SAnna Dabrowska    /**
28*4593dbd2SAnna Dabrowska     * StyleUtils constructor.
29*4593dbd2SAnna Dabrowska     * @param string $tpl template name: if not passed as argument, the default value from $conf will be used
30*4593dbd2SAnna Dabrowska     * @param bool $preview
31*4593dbd2SAnna Dabrowska     * @param bool $reinit whether static style conf should be reinitialized
32*4593dbd2SAnna Dabrowska     */
33*4593dbd2SAnna Dabrowska    public function __construct($tpl = '', $preview = false, $reinit = false)
34*4593dbd2SAnna Dabrowska    {
35*4593dbd2SAnna Dabrowska        if (!$tpl) {
36*4593dbd2SAnna Dabrowska            global $conf;
37*4593dbd2SAnna Dabrowska            $tpl = $conf['conf'];
38*4593dbd2SAnna Dabrowska        }
39*4593dbd2SAnna Dabrowska        $this->tpl = $tpl;
40*4593dbd2SAnna Dabrowska        $this->reinit = $reinit;
41*4593dbd2SAnna Dabrowska        $this->preview = $preview;
42*4593dbd2SAnna Dabrowska    }
43fb1f9089SMichael Große
44*4593dbd2SAnna Dabrowska    /**
45*4593dbd2SAnna Dabrowska     * Load style ini contents
46*4593dbd2SAnna Dabrowska     *
47*4593dbd2SAnna Dabrowska     * Loads and merges style.ini files from template and config and prepares
48*4593dbd2SAnna Dabrowska     * the stylesheet modes
49*4593dbd2SAnna Dabrowska     *
50*4593dbd2SAnna Dabrowska     * @author Andreas Gohr <andi@splitbrain.org>
51*4593dbd2SAnna Dabrowska     * @author Anna Dabrowska <info@cosmocode.de>
52*4593dbd2SAnna Dabrowska     *
53*4593dbd2SAnna Dabrowska     * @return array with keys 'stylesheets' and 'replacements'
54*4593dbd2SAnna Dabrowska     */
55*4593dbd2SAnna Dabrowska    public function cssStyleini()
56*4593dbd2SAnna Dabrowska    {
57*4593dbd2SAnna Dabrowska        static $combined = [];
58*4593dbd2SAnna Dabrowska        if (!empty($combined) && !$this->reinit) {
59*4593dbd2SAnna Dabrowska            return $combined;
60*4593dbd2SAnna Dabrowska        }
61*4593dbd2SAnna Dabrowska
62*4593dbd2SAnna Dabrowska        global $conf;
63*4593dbd2SAnna Dabrowska        global $config_cascade;
64*4593dbd2SAnna Dabrowska        $stylesheets = array(); // mode, file => base
65*4593dbd2SAnna Dabrowska
66*4593dbd2SAnna Dabrowska        // guaranteed placeholder => value
67*4593dbd2SAnna Dabrowska        $replacements = $this->defaultReplacements;
68*4593dbd2SAnna Dabrowska
69*4593dbd2SAnna Dabrowska        // merge all styles from config cascade
70*4593dbd2SAnna Dabrowska        if (!is_array($config_cascade['styleini'])) {
71*4593dbd2SAnna Dabrowska            trigger_error('Missing config cascade for styleini', E_USER_WARNING);
72*4593dbd2SAnna Dabrowska        }
73*4593dbd2SAnna Dabrowska
74*4593dbd2SAnna Dabrowska        // allow replacement overwrites in preview mode
75*4593dbd2SAnna Dabrowska        if ($this->preview) {
76*4593dbd2SAnna Dabrowska            $config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
77*4593dbd2SAnna Dabrowska        }
78*4593dbd2SAnna Dabrowska
79*4593dbd2SAnna Dabrowska        $combined['stylesheets'] = [];
80*4593dbd2SAnna Dabrowska        $combined['replacements'] = [];
81*4593dbd2SAnna Dabrowska
82*4593dbd2SAnna Dabrowska        foreach (array('default', 'local', 'protected') as $config_group) {
83*4593dbd2SAnna Dabrowska            if (empty($config_cascade['styleini'][$config_group])) continue;
84*4593dbd2SAnna Dabrowska
85*4593dbd2SAnna Dabrowska            // set proper server dirs
86*4593dbd2SAnna Dabrowska            $webbase = $this->getWebbase($config_group);
87*4593dbd2SAnna Dabrowska
88*4593dbd2SAnna Dabrowska            foreach ($config_cascade['styleini'][$config_group] as $inifile) {
89*4593dbd2SAnna Dabrowska                // replace the placeholder with the name of the current template
90*4593dbd2SAnna Dabrowska                $inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
91*4593dbd2SAnna Dabrowska
92*4593dbd2SAnna Dabrowska                $incbase = dirname($inifile) . '/';
93*4593dbd2SAnna Dabrowska
94*4593dbd2SAnna Dabrowska                if (file_exists($inifile)) {
95*4593dbd2SAnna Dabrowska                    $config = parse_ini_file($inifile, true);
96*4593dbd2SAnna Dabrowska
97*4593dbd2SAnna Dabrowska                    if (is_array($config['stylesheets'])) {
98*4593dbd2SAnna Dabrowska
99*4593dbd2SAnna Dabrowska                        foreach ($config['stylesheets'] as $inifile => $mode) {
100*4593dbd2SAnna Dabrowska                            // validate and include style files
101*4593dbd2SAnna Dabrowska                            $stylesheets = array_merge($stylesheets, $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase));
102*4593dbd2SAnna Dabrowska                            $combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
103*4593dbd2SAnna Dabrowska                        }
104*4593dbd2SAnna Dabrowska                    }
105*4593dbd2SAnna Dabrowska
106*4593dbd2SAnna Dabrowska                    if (is_array($config['replacements'])) {
107*4593dbd2SAnna Dabrowska                        $replacements = array_replace($replacements, $this->cssFixreplacementurls($config['replacements'], $webbase));
108*4593dbd2SAnna Dabrowska                        $combined['replacements'] = array_merge($combined['replacements'], $replacements);
109*4593dbd2SAnna Dabrowska                    }
110*4593dbd2SAnna Dabrowska                }
111*4593dbd2SAnna Dabrowska            }
112*4593dbd2SAnna Dabrowska        }
113*4593dbd2SAnna Dabrowska
114*4593dbd2SAnna Dabrowska
115*4593dbd2SAnna Dabrowska        return $combined;
116*4593dbd2SAnna Dabrowska    }
117*4593dbd2SAnna Dabrowska
118*4593dbd2SAnna Dabrowska    /**
119*4593dbd2SAnna Dabrowska     * Checks if configured style files exist and, if necessary, adjusts file extensions in config
120*4593dbd2SAnna Dabrowska     *
121*4593dbd2SAnna Dabrowska     * @param array $stylesheets
122*4593dbd2SAnna Dabrowska     * @param string $file
123*4593dbd2SAnna Dabrowska     * @param string $mode
124*4593dbd2SAnna Dabrowska     * @param string $incbase
125*4593dbd2SAnna Dabrowska     * @param string $webbase
126*4593dbd2SAnna Dabrowska     * @return mixed
127*4593dbd2SAnna Dabrowska     */
128*4593dbd2SAnna Dabrowska    protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
129*4593dbd2SAnna Dabrowska    {
130*4593dbd2SAnna Dabrowska        global $conf;
131432cf0d1SMichael Große        if (!file_exists($incbase . $file)) {
132432cf0d1SMichael Große            list($extension, $basename) = array_map('strrev', explode('.', strrev($file), 2));
133432cf0d1SMichael Große            $newExtension = $extension === 'css' ? 'less' : 'css';
134432cf0d1SMichael Große            if (file_exists($incbase . $basename . '.' . $newExtension)) {
135432cf0d1SMichael Große                $stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
136432cf0d1SMichael Große                if ($conf['allowdebug']) {
137*4593dbd2SAnna Dabrowska                    msg("Stylesheet $file not found, using $basename.$newExtension instead. Please contact developer of \"$this->tpl\" template.", 2);
138432cf0d1SMichael Große                }
139*4593dbd2SAnna Dabrowska            } elseif ($conf['allowdebug']) {
140*4593dbd2SAnna Dabrowska                msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
141432cf0d1SMichael Große            }
142432cf0d1SMichael Große        }
143*4593dbd2SAnna Dabrowska        $stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
144*4593dbd2SAnna Dabrowska        return $stylesheets;
145fb1f9089SMichael Große    }
146fb1f9089SMichael Große
147*4593dbd2SAnna Dabrowska    /**
148*4593dbd2SAnna Dabrowska     * Returns the web base path for the given level/group in config cascade.
149*4593dbd2SAnna Dabrowska     * Style resources are relative to the template directory for the main (default) styles
150*4593dbd2SAnna Dabrowska     * but relative to DOKU_BASE for everything else"
151*4593dbd2SAnna Dabrowska     *
152*4593dbd2SAnna Dabrowska     * @param string $config_group
153*4593dbd2SAnna Dabrowska     * @return string
154*4593dbd2SAnna Dabrowska     */
155*4593dbd2SAnna Dabrowska    protected function getWebbase($config_group)
156*4593dbd2SAnna Dabrowska    {
157*4593dbd2SAnna Dabrowska        if ($config_group === 'default') {
158*4593dbd2SAnna Dabrowska            return tpl_basedir($this->tpl);
159*4593dbd2SAnna Dabrowska        } else {
160*4593dbd2SAnna Dabrowska            return DOKU_BASE;
161fb1f9089SMichael Große        }
162fb1f9089SMichael Große    }
163fb1f9089SMichael Große
164fb1f9089SMichael Große    /**
165fb1f9089SMichael Große     * Amend paths used in replacement relative urls, refer FS#2879
166fb1f9089SMichael Große     *
167fb1f9089SMichael Große     * @author Chris Smith <chris@jalakai.co.uk>
168fb1f9089SMichael Große     *
169fb1f9089SMichael Große     * @param array $replacements with key-value pairs
170fb1f9089SMichael Große     * @param string $location
171fb1f9089SMichael Große     * @return array
172fb1f9089SMichael Große     */
173*4593dbd2SAnna Dabrowska    protected function cssFixreplacementurls($replacements, $location)
174*4593dbd2SAnna Dabrowska    {
175fb1f9089SMichael Große        foreach ($replacements as $key => $value) {
176fb1f9089SMichael Große            $replacements[$key] = preg_replace('#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#', '\\1' . $location, $value);
177fb1f9089SMichael Große        }
178fb1f9089SMichael Große        return $replacements;
179fb1f9089SMichael Große    }
180fb1f9089SMichael Große}
181