diff --git a/conf/manifest.json b/conf/manifest.json new file mode 100644 index 0000000000..891bd79fbf --- /dev/null +++ b/conf/manifest.json @@ -0,0 +1,3 @@ +{ + "display": "standalone" +} diff --git a/data/media/wiki/dokuwiki.svg b/data/media/wiki/dokuwiki.svg new file mode 100644 index 0000000000..6e522c8b27 --- /dev/null +++ b/data/media/wiki/dokuwiki.svg @@ -0,0 +1,586 @@ + + + + + DokuWiki Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + DokuWiki Logo + + + Esther Brunner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inc/Manifest.php b/inc/Manifest.php new file mode 100644 index 0000000000..0df9c2b819 --- /dev/null +++ b/inc/Manifest.php @@ -0,0 +1,80 @@ +cssStyleini($conf['template']); + $replacements = $styleIni['replacements']; + + if (empty($manifest['background_color'])) { + $manifest['background_color'] = $replacements['__background__']; + } + + if (empty($manifest['theme_color'])) { + $manifest['theme_color'] = !empty($replacements['__theme_color__']) ? $replacements['__theme_color__'] : $replacements['__background_alt__']; + } + + if (empty($manifest['icons'])) { + $manifest['icons'] = []; + if (file_exists(mediaFN(':wiki:favicon.ico'))) { + $url = ml(':wiki:favicon.ico', '', true, '', true); + $manifest['icons'][] = [ + 'src' => $url, + 'sizes' => '16x16', + ]; + } + + $look = [ + ':wiki:logo.svg', + ':logo.svg', + ':wiki:dokuwiki.svg' + ]; + + foreach ($look as $svgLogo) { + + $svgLogoFN = mediaFN($svgLogo); + + if (file_exists($svgLogoFN)) { + $url = ml($svgLogo, '', true, '', true); + $manifest['icons'][] = [ + 'src' => $url, + 'sizes' => '17x17 512x512', + 'type' => 'image/svg+xml', + ]; + break; + }; + } + } + + trigger_event('MANIFEST_SEND', $manifest); + + header('Content-Type: application/manifest+json'); + echo json_encode($manifest); + } +} diff --git a/inc/StyleUtils.php b/inc/StyleUtils.php new file mode 100644 index 0000000000..494ed8e0ca --- /dev/null +++ b/inc/StyleUtils.php @@ -0,0 +1,107 @@ + + * + * @param string $tpl the used template + * @param bool $preview load preview replacements + * @return array with keys 'stylesheets' and 'replacements' + */ + public function cssStyleini($tpl, $preview=false) { + global $conf; + + $stylesheets = array(); // mode, file => base + // guaranteed placeholder => value + $replacements = array( + '__text__' => "#000", + '__background__' => "#fff", + '__text_alt__' => "#999", + '__background_alt__' => "#eee", + '__text_neu__' => "#666", + '__background_neu__' => "#ddd", + '__border__' => "#ccc", + '__highlight__' => "#ff9", + '__link__' => "#00f", + ); + + // load template's style.ini + $incbase = tpl_incdir($tpl); + $webbase = tpl_basedir($tpl); + $ini = $incbase.'style.ini'; + if(file_exists($ini)){ + $data = parse_ini_file($ini, true); + + // stylesheets + if(is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){ + $stylesheets[$mode][$incbase.$file] = $webbase; + } + + // replacements + if(is_array($data['replacements'])){ + $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'],$webbase)); + } + } + + // load configs's style.ini + $webbase = DOKU_BASE; + $ini = DOKU_CONF."tpl/$tpl/style.ini"; + $incbase = dirname($ini).'/'; + if(file_exists($ini)){ + $data = parse_ini_file($ini, true); + + // stylesheets + if(isset($data['stylesheets']) && is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){ + $stylesheets[$mode][$incbase.$file] = $webbase; + } + + // replacements + if(isset($data['replacements']) && is_array($data['replacements'])){ + $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'],$webbase)); + } + } + + // allow replacement overwrites in preview mode + if($preview) { + $webbase = DOKU_BASE; + $ini = $conf['cachedir'].'/preview.ini'; + if(file_exists($ini)) { + $data = parse_ini_file($ini, true); + // replacements + if(is_array($data['replacements'])) { + $replacements = array_merge($replacements, $this->cssFixreplacementurls($data['replacements'], $webbase)); + } + } + } + + return array( + 'stylesheets' => $stylesheets, + 'replacements' => $replacements + ); + } + + + /** + * Amend paths used in replacement relative urls, refer FS#2879 + * + * @author Chris Smith + * + * @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; + } +} diff --git a/inc/config_cascade.php b/inc/config_cascade.php index 2466290bc2..f0aa6cc7e4 100644 --- a/inc/config_cascade.php +++ b/inc/config_cascade.php @@ -28,6 +28,10 @@ 'default' => array(DOKU_CONF . 'license.php'), 'local' => array(DOKU_CONF . 'license.local.php'), ), + 'manifest' => array( + 'default' => array(DOKU_CONF . 'manifest.json'), + 'local' => array(DOKU_CONF . 'manifest.local.json'), + ), 'mediameta' => array( 'default' => array(DOKU_CONF . 'mediameta.php'), 'local' => array(DOKU_CONF . 'mediameta.local.php'), diff --git a/inc/confutils.php b/inc/confutils.php index f753b18c2a..59147010f1 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -255,6 +255,25 @@ function confToHash($file,$lower=false) { return linesToHash($lines, $lower); } +/** + * Read a json config file into an array + * + * @param string $file + * @return array + */ +function jsonToArray($file) +{ + $json = file_get_contents($file); + + $conf = json_decode($json, true); + + if ($conf === null) { + return []; + } + + return $conf; +} + /** * Retrieve the requested configuration information * diff --git a/inc/template.php b/inc/template.php index c44cd064ce..659d590493 100644 --- a/inc/template.php +++ b/inc/template.php @@ -242,6 +242,17 @@ function tpl_metaheaders($alt = true) { ); } + if (actionOK('manifest')) { + $head['link'][] = array('rel'=> 'manifest', 'href'=> DOKU_BASE.'lib/exe/manifest.php'); + } + + $styleUtil = new \dokuwiki\StyleUtils(); + $styleIni = $styleUtil->cssStyleini($conf['template']); + $replacements = $styleIni['replacements']; + if (!empty($replacements['__theme_color__'])) { + $head['meta'][] = array('name' => 'theme-color', 'content' => $replacements['__theme_color__']); + } + if($alt) { if(actionOK('rss')) { $head['link'][] = array( diff --git a/lib/exe/css.php b/lib/exe/css.php index ae51d9fc0a..40eaf99a66 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -45,7 +45,8 @@ function css_out(){ if(!$tpl) $tpl = $conf['template']; // load style.ini - $styleini = css_styleini($tpl, $INPUT->bool('preview')); + $styleUtil = new \dokuwiki\StyleUtils(); + $styleini = $styleUtil->cssStyleini($tpl, $INPUT->bool('preview')); // cache influencers $tplinc = tpl_incdir($tpl); @@ -264,106 +265,6 @@ function css_applystyle($css, $replacements) { return $css; } -/** - * Load style ini contents - * - * Loads and merges style.ini files from template and config and prepares - * the stylesheet modes - * - * @author Andreas Gohr - * - * @param string $tpl the used template - * @param bool $preview load preview replacements - * @return array with keys 'stylesheets' and 'replacements' - */ -function css_styleini($tpl, $preview=false) { - global $conf; - - $stylesheets = array(); // mode, file => base - // guaranteed placeholder => value - $replacements = array( - '__text__' => "#000", - '__background__' => "#fff", - '__text_alt__' => "#999", - '__background_alt__' => "#eee", - '__text_neu__' => "#666", - '__background_neu__' => "#ddd", - '__border__' => "#ccc", - '__highlight__' => "#ff9", - '__link__' => "#00f", - ); - - // load template's style.ini - $incbase = tpl_incdir($tpl); - $webbase = tpl_basedir($tpl); - $ini = $incbase.'style.ini'; - if(file_exists($ini)){ - $data = parse_ini_file($ini, true); - - // stylesheets - if(is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){ - $stylesheets[$mode][$incbase.$file] = $webbase; - } - - // replacements - if(is_array($data['replacements'])){ - $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'],$webbase)); - } - } - - // load configs's style.ini - $webbase = DOKU_BASE; - $ini = DOKU_CONF."tpl/$tpl/style.ini"; - $incbase = dirname($ini).'/'; - if(file_exists($ini)){ - $data = parse_ini_file($ini, true); - - // stylesheets - if(isset($data['stylesheets']) && is_array($data['stylesheets'])) foreach($data['stylesheets'] as $file => $mode){ - $stylesheets[$mode][$incbase.$file] = $webbase; - } - - // replacements - if(isset($data['replacements']) && is_array($data['replacements'])){ - $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'],$webbase)); - } - } - - // allow replacement overwrites in preview mode - if($preview) { - $webbase = DOKU_BASE; - $ini = $conf['cachedir'].'/preview.ini'; - if(file_exists($ini)) { - $data = parse_ini_file($ini, true); - // replacements - if(is_array($data['replacements'])) { - $replacements = array_merge($replacements, css_fixreplacementurls($data['replacements'], $webbase)); - } - } - } - - return array( - 'stylesheets' => $stylesheets, - 'replacements' => $replacements - ); -} - -/** - * Amend paths used in replacement relative urls, refer FS#2879 - * - * @author Chris Smith - * - * @param array $replacements with key-value pairs - * @param string $location - * @return array - */ -function css_fixreplacementurls($replacements, $location) { - foreach($replacements as $key => $value) { - $replacements[$key] = preg_replace('#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#','\\1'.$location,$value); - } - return $replacements; -} - /** * Wrapper for the files, content and mediatype for the event CSS_STYLES_INCLUDED * diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php new file mode 100644 index 0000000000..e9a35289c0 --- /dev/null +++ b/lib/exe/manifest.php @@ -0,0 +1,14 @@ +sendManifest(); diff --git a/lib/plugins/styling/admin.php b/lib/plugins/styling/admin.php index c747c3130e..055ac2279a 100644 --- a/lib/plugins/styling/admin.php +++ b/lib/plugins/styling/admin.php @@ -57,9 +57,9 @@ public function html() { public function form() { global $conf; global $ID; - define('SIMPLE_TEST', 1); // hack, ideally certain functions should be moved out of css.php - require_once(DOKU_INC.'lib/exe/css.php'); - $styleini = css_styleini($conf['template'], true); + + $styleUtil = new \dokuwiki\StyleUtils(); + $styleini = $styleUtil->cssStyleini($conf['template'], true); $replacements = $styleini['replacements']; if($this->ispopup) { diff --git a/lib/tpl/dokuwiki/lang/en/lang.php b/lib/tpl/dokuwiki/lang/en/lang.php index b7b3e7fa11..7c890c6513 100644 --- a/lib/tpl/dokuwiki/lang/en/lang.php +++ b/lib/tpl/dokuwiki/lang/en/lang.php @@ -10,3 +10,4 @@ $lang['__sidebar_width__'] = 'The width of the sidebar, if any (can be any length unit: %, px, em, ...)'; $lang['__tablet_width__'] = 'Below screensizes of this width, the site switches to tablet mode'; $lang['__phone_width__'] = 'Below screensizes of this width, the site switches to phone mode'; +$lang['__theme_color__'] = 'Theme color of the web app'; diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 892a6a6e54..ca6de6aa1e 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -85,3 +85,5 @@ __sidebar_width__ = "16em" ; @ini_sidebar_width ; cut off points for mobile devices __tablet_width__ = "800px" ; @ini_tablet_width __phone_width__ = "480px" ; @ini_phone_width + +__theme_color__ = "#008800" ; @_ini_theme_color: theme_color of the web app