Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWA manifest and new @ini_theme_color replacement #2241

Merged
merged 13 commits into from Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions conf/manifest.json
@@ -0,0 +1,3 @@
{
"display": "standalone"
}
95 changes: 95 additions & 0 deletions inc/Manifest.php
@@ -0,0 +1,95 @@
<?php

namespace dokuwiki;

class Manifest
{
public function sendManifest()
{
$manifest = retrieveConfig('manifest', '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',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this refer to? There is no images folder in dokuwiki. There might be one in the template but you wouldn't want that one if you already found one in wiki: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',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are .ico files supported?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't read the spec yet, but MDN has them in their example: https://developer.mozilla.org/en-US/docs/Web/Manifest#icons

':favicon.ico',
'images/favicon.ico',
':wiki:logo',
];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're basically adding all of these if we find them, right? It would be nice to fall back to the DokuWiki logo if none could be found.


$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);
}
}
107 changes: 107 additions & 0 deletions inc/StyleUtils.php
@@ -0,0 +1,107 @@
<?php

namespace dokuwiki;

class StyleUtils
{
/**
* Load style ini contents
*
* Loads and merges style.ini files from template and config and prepares
* the stylesheet modes
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @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 <chris@jalakai.co.uk>
*
* @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;
}
}
4 changes: 4 additions & 0 deletions inc/config_cascade.php
Expand Up @@ -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'),
Expand Down
57 changes: 57 additions & 0 deletions inc/confutils.php
Expand Up @@ -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 [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error handling seems excessive. First of all it could probably be better handled with all the error codes in a lookup array (with the JSON* constants as the key).

Then I'm wondering about using trigger_error(). Have you tried what happens when you pass invalid json to json_decode()? I would assume that it already does trigger an error that would need to be supressed with @. When we do hande this ourselves I'd think an exception would be the better way?

}

return $conf;
}

/**
* Retrieve the requested configuration information
*
Expand Down
1 change: 1 addition & 0 deletions inc/load.php
Expand Up @@ -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',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be needed because the file is namespaced and the autoloader should take care of this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the class seems to be named StyleUtils?


'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
Expand Down
4 changes: 4 additions & 0 deletions inc/template.php
Expand Up @@ -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(
Expand Down