From 5e0255e36bf156b973d6ab46192daa88891c0027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 24 Jan 2018 14:24:48 +0100 Subject: [PATCH 01/13] feat: provide web app manifest (dynamically geneated) --- inc/config_cascade.php | 4 ++ inc/template.php | 4 ++ lib/exe/manifest.php | 134 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 lib/exe/manifest.php 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/template.php b/inc/template.php index c44cd064ce..b9fe960851 100644 --- a/inc/template.php +++ b/inc/template.php @@ -242,6 +242,10 @@ function tpl_metaheaders($alt = true) { ); } + if (actionOK('manifest')) { + $head['link'][] = array('rel'=> 'manifest', 'href'=> DOKU_BASE.'lib/exe/manifest.php'); + } + if($alt) { if(actionOK('rss')) { $head['link'][] = array( diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php new file mode 100644 index 0000000000..5f22f1ccfb --- /dev/null +++ b/lib/exe/manifest.php @@ -0,0 +1,134 @@ + $url, + 'sizes' => $imginfo[0] . 'x' . $imginfo[1], + 'type' => $imginfo['mime'], + ]; + }; + } + } + + trigger_event('MANIFEST_SEND', $manifest); + + header('Content-Type: application/manifest+json'); + echo json_encode($manifest); + } + + public function jsonToArray($file) + { + $json = file_get_contents($file); + + $conf = json_decode($json, true); + + $jsonError = json_last_error(); + if (!is_array($conf) && $jsonError !== JSON_ERROR_NONE) { + + switch ($jsonError) { + case JSON_ERROR_DEPTH: + $jsonErrorText = 'The maximum stack depth has been exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $jsonErrorText = 'Invalid or malformed JSON'; + break; + case JSON_ERROR_CTRL_CHAR: + $jsonErrorText = 'Control character error, possibly incorrectly encoded'; + break; + case JSON_ERROR_SYNTAX: + $jsonErrorText = 'Syntax error'; + break; + case JSON_ERROR_UTF8: + $jsonErrorText = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + case JSON_ERROR_RECURSION: + $jsonErrorText = 'One or more recursive references in the value to be encoded'; + break; + case JSON_ERROR_INF_OR_NAN: + $jsonErrorText = 'One or more NAN or INF values in the value to be encoded'; + break; + case JSON_ERROR_UNSUPPORTED_TYPE: + $jsonErrorText = 'A value of a type that cannot be encoded was given'; + break; + case JSON_ERROR_INVALID_PROPERTY_NAME: + $jsonErrorText = 'A property name that cannot be encoded was given'; + break; + case JSON_ERROR_UTF16: + $jsonErrorText = 'Malformed UTF-16 characters, possibly incorrectly encoded'; + break; + default: + $jsonErrorText = 'Unknown Error Code'; + } + + trigger_error('JSON decoding error "' . $jsonErrorText . '" for file ' . $file, E_USER_WARNING); + return []; + } + + return $conf; + } +} + +$manifest = new Manifest(); +$manifest->run(); From ff1e4eaee6c4bc12774c394adf3cab2acb2bf6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 24 Jan 2018 15:19:35 +0100 Subject: [PATCH 02/13] fix: add default manifest.json This should have been part of the previous commit 5e0255e36bf156b973d6ab46192daa88891c0027 Some simple static defaults for the PWA manifest --- conf/manifest.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 conf/manifest.json diff --git a/conf/manifest.json b/conf/manifest.json new file mode 100644 index 0000000000..f7e98b97fb --- /dev/null +++ b/conf/manifest.json @@ -0,0 +1,4 @@ +{ + "display": "standalone", + "background_color": "#ffffff" +} From fb1f9089ad53554574c96fe6f86cc029958f87e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Thu, 1 Feb 2018 11:36:11 +0100 Subject: [PATCH 03/13] refactor: extract css utils to an autoloaded class The goal is to make the css replacement accessible in other contexts, for example for the manifest. --- inc/StyleUtils.php | 107 ++++++++++++++++++++++++++++++++++ inc/load.php | 1 + lib/exe/css.php | 103 +------------------------------- lib/plugins/styling/admin.php | 6 +- 4 files changed, 113 insertions(+), 104 deletions(-) create mode 100644 inc/StyleUtils.php 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/load.php b/inc/load.php index b6613d6980..9d109dcae6 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,7 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', + 'StyleUtil' => DOKU_INC.'inc/StyleUtil.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', 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/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) { From 6f8582363c4b84eb5db1b587f9ad46df9a194159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Thu, 1 Feb 2018 11:38:09 +0100 Subject: [PATCH 04/13] feat: use style replacements for background and theme color This also adds the default theme color for the DokuWiki template as the green from the existing links. --- conf/manifest.json | 3 +-- lib/exe/manifest.php | 12 ++++++++++++ lib/tpl/dokuwiki/lang/en/lang.php | 1 + lib/tpl/dokuwiki/style.ini | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/conf/manifest.json b/conf/manifest.json index f7e98b97fb..891bd79fbf 100644 --- a/conf/manifest.json +++ b/conf/manifest.json @@ -1,4 +1,3 @@ { - "display": "standalone", - "background_color": "#ffffff" + "display": "standalone" } diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php index 5f22f1ccfb..d9d3e20b5a 100644 --- a/lib/exe/manifest.php +++ b/lib/exe/manifest.php @@ -27,6 +27,18 @@ public function run() { $manifest['start_url'] = DOKU_REL; } + $styleUtil = new \dokuwiki\StyleUtils(); + $styleIni = $styleUtil->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'] = []; $look = [ 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 From 10b4c8435636e679868d7659f1dd1e2031018364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Thu, 1 Feb 2018 11:53:33 +0100 Subject: [PATCH 05/13] feat: ensure that the cope is always only the current wiki --- lib/exe/manifest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php index d9d3e20b5a..e7a5f1f8b1 100644 --- a/lib/exe/manifest.php +++ b/lib/exe/manifest.php @@ -11,6 +11,8 @@ public function run() { global $conf; + $manifest['scope'] = DOKU_REL; + if (empty($manifest['name'])) { $manifest['name'] = $conf['title']; } From c90718343a6d54f1212fc3900fca635375ea422d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Mon, 5 Feb 2018 10:42:09 +0100 Subject: [PATCH 06/13] refactor: move manifest functions to more intuitive places --- inc/Manifest.php | 95 ++++++++++++++++++++++++++++ inc/confutils.php | 57 +++++++++++++++++ lib/exe/manifest.php | 143 +------------------------------------------ 3 files changed, 154 insertions(+), 141 deletions(-) create mode 100644 inc/Manifest.php diff --git a/inc/Manifest.php b/inc/Manifest.php new file mode 100644 index 0000000000..53c5d2d92a --- /dev/null +++ b/inc/Manifest.php @@ -0,0 +1,95 @@ +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'] = []; + $look = [ + ':wiki:logo.png', + ':logo.png', + 'images/logo.png', + ':wiki:apple-touch-icon.png', + ':apple-touch-icon.png', + 'images/apple-touch-icon.png', + ':wiki:favicon.svg', + ':favicon.svg', + 'images/favicon.svg', + ':wiki:favicon.ico', + ':favicon.ico', + 'images/favicon.ico', + ':wiki:logo', + ]; + + $abs = true; + foreach ($look as $img) { + if ($img[0] === ':') { + $file = mediaFN($img); + $ismedia = true; + } else { + $file = tpl_incdir() . $img; + $ismedia = false; + } + + if (file_exists($file)) { + $imginfo = getimagesize($file); + if ($ismedia) { + $url = ml($img, '', true, '', $abs); + } else { + $url = tpl_basedir() . $img; + if ($abs) { + $url = DOKU_URL . substr($url, strlen(DOKU_REL)); + } + } + $manifest['icons'][] = [ + 'src' => $url, + 'sizes' => $imginfo[0] . 'x' . $imginfo[1], + 'type' => $imginfo['mime'], + ]; + }; + } + } + + trigger_event('MANIFEST_SEND', $manifest); + + header('Content-Type: application/manifest+json'); + echo json_encode($manifest); + } +} diff --git a/inc/confutils.php b/inc/confutils.php index f753b18c2a..7224b467ac 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -255,6 +255,63 @@ 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); + + $jsonError = json_last_error(); + if (!is_array($conf) && $jsonError !== JSON_ERROR_NONE) { + + switch ($jsonError) { + case JSON_ERROR_DEPTH: + $jsonErrorText = 'The maximum stack depth has been exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $jsonErrorText = 'Invalid or malformed JSON'; + break; + case JSON_ERROR_CTRL_CHAR: + $jsonErrorText = 'Control character error, possibly incorrectly encoded'; + break; + case JSON_ERROR_SYNTAX: + $jsonErrorText = 'Syntax error'; + break; + case JSON_ERROR_UTF8: + $jsonErrorText = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + case JSON_ERROR_RECURSION: + $jsonErrorText = 'One or more recursive references in the value to be encoded'; + break; + case JSON_ERROR_INF_OR_NAN: + $jsonErrorText = 'One or more NAN or INF values in the value to be encoded'; + break; + case JSON_ERROR_UNSUPPORTED_TYPE: + $jsonErrorText = 'A value of a type that cannot be encoded was given'; + break; + case JSON_ERROR_INVALID_PROPERTY_NAME: + $jsonErrorText = 'A property name that cannot be encoded was given'; + break; + case JSON_ERROR_UTF16: + $jsonErrorText = 'Malformed UTF-16 characters, possibly incorrectly encoded'; + break; + default: + $jsonErrorText = 'Unknown Error Code'; + } + + trigger_error('JSON decoding error "' . $jsonErrorText . '" for file ' . $file, E_USER_WARNING); + return []; + } + + return $conf; +} + /** * Retrieve the requested configuration information * diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php index e7a5f1f8b1..a5c1882024 100644 --- a/lib/exe/manifest.php +++ b/lib/exe/manifest.php @@ -5,144 +5,5 @@ } require_once(DOKU_INC . 'inc/init.php'); -class Manifest { - public function run() { - $manifest = retrieveConfig('manifest', [$this, 'jsonToArray']); - - global $conf; - - $manifest['scope'] = DOKU_REL; - - if (empty($manifest['name'])) { - $manifest['name'] = $conf['title']; - } - - if (empty($manifest['short_name'])) { - $manifest['short_name'] = $conf['title']; - } - - if (empty($manifest['description'])) { - $manifest['description'] = $conf['tagline']; - } - - if (empty($manifest['start_url'])) { - $manifest['start_url'] = DOKU_REL; - } - - $styleUtil = new \dokuwiki\StyleUtils(); - $styleIni = $styleUtil->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'] = []; - $look = [ - ':wiki:logo.png', - ':logo.png', - 'images/logo.png', - ':wiki:apple-touch-icon.png', - ':apple-touch-icon.png', - 'images/apple-touch-icon.png', - ':wiki:favicon.svg', - ':favicon.svg', - 'images/favicon.svg', - ':wiki:favicon.ico', - ':favicon.ico', - 'images/favicon.ico', - ':wiki:logo', - ]; - - $abs = true; - foreach($look as $img) { - if($img[0] === ':') { - $file = mediaFN($img); - $ismedia = true; - } else { - $file = tpl_incdir().$img; - $ismedia = false; - } - - if (file_exists($file)) { - $imginfo = getimagesize($file); - if($ismedia) { - $url = ml($img, '', true, '', $abs); - } else { - $url = tpl_basedir().$img; - if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL)); - } - $manifest['icons'][] = [ - 'src' => $url, - 'sizes' => $imginfo[0] . 'x' . $imginfo[1], - 'type' => $imginfo['mime'], - ]; - }; - } - } - - trigger_event('MANIFEST_SEND', $manifest); - - header('Content-Type: application/manifest+json'); - echo json_encode($manifest); - } - - public function jsonToArray($file) - { - $json = file_get_contents($file); - - $conf = json_decode($json, true); - - $jsonError = json_last_error(); - if (!is_array($conf) && $jsonError !== JSON_ERROR_NONE) { - - switch ($jsonError) { - case JSON_ERROR_DEPTH: - $jsonErrorText = 'The maximum stack depth has been exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $jsonErrorText = 'Invalid or malformed JSON'; - break; - case JSON_ERROR_CTRL_CHAR: - $jsonErrorText = 'Control character error, possibly incorrectly encoded'; - break; - case JSON_ERROR_SYNTAX: - $jsonErrorText = 'Syntax error'; - break; - case JSON_ERROR_UTF8: - $jsonErrorText = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - case JSON_ERROR_RECURSION: - $jsonErrorText = 'One or more recursive references in the value to be encoded'; - break; - case JSON_ERROR_INF_OR_NAN: - $jsonErrorText = 'One or more NAN or INF values in the value to be encoded'; - break; - case JSON_ERROR_UNSUPPORTED_TYPE: - $jsonErrorText = 'A value of a type that cannot be encoded was given'; - break; - case JSON_ERROR_INVALID_PROPERTY_NAME: - $jsonErrorText = 'A property name that cannot be encoded was given'; - break; - case JSON_ERROR_UTF16: - $jsonErrorText = 'Malformed UTF-16 characters, possibly incorrectly encoded'; - break; - default: - $jsonErrorText = 'Unknown Error Code'; - } - - trigger_error('JSON decoding error "' . $jsonErrorText . '" for file ' . $file, E_USER_WARNING); - return []; - } - - return $conf; - } -} - -$manifest = new Manifest(); -$manifest->run(); +$manifest = new \dokuwiki\Manifest(); +$manifest->sendManifest(); From ac6ceee39397df8191bff60624aad343e50fdfe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Fri, 16 Feb 2018 18:54:49 +0100 Subject: [PATCH 07/13] fix(manifest): check if manifest action enabled before sending --- lib/exe/manifest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php index a5c1882024..d11bb53105 100644 --- a/lib/exe/manifest.php +++ b/lib/exe/manifest.php @@ -5,5 +5,10 @@ } require_once(DOKU_INC . 'inc/init.php'); +if (!actionOK('manifest')) { + http_status(404, 'Manifest has been disabled in DokuWiki configuration.'); + return; +} + $manifest = new \dokuwiki\Manifest(); $manifest->sendManifest(); From 2d8226d6a33a982bdf5868e54ccfc9158e8a4a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:24:44 +0100 Subject: [PATCH 08/13] feat(PWAManifest): Use sensible defaults for icons Defining SVG both as 17x17 and 512x512 is intended to support custom splash screens, though the documentation is somewhat unclear. This currently satisfies the Google Lighthouse auditing tool. --- inc/Manifest.php | 55 ++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/inc/Manifest.php b/inc/Manifest.php index 53c5d2d92a..0df9c2b819 100644 --- a/inc/Manifest.php +++ b/inc/Manifest.php @@ -42,47 +42,32 @@ public function sendManifest() 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.png', - ':logo.png', - 'images/logo.png', - ':wiki:apple-touch-icon.png', - ':apple-touch-icon.png', - 'images/apple-touch-icon.png', - ':wiki:favicon.svg', - ':favicon.svg', - 'images/favicon.svg', - ':wiki:favicon.ico', - ':favicon.ico', - 'images/favicon.ico', - ':wiki:logo', + ':wiki:logo.svg', + ':logo.svg', + ':wiki:dokuwiki.svg' ]; - $abs = true; - foreach ($look as $img) { - if ($img[0] === ':') { - $file = mediaFN($img); - $ismedia = true; - } else { - $file = tpl_incdir() . $img; - $ismedia = false; - } - - if (file_exists($file)) { - $imginfo = getimagesize($file); - if ($ismedia) { - $url = ml($img, '', true, '', $abs); - } else { - $url = tpl_basedir() . $img; - if ($abs) { - $url = DOKU_URL . substr($url, strlen(DOKU_REL)); - } - } + foreach ($look as $svgLogo) { + + $svgLogoFN = mediaFN($svgLogo); + + if (file_exists($svgLogoFN)) { + $url = ml($svgLogo, '', true, '', true); $manifest['icons'][] = [ 'src' => $url, - 'sizes' => $imginfo[0] . 'x' . $imginfo[1], - 'type' => $imginfo['mime'], + 'sizes' => '17x17 512x512', + 'type' => 'image/svg+xml', ]; + break; }; } } From b52493c2b149cbcb6220182bf2bc94a39cba437d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:27:50 +0100 Subject: [PATCH 09/13] feat: add DokuWiki SVG logo --- data/media/wiki/dokuwiki.svg | 586 +++++++++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 data/media/wiki/dokuwiki.svg 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 40ca854045b82f2501688b96ac3150ce66fd4b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:29:15 +0100 Subject: [PATCH 10/13] feat(metaheaders): Set theme-color meta header This color is for example shown in Chrome on Android as menu-bar coloring. --- inc/template.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/inc/template.php b/inc/template.php index b9fe960851..659d590493 100644 --- a/inc/template.php +++ b/inc/template.php @@ -246,6 +246,13 @@ function tpl_metaheaders($alt = true) { $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( From 6c4fa3b37e8603ae865e9fc27a6c3f562404e738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:35:04 +0100 Subject: [PATCH 11/13] fix: StyleUtils is already handled by the autoloader Since StyleUtils has a namespace, it is already handled correctly by the autoloader. This is further underlined by the fact that the removed line isn't actually working because of the missing `s` in the classname. --- inc/load.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/load.php b/inc/load.php index 9d109dcae6..b6613d6980 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,7 +82,6 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', - 'StyleUtil' => DOKU_INC.'inc/StyleUtil.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', From f3d2b6aeee3acd25f1418e23f326a5962384621a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:40:59 +0100 Subject: [PATCH 12/13] fix: use exit instead of return in the global scope --- lib/exe/manifest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/manifest.php b/lib/exe/manifest.php index d11bb53105..e9a35289c0 100644 --- a/lib/exe/manifest.php +++ b/lib/exe/manifest.php @@ -7,7 +7,7 @@ if (!actionOK('manifest')) { http_status(404, 'Manifest has been disabled in DokuWiki configuration.'); - return; + exit(); } $manifest = new \dokuwiki\Manifest(); From dceb2cc1515e89a918d4a1b29f749e94d88f2a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Wed, 7 Mar 2018 11:52:49 +0100 Subject: [PATCH 13/13] fix: drop JSON error handling This isn't really the best place for that error handling. --- inc/confutils.php | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/inc/confutils.php b/inc/confutils.php index 7224b467ac..59147010f1 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -267,45 +267,7 @@ function jsonToArray($file) $conf = json_decode($json, true); - $jsonError = json_last_error(); - if (!is_array($conf) && $jsonError !== JSON_ERROR_NONE) { - - switch ($jsonError) { - case JSON_ERROR_DEPTH: - $jsonErrorText = 'The maximum stack depth has been exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $jsonErrorText = 'Invalid or malformed JSON'; - break; - case JSON_ERROR_CTRL_CHAR: - $jsonErrorText = 'Control character error, possibly incorrectly encoded'; - break; - case JSON_ERROR_SYNTAX: - $jsonErrorText = 'Syntax error'; - break; - case JSON_ERROR_UTF8: - $jsonErrorText = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - case JSON_ERROR_RECURSION: - $jsonErrorText = 'One or more recursive references in the value to be encoded'; - break; - case JSON_ERROR_INF_OR_NAN: - $jsonErrorText = 'One or more NAN or INF values in the value to be encoded'; - break; - case JSON_ERROR_UNSUPPORTED_TYPE: - $jsonErrorText = 'A value of a type that cannot be encoded was given'; - break; - case JSON_ERROR_INVALID_PROPERTY_NAME: - $jsonErrorText = 'A property name that cannot be encoded was given'; - break; - case JSON_ERROR_UTF16: - $jsonErrorText = 'Malformed UTF-16 characters, possibly incorrectly encoded'; - break; - default: - $jsonErrorText = 'Unknown Error Code'; - } - - trigger_error('JSON decoding error "' . $jsonErrorText . '" for file ' . $file, E_USER_WARNING); + if ($conf === null) { return []; }