* @copyright (C) 2015-2018, Giuseppe Di Terlizzi
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
class syntax_plugin_icons_icon extends DokuWiki_Syntax_Plugin {
const IS_ICON = null;
const IS_FONT_ICON = null;
protected $pattern = '{{icon>.+?}}';
protected $linkPattern = '\[\[[^\]\r\n]*\|%s\]\]';
protected $flags = array();
protected $classes = array();
protected $styles = array();
/**
* Syntax Type
*
* Needs to return one of the mode types defined in $PARSER_MODES in parser.php
*
* @return string
*/
public function getType() { return 'substition'; }
/**
* Sort for applying this mode
*
* @return int
*/
public function getSort() { return 299; }
/**
* @param string $mode
*/
public function connectTo($mode) {
$this->Lexer->addSpecialPattern($this->pattern, $mode, 'plugin_icons_'.$this->getPluginComponent());
$this->Lexer->addSpecialPattern(sprintf($this->linkPattern, $this->pattern), $mode, 'plugin_icons_'.$this->getPluginComponent());
}
/**
* Handler to prepare matched data for the rendering process
*
* @param string $match The text matched by the patterns
* @param int $state The lexer state for the match
* @param int $pos The character position of the matched text
* @param Doku_Handler $handler The Doku_Handler object
* @return bool|array Return an array with all data you want to use in render, false don't add an instruction
*/
public function handle($match, $state, $pos, Doku_Handler $handler) {
$url = null;
$flags = array();
$title = null;
$pack = null;
$icon = null;
$match = substr($match, 2, -2); // strip markup
@list($match, $title, $title2) = explode('|', $match);
if (isset($title2)) $title .= '}}';
if (isset($title) && preg_match('/'.$this->pattern.'/', $title)) {
$url = $match;
$match = $title;
$match = substr($match, 2, -2); // strip markup
list($match, $title) = explode('|', $match);
if (isset($title2)) $title = rtrim($title2, '}');
}
$align_left = false;
$align_right = false;
$align_center = false;
$align_flag = '';
if (substr($match, 0, 1) == ' ') {
$align_right = true;
$align_flag = "align=right";
}
if (substr($match, -1, 1) == ' ') {
$align_left = true;
$align_flag = "align=left";
}
if ($align_left && $align_right) {
$align_center = true;
$align_flag = "align=center";
}
list($match, $flags) = explode('?', trim($match), 2);
list($pack, $icon) = explode('>', trim($match), 2);
$flags .= "&$align_flag";
return array($pack, $icon, explode('&', rtrim($flags, '&')), $title, $url, $match, $state, $pos);
}
/**
* Handles the actual output creation.
*
* @param string $mode output format being rendered
* @param Doku_Renderer $renderer the current renderer object
* @param array $data data created by handler()
* @return boolean rendered correctly? (however, returned value is not used at the moment)
*/
public function render($mode, Doku_Renderer $renderer, $data) {
if ($mode !== 'xhtml') return false;
/** @var Doku_Renderer_xhtml $renderer */
list($pack, $icon, $flags, $title, $url) = $data;
$this->parseFlags($pack, $icon, $flags);
if ($this->isIcon()) {
$icon_size = $this->getFlag('size');
$icon_pack = $this->getFlag('pack');
$icon_base_url = rtrim($this->getConf(sprintf('%sURL', $icon_pack)), '/');
$icon_url = $this->makePath($icon, $icon_size, $icon_base_url);
$cached_icon_url = ml($icon_url, array('cache' => 'recache', 'w' => $icon_size, 'h' => $icon_size));
$icon_markup = sprintf('',
$cached_icon_url, $title,
$this->toClassString($this->getClasses()),
$this->toInlineStyle($this->getStyles()));
} else {
if ($this->getFlag('pack') == 'material') {
$this->classes[] = 'material-icons';
# Material Icons use ligatures feature supported in most modern browsers
# on both desktop and mobile devices.
$icon_markup = sprintf('%s',
$this->toClassString($this->getClasses()),
$this->toInlineStyle($this->getStyles()),
$title, $icon);
} else {
$this->classes[] = $this->getFlag('pack');
$this->classes[] = sprintf('%s-%s', $this->getFlag('pack'), $icon);
$icon_markup = sprintf('',
$this->toClassString($this->getClasses()),
$this->toInlineStyle($this->getStyles()),
$title);
}
}
if (isset($url)) {
global $conf;
global $ID;
$is_external = false;
$exists = false;
$link = array();
if (preg_match('/^(http?|ftp?|www?)/', $url)) {
$is_external = true;
} else {
resolve_pageid(getNS($ID), $url, $exists);
$url = wl($url);
}
$link['target'] = ($is_external) ? $conf['target']['extern'] : $conf['target']['wiki'];
$link['style'] = '';
$link['pre'] = '';
$link['suf'] = '';
$link['more'] = '';
$link['class'] = '';
$link['url'] = $url;
$link['name'] = $icon_markup;
if ($exists) {
$link['class'] = 'wikilink1';
} else {
$link['rel'] = 'nofollow';
if (! $is_external) {
$link['class'] = 'wikilink2';
}
}
$renderer->doc .= $renderer->_formatLink($link);
return true;
}
$renderer->doc .= $icon_markup;
return true;
}
protected function isIcon() {
$class_icon = sprintf('syntax_plugin_icons_%s', $this->getFlag('pack'));
return constant("$class_icon::IS_ICON");
}
protected function isFontIcon() {
$class_icon = sprintf('syntax_plugin_icons_%s', $this->getFlag('pack'));
return constant("$class_icon::IS_FONT_ICON");
}
protected function toClassString($things) {
return trim(implode(' ', $things), ' ');
}
protected function toInlineStyle($things) {
$result = '';
foreach ($things as $property => $value) {
$result .= "$property:$value;";
}
$result = trim($result, ';');
return $result;
}
protected function getFlag($name) {
return (isset($this->flags[$name]) ? $this->flags[$name] : null);
}
protected function getFlags() {
return $this->flags;
}
protected function parseFlags($pack, $icon, $flags) {
$this->flags = array();
$this->classes = array();
$this->styles = array();
$this->flags['pack'] = $pack;
$this->flags['icon'] = $icon;
if ((int) $flags[0] > 0 && ! in_array($flags[0], array('2x', '3x', '4x', '5x'))) {
$flags[] = "size=" . $flags[0];
unset($flags[0]);
}
if ($left = array_search('left', $flags)) {
$flags[] = 'align=left';
unset($flags[$left]);
}
if ($right = array_search('right', $flags)) {
$flags[] = 'align=right';
unset($flags[$right]);
}
if ($center = array_search('center', $flags)) {
$flags[] = 'align=center';
unset($flags[$center]);
}
foreach ($flags as $flag) {
@list($flag, $value) = explode('=', $flag);
if (! $flag) continue;
$this->flags[$flag] = $value;
switch ($flag) {
case 'size':
$this->flags[$flag] = (int) $value;
if ($this->isFontIcon()) {
$this->styles['font-size'] = "{$value}px";
}
break;
case 'circle':
$this->flags[$flag] = true;
$this->styles['border-radius'] = '50%';
$this->styles['-moz-border-radius'] = '50%';
$this->styles['-webkit-border-radius'] = '50%';
break;
case 'border':
$this->flags[$flag] = true;
if ($this->flags['pack'] == 'fa') {
$this->classes[] = 'fa-border';
} else {
$this->styles['border'] = '0.08em solid #EEE';
}
break;
case 'borderColor':
$this->styles['border-color'] = $value;
break;
case 'padding':
$this->styles['padding'] = $value;
break;
case 'background':
$this->styles['background-color'] = $value;
break;
case 'color':
$this->styles['color'] = $value;
break;
case 'class':
$this->classes[] = $value;
break;
case 'align':
if ($this->isIcon()) {
$this->classes[] = "media$value";
} else {
if ($value == 'center') {
$this->styles['text-align'] = 'center';
} else {
$this->styles['padding-'.(($value == 'left') ? 'right' : 'left')] = '.2em';
$this->styles['float'] = $value;
}
}
break;
case 'rotate':
if (in_array($value, array(90, 180, 270))) {
$this->classes[] = "fa-rotate-$value";
}
break;
case 'flip':
if (in_array($value, array('horizontal', 'vertical'))) {
$this->classes[] = "fa-flip-$value";
}
break;
case 'pull-left':
case 'pullLeft':
case 'pull-right':
case 'pullRight':
case 'spin':
case 'pulse':
$this->classes[] = "fa-$flag";
break;
case 'fw':
case 'lg':
case '2x':
case '3x':
case '4x':
case '5x':
$this->classes[] = "fa-$flag";
$this->flags['size'] = true;
unset($this->styles['font-size']);
break;
default:
$this->classes[] = $flag;
}
}
if (! isset($this->flags['size'])) {
$this->flags['size'] = (int) $this->getConf('defaultSize');
if ($this->isFontIcon()) {
$this->styles['font-size'] = $this->getConf('defaultSize') . "px";
}
}
if ($this->flags['pack'] == 'icon') {
$this->flags['pack'] = $this->getConf('defaultPack');
}
}
protected function getStyles() {
return $this->styles;
}
protected function getClasses() {
return $this->classes;
}
public static function makePath($icon, $size, $base_url) {
return true;
}
}