xref: /dokuwiki/inc/StyleUtils.php (revision e9f4a0f6846df14eb77aed6328759990ce4e3c08)
1fb1f9089SMichael Große<?php
2fb1f9089SMichael Große
3fb1f9089SMichael Großenamespace dokuwiki;
4fb1f9089SMichael Große
5*e9f4a0f6SAndreas Gohr/**
6*e9f4a0f6SAndreas Gohr * Class StyleUtils
7*e9f4a0f6SAndreas Gohr *
8*e9f4a0f6SAndreas Gohr * Reads and applies the template's style.ini settings
9*e9f4a0f6SAndreas Gohr */
10fb1f9089SMichael Großeclass StyleUtils
11fb1f9089SMichael Große{
12fb1f9089SMichael Große
134593dbd2SAnna Dabrowska    /** @var string current template */
144593dbd2SAnna Dabrowska    protected $tpl;
154593dbd2SAnna Dabrowska    /** @var bool reinitialize styles config */
164593dbd2SAnna Dabrowska    protected $reinit;
174593dbd2SAnna Dabrowska    /** @var bool $preview preview mode */
184593dbd2SAnna Dabrowska    protected $preview;
194593dbd2SAnna Dabrowska    /** @var array default replacements to be merged with custom style configs */
204593dbd2SAnna Dabrowska    protected $defaultReplacements = array(
21fb1f9089SMichael Große        '__text__' => "#000",
22fb1f9089SMichael Große        '__background__' => "#fff",
23fb1f9089SMichael Große        '__text_alt__' => "#999",
24fb1f9089SMichael Große        '__background_alt__' => "#eee",
25fb1f9089SMichael Große        '__text_neu__' => "#666",
26fb1f9089SMichael Große        '__background_neu__' => "#ddd",
27fb1f9089SMichael Große        '__border__' => "#ccc",
28fb1f9089SMichael Große        '__highlight__' => "#ff9",
29fb1f9089SMichael Große        '__link__' => "#00f",
30fb1f9089SMichael Große    );
31fb1f9089SMichael Große
324593dbd2SAnna Dabrowska    /**
334593dbd2SAnna Dabrowska     * StyleUtils constructor.
344593dbd2SAnna Dabrowska     * @param string $tpl template name: if not passed as argument, the default value from $conf will be used
354593dbd2SAnna Dabrowska     * @param bool $preview
364593dbd2SAnna Dabrowska     * @param bool $reinit whether static style conf should be reinitialized
374593dbd2SAnna Dabrowska     */
384593dbd2SAnna Dabrowska    public function __construct($tpl = '', $preview = false, $reinit = false)
394593dbd2SAnna Dabrowska    {
404593dbd2SAnna Dabrowska        if (!$tpl) {
414593dbd2SAnna Dabrowska            global $conf;
424593dbd2SAnna Dabrowska            $tpl = $conf['conf'];
434593dbd2SAnna Dabrowska        }
444593dbd2SAnna Dabrowska        $this->tpl = $tpl;
454593dbd2SAnna Dabrowska        $this->reinit = $reinit;
464593dbd2SAnna Dabrowska        $this->preview = $preview;
474593dbd2SAnna Dabrowska    }
48fb1f9089SMichael Große
494593dbd2SAnna Dabrowska    /**
504593dbd2SAnna Dabrowska     * Load style ini contents
514593dbd2SAnna Dabrowska     *
524593dbd2SAnna Dabrowska     * Loads and merges style.ini files from template and config and prepares
534593dbd2SAnna Dabrowska     * the stylesheet modes
544593dbd2SAnna Dabrowska     *
554593dbd2SAnna Dabrowska     * @author Andreas Gohr <andi@splitbrain.org>
564593dbd2SAnna Dabrowska     * @author Anna Dabrowska <info@cosmocode.de>
574593dbd2SAnna Dabrowska     *
584593dbd2SAnna Dabrowska     * @return array with keys 'stylesheets' and 'replacements'
594593dbd2SAnna Dabrowska     */
604593dbd2SAnna Dabrowska    public function cssStyleini()
614593dbd2SAnna Dabrowska    {
624593dbd2SAnna Dabrowska        static $combined = [];
634593dbd2SAnna Dabrowska        if (!empty($combined) && !$this->reinit) {
644593dbd2SAnna Dabrowska            return $combined;
654593dbd2SAnna Dabrowska        }
664593dbd2SAnna Dabrowska
674593dbd2SAnna Dabrowska        global $conf;
684593dbd2SAnna Dabrowska        global $config_cascade;
694593dbd2SAnna Dabrowska        $stylesheets = array(); // mode, file => base
704593dbd2SAnna Dabrowska
714593dbd2SAnna Dabrowska        // guaranteed placeholder => value
724593dbd2SAnna Dabrowska        $replacements = $this->defaultReplacements;
734593dbd2SAnna Dabrowska
744593dbd2SAnna Dabrowska        // merge all styles from config cascade
754593dbd2SAnna Dabrowska        if (!is_array($config_cascade['styleini'])) {
764593dbd2SAnna Dabrowska            trigger_error('Missing config cascade for styleini', E_USER_WARNING);
774593dbd2SAnna Dabrowska        }
784593dbd2SAnna Dabrowska
794593dbd2SAnna Dabrowska        // allow replacement overwrites in preview mode
804593dbd2SAnna Dabrowska        if ($this->preview) {
814593dbd2SAnna Dabrowska            $config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
824593dbd2SAnna Dabrowska        }
834593dbd2SAnna Dabrowska
844593dbd2SAnna Dabrowska        $combined['stylesheets'] = [];
854593dbd2SAnna Dabrowska        $combined['replacements'] = [];
864593dbd2SAnna Dabrowska
874593dbd2SAnna Dabrowska        foreach (array('default', 'local', 'protected') as $config_group) {
884593dbd2SAnna Dabrowska            if (empty($config_cascade['styleini'][$config_group])) continue;
894593dbd2SAnna Dabrowska
904593dbd2SAnna Dabrowska            // set proper server dirs
914593dbd2SAnna Dabrowska            $webbase = $this->getWebbase($config_group);
924593dbd2SAnna Dabrowska
934593dbd2SAnna Dabrowska            foreach ($config_cascade['styleini'][$config_group] as $inifile) {
944593dbd2SAnna Dabrowska                // replace the placeholder with the name of the current template
954593dbd2SAnna Dabrowska                $inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
964593dbd2SAnna Dabrowska
974593dbd2SAnna Dabrowska                $incbase = dirname($inifile) . '/';
984593dbd2SAnna Dabrowska
994593dbd2SAnna Dabrowska                if (file_exists($inifile)) {
1004593dbd2SAnna Dabrowska                    $config = parse_ini_file($inifile, true);
1014593dbd2SAnna Dabrowska
1024593dbd2SAnna Dabrowska                    if (is_array($config['stylesheets'])) {
1034593dbd2SAnna Dabrowska                        foreach ($config['stylesheets'] as $inifile => $mode) {
1044593dbd2SAnna Dabrowska                            // validate and include style files
105*e9f4a0f6SAndreas Gohr                            $stylesheets = array_merge(
106*e9f4a0f6SAndreas Gohr                                $stylesheets,
107*e9f4a0f6SAndreas Gohr                                $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase)
108*e9f4a0f6SAndreas Gohr                            );
1094593dbd2SAnna Dabrowska                            $combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
1104593dbd2SAnna Dabrowska                        }
1114593dbd2SAnna Dabrowska                    }
1124593dbd2SAnna Dabrowska
1134593dbd2SAnna Dabrowska                    if (is_array($config['replacements'])) {
114*e9f4a0f6SAndreas Gohr                        $replacements = array_replace(
115*e9f4a0f6SAndreas Gohr                            $replacements,
116*e9f4a0f6SAndreas Gohr                            $this->cssFixreplacementurls($config['replacements'], $webbase)
117*e9f4a0f6SAndreas Gohr                        );
1184593dbd2SAnna Dabrowska                        $combined['replacements'] = array_merge($combined['replacements'], $replacements);
1194593dbd2SAnna Dabrowska                    }
1204593dbd2SAnna Dabrowska                }
1214593dbd2SAnna Dabrowska            }
1224593dbd2SAnna Dabrowska        }
1234593dbd2SAnna Dabrowska
1244593dbd2SAnna Dabrowska        return $combined;
1254593dbd2SAnna Dabrowska    }
1264593dbd2SAnna Dabrowska
1274593dbd2SAnna Dabrowska    /**
1284593dbd2SAnna Dabrowska     * Checks if configured style files exist and, if necessary, adjusts file extensions in config
1294593dbd2SAnna Dabrowska     *
1304593dbd2SAnna Dabrowska     * @param array $stylesheets
1314593dbd2SAnna Dabrowska     * @param string $file
1324593dbd2SAnna Dabrowska     * @param string $mode
1334593dbd2SAnna Dabrowska     * @param string $incbase
1344593dbd2SAnna Dabrowska     * @param string $webbase
1354593dbd2SAnna Dabrowska     * @return mixed
1364593dbd2SAnna Dabrowska     */
1374593dbd2SAnna Dabrowska    protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
1384593dbd2SAnna Dabrowska    {
1394593dbd2SAnna Dabrowska        global $conf;
140432cf0d1SMichael Große        if (!file_exists($incbase . $file)) {
141432cf0d1SMichael Große            list($extension, $basename) = array_map('strrev', explode('.', strrev($file), 2));
142432cf0d1SMichael Große            $newExtension = $extension === 'css' ? 'less' : 'css';
143432cf0d1SMichael Große            if (file_exists($incbase . $basename . '.' . $newExtension)) {
144432cf0d1SMichael Große                $stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
145432cf0d1SMichael Große                if ($conf['allowdebug']) {
146*e9f4a0f6SAndreas Gohr                    msg("Stylesheet $file not found, using $basename.$newExtension instead. " .
147*e9f4a0f6SAndreas Gohr                        "Please contact developer of \"$this->tpl\" template.", 2);
148432cf0d1SMichael Große                }
1494593dbd2SAnna Dabrowska            } elseif ($conf['allowdebug']) {
1504593dbd2SAnna Dabrowska                msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
151432cf0d1SMichael Große            }
152432cf0d1SMichael Große        }
1534593dbd2SAnna Dabrowska        $stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
1544593dbd2SAnna Dabrowska        return $stylesheets;
155fb1f9089SMichael Große    }
156fb1f9089SMichael Große
1574593dbd2SAnna Dabrowska    /**
1584593dbd2SAnna Dabrowska     * Returns the web base path for the given level/group in config cascade.
1594593dbd2SAnna Dabrowska     * Style resources are relative to the template directory for the main (default) styles
1604593dbd2SAnna Dabrowska     * but relative to DOKU_BASE for everything else"
1614593dbd2SAnna Dabrowska     *
1624593dbd2SAnna Dabrowska     * @param string $config_group
1634593dbd2SAnna Dabrowska     * @return string
1644593dbd2SAnna Dabrowska     */
1654593dbd2SAnna Dabrowska    protected function getWebbase($config_group)
1664593dbd2SAnna Dabrowska    {
1674593dbd2SAnna Dabrowska        if ($config_group === 'default') {
1684593dbd2SAnna Dabrowska            return tpl_basedir($this->tpl);
1694593dbd2SAnna Dabrowska        } else {
1704593dbd2SAnna Dabrowska            return DOKU_BASE;
171fb1f9089SMichael Große        }
172fb1f9089SMichael Große    }
173fb1f9089SMichael Große
174fb1f9089SMichael Große    /**
175fb1f9089SMichael Große     * Amend paths used in replacement relative urls, refer FS#2879
176fb1f9089SMichael Große     *
177fb1f9089SMichael Große     * @author Chris Smith <chris@jalakai.co.uk>
178fb1f9089SMichael Große     *
179fb1f9089SMichael Große     * @param array $replacements with key-value pairs
180fb1f9089SMichael Große     * @param string $location
181fb1f9089SMichael Große     * @return array
182fb1f9089SMichael Große     */
1834593dbd2SAnna Dabrowska    protected function cssFixreplacementurls($replacements, $location)
1844593dbd2SAnna Dabrowska    {
185fb1f9089SMichael Große        foreach ($replacements as $key => $value) {
18664159a61SAndreas Gohr            $replacements[$key] = preg_replace(
18764159a61SAndreas Gohr                '#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#',
18864159a61SAndreas Gohr                '\\1' . $location,
18964159a61SAndreas Gohr                $value
19064159a61SAndreas Gohr            );
191fb1f9089SMichael Große        }
192fb1f9089SMichael Große        return $replacements;
193fb1f9089SMichael Große    }
194fb1f9089SMichael Große}
195