xref: /dokuwiki/inc/StyleUtils.php (revision 2e6e11ad01bd9ddb094d56aae0bcb96162a2cd53)
1fb1f9089SMichael Große<?php
2fb1f9089SMichael Große
3fb1f9089SMichael Großenamespace dokuwiki;
4fb1f9089SMichael Große
5fb1f9089SMichael Großeclass StyleUtils
6fb1f9089SMichael Große{
7fb1f9089SMichael Große
84593dbd2SAnna Dabrowska    /** @var string current template */
94593dbd2SAnna Dabrowska    protected $tpl;
104593dbd2SAnna Dabrowska    /** @var bool reinitialize styles config */
114593dbd2SAnna Dabrowska    protected $reinit;
124593dbd2SAnna Dabrowska    /** @var bool $preview preview mode */
134593dbd2SAnna Dabrowska    protected $preview;
144593dbd2SAnna Dabrowska    /** @var array default replacements to be merged with custom style configs */
154593dbd2SAnna 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
274593dbd2SAnna Dabrowska    /**
284593dbd2SAnna Dabrowska     * StyleUtils constructor.
294593dbd2SAnna Dabrowska     * @param string $tpl template name: if not passed as argument, the default value from $conf will be used
304593dbd2SAnna Dabrowska     * @param bool $preview
314593dbd2SAnna Dabrowska     * @param bool $reinit whether static style conf should be reinitialized
324593dbd2SAnna Dabrowska     */
334593dbd2SAnna Dabrowska    public function __construct($tpl = '', $preview = false, $reinit = false)
344593dbd2SAnna Dabrowska    {
354593dbd2SAnna Dabrowska        if (!$tpl) {
364593dbd2SAnna Dabrowska            global $conf;
37*2e6e11adSAndreas Gohr            $tpl = $conf['template'];
384593dbd2SAnna Dabrowska        }
394593dbd2SAnna Dabrowska        $this->tpl = $tpl;
404593dbd2SAnna Dabrowska        $this->reinit = $reinit;
414593dbd2SAnna Dabrowska        $this->preview = $preview;
424593dbd2SAnna Dabrowska    }
43fb1f9089SMichael Große
444593dbd2SAnna Dabrowska    /**
454593dbd2SAnna Dabrowska     * Load style ini contents
464593dbd2SAnna Dabrowska     *
474593dbd2SAnna Dabrowska     * Loads and merges style.ini files from template and config and prepares
484593dbd2SAnna Dabrowska     * the stylesheet modes
494593dbd2SAnna Dabrowska     *
504593dbd2SAnna Dabrowska     * @author Andreas Gohr <andi@splitbrain.org>
514593dbd2SAnna Dabrowska     * @author Anna Dabrowska <info@cosmocode.de>
524593dbd2SAnna Dabrowska     *
534593dbd2SAnna Dabrowska     * @return array with keys 'stylesheets' and 'replacements'
544593dbd2SAnna Dabrowska     */
554593dbd2SAnna Dabrowska    public function cssStyleini()
564593dbd2SAnna Dabrowska    {
574593dbd2SAnna Dabrowska        static $combined = [];
584593dbd2SAnna Dabrowska        if (!empty($combined) && !$this->reinit) {
594593dbd2SAnna Dabrowska            return $combined;
604593dbd2SAnna Dabrowska        }
614593dbd2SAnna Dabrowska
624593dbd2SAnna Dabrowska        global $conf;
634593dbd2SAnna Dabrowska        global $config_cascade;
644593dbd2SAnna Dabrowska        $stylesheets = array(); // mode, file => base
654593dbd2SAnna Dabrowska
664593dbd2SAnna Dabrowska        // guaranteed placeholder => value
674593dbd2SAnna Dabrowska        $replacements = $this->defaultReplacements;
684593dbd2SAnna Dabrowska
694593dbd2SAnna Dabrowska        // merge all styles from config cascade
704593dbd2SAnna Dabrowska        if (!is_array($config_cascade['styleini'])) {
714593dbd2SAnna Dabrowska            trigger_error('Missing config cascade for styleini', E_USER_WARNING);
724593dbd2SAnna Dabrowska        }
734593dbd2SAnna Dabrowska
744593dbd2SAnna Dabrowska        // allow replacement overwrites in preview mode
754593dbd2SAnna Dabrowska        if ($this->preview) {
764593dbd2SAnna Dabrowska            $config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
774593dbd2SAnna Dabrowska        }
784593dbd2SAnna Dabrowska
794593dbd2SAnna Dabrowska        $combined['stylesheets'] = [];
804593dbd2SAnna Dabrowska        $combined['replacements'] = [];
814593dbd2SAnna Dabrowska
824593dbd2SAnna Dabrowska        foreach (array('default', 'local', 'protected') as $config_group) {
834593dbd2SAnna Dabrowska            if (empty($config_cascade['styleini'][$config_group])) continue;
844593dbd2SAnna Dabrowska
854593dbd2SAnna Dabrowska            // set proper server dirs
864593dbd2SAnna Dabrowska            $webbase = $this->getWebbase($config_group);
874593dbd2SAnna Dabrowska
884593dbd2SAnna Dabrowska            foreach ($config_cascade['styleini'][$config_group] as $inifile) {
894593dbd2SAnna Dabrowska                // replace the placeholder with the name of the current template
904593dbd2SAnna Dabrowska                $inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
914593dbd2SAnna Dabrowska
924593dbd2SAnna Dabrowska                $incbase = dirname($inifile) . '/';
934593dbd2SAnna Dabrowska
944593dbd2SAnna Dabrowska                if (file_exists($inifile)) {
954593dbd2SAnna Dabrowska                    $config = parse_ini_file($inifile, true);
964593dbd2SAnna Dabrowska
974593dbd2SAnna Dabrowska                    if (is_array($config['stylesheets'])) {
984593dbd2SAnna Dabrowska
994593dbd2SAnna Dabrowska                        foreach ($config['stylesheets'] as $inifile => $mode) {
1004593dbd2SAnna Dabrowska                            // validate and include style files
1014593dbd2SAnna Dabrowska                            $stylesheets = array_merge($stylesheets, $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase));
1024593dbd2SAnna Dabrowska                            $combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
1034593dbd2SAnna Dabrowska                        }
1044593dbd2SAnna Dabrowska                    }
1054593dbd2SAnna Dabrowska
1064593dbd2SAnna Dabrowska                    if (is_array($config['replacements'])) {
1074593dbd2SAnna Dabrowska                        $replacements = array_replace($replacements, $this->cssFixreplacementurls($config['replacements'], $webbase));
1084593dbd2SAnna Dabrowska                        $combined['replacements'] = array_merge($combined['replacements'], $replacements);
1094593dbd2SAnna Dabrowska                    }
1104593dbd2SAnna Dabrowska                }
1114593dbd2SAnna Dabrowska            }
1124593dbd2SAnna Dabrowska        }
1134593dbd2SAnna Dabrowska
1144593dbd2SAnna Dabrowska
1154593dbd2SAnna Dabrowska        return $combined;
1164593dbd2SAnna Dabrowska    }
1174593dbd2SAnna Dabrowska
1184593dbd2SAnna Dabrowska    /**
1194593dbd2SAnna Dabrowska     * Checks if configured style files exist and, if necessary, adjusts file extensions in config
1204593dbd2SAnna Dabrowska     *
1214593dbd2SAnna Dabrowska     * @param array $stylesheets
1224593dbd2SAnna Dabrowska     * @param string $file
1234593dbd2SAnna Dabrowska     * @param string $mode
1244593dbd2SAnna Dabrowska     * @param string $incbase
1254593dbd2SAnna Dabrowska     * @param string $webbase
1264593dbd2SAnna Dabrowska     * @return mixed
1274593dbd2SAnna Dabrowska     */
1284593dbd2SAnna Dabrowska    protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
1294593dbd2SAnna Dabrowska    {
1304593dbd2SAnna 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']) {
1374593dbd2SAnna Dabrowska                    msg("Stylesheet $file not found, using $basename.$newExtension instead. Please contact developer of \"$this->tpl\" template.", 2);
138432cf0d1SMichael Große                }
1394593dbd2SAnna Dabrowska            } elseif ($conf['allowdebug']) {
1404593dbd2SAnna Dabrowska                msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
141432cf0d1SMichael Große            }
142432cf0d1SMichael Große        }
1434593dbd2SAnna Dabrowska        $stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
1444593dbd2SAnna Dabrowska        return $stylesheets;
145fb1f9089SMichael Große    }
146fb1f9089SMichael Große
1474593dbd2SAnna Dabrowska    /**
1484593dbd2SAnna Dabrowska     * Returns the web base path for the given level/group in config cascade.
1494593dbd2SAnna Dabrowska     * Style resources are relative to the template directory for the main (default) styles
1504593dbd2SAnna Dabrowska     * but relative to DOKU_BASE for everything else"
1514593dbd2SAnna Dabrowska     *
1524593dbd2SAnna Dabrowska     * @param string $config_group
1534593dbd2SAnna Dabrowska     * @return string
1544593dbd2SAnna Dabrowska     */
1554593dbd2SAnna Dabrowska    protected function getWebbase($config_group)
1564593dbd2SAnna Dabrowska    {
1574593dbd2SAnna Dabrowska        if ($config_group === 'default') {
1584593dbd2SAnna Dabrowska            return tpl_basedir($this->tpl);
1594593dbd2SAnna Dabrowska        } else {
1604593dbd2SAnna 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     */
1734593dbd2SAnna Dabrowska    protected function cssFixreplacementurls($replacements, $location)
1744593dbd2SAnna 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