1<?php
2/**
3 * Plugin tcycle: tiny cycle
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author  Reinhard Kaeferboeck <rfk@kaeferboeck.info>
7 * @author  Trailjeep <trailjeep@gmail.com>
8 */
9
10// must be run within Dokuwiki
11if(!defined('DOKU_INC')) die();
12
13if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
14
15/**
16 * All DokuWiki plugins to extend the parser/rendering mechanism
17 * need to inherit from this class
18 */
19class syntax_plugin_tcycle extends DokuWiki_Syntax_Plugin {
20    function getType(){ return 'formatting';}
21    function getPType(){ return 'normal';}
22    function getAllowedTypes() { return array('container','substition','protected','disabled','formatting','paragraphs'); }
23    function getSort(){ return 195; }
24    function connectTo($mode) {
25        $this->Lexer->addEntryPattern('<tcycle.*?>(?=.*?</tcycle>)',$mode,'plugin_tcycle');
26        $this->Lexer->addPattern('\{\{.*\}\}','plugin_tcycle');
27    }
28    function postConnect() { $this->Lexer->addExitPattern('</tcycle>','plugin_tcycle'); }
29
30    /**
31     * Handle the match
32     */
33    function handle($match, $state, $pos, Doku_Handler $handler) {
34        switch($state) {
35            case DOKU_LEXER_ENTER:
36                $attributes  = strtolower(substr($match, 5, -1));
37                $dataspeed   = $this->_getAttribute($attributes, "data-speed", $this->getConf('data-speed'));
38                $datafx      = $this->_getAttribute($attributes, "data-fx", $this->getConf('data-fx'));
39                if (!in_array($datafx, array('scroll', 'fade'))) { $datafx = $this->getConf('data-fx'); }
40                $datatimeout = $this->_getAttribute($attributes, "data-timeout", $this->getConf('data-timeout'));
41                $width       = $this->_getAttribute($attributes, "width", $this->getConf('width'));
42                $height      = $this->_getAttribute($attributes, "height", $this->getConf('height'));
43                $namespace   = $this->_getAttribute($attributes, "namespace", $this->getConf('namespace'));
44                if ($namespace === 1) {
45                    $namespace = str_replace(':', '/', getNS(cleanID(getID())));
46                } elseif ($namespace !== 0) {
47                    $namespace = str_replace(':', '/', $namespace);
48                }
49                $metadata    = $this->_getAttribute($attributes, "metadata", $this->getConf('metadata'));
50                $objectfit   = $this->_getAttribute($attributes, "fit", $this->getConf('fit'));
51                if (!in_array($objectfit, array('fill','contain','cover','scale-down','none'))) { $objectfit = $this->getConf('fit'); }
52                return array($state, array($dataspeed, $datafx, $datatimeout, $width, $height, $namespace, $metadata, $objectfit));
53            case DOKU_LEXER_MATCHED:
54                global $conf;
55                $addimgs = trim($match);
56                $addimgs = preg_replace('/\{\{ ?:?/', $conf['mediadir'].'/', $addimgs);
57                $addimgs = preg_replace('/\?.*\}\}/', '', $addimgs);
58                $addimgs = preg_replace('/\| ?.*?\}\}/', '', $addimgs);
59                $addimgs = str_replace(':', '/', $addimgs);
60                $addimgs = preg_split('/\s+/', $addimgs);
61                return array($state, array($addimgs));
62            case DOKU_LEXER_UNMATCHED:
63                return array($state, $match);
64            case DOKU_LEXER_EXIT:
65                return array($state, '');
66        }
67        return array();
68    }
69
70    /**
71     * Create output
72     */
73    function render($mode, Doku_Renderer $renderer, $data) {
74        if($mode == 'xhtml'){
75            list($state,$match) = $data;
76            switch ($state) {
77                case DOKU_LEXER_ENTER :
78                    list($this->dataspeed, $this->datafx, $this->datatimeout, $this->width, $this->height, $this->namespace, $this->metadata, $this->objectfit) = $match;
79                    $renderer->doc .= '<div class="tcycle" style="width: '.$this->width.';"';
80                    $renderer->doc .= 'data-speed="'.$this->dataspeed.'" ';
81                    $renderer->doc .= 'data-fx="'.$this->datafx.'" ';
82                    $renderer->doc .= 'data-timeout="'.$this->datatimeout.'">';
83                    break;
84                case DOKU_LEXER_MATCHED:
85                    list($this->addimgs) = $match;
86                    break;
87                case DOKU_LEXER_UNMATCHED :
88                    $renderer->doc .= $renderer->_xmlEntities($match);
89                    break;
90                case DOKU_LEXER_EXIT :
91                    $images = $this->_getImages($this->namespace, $this->addimgs);
92                    $renderer->doc .= $images;
93                    $renderer->doc .= '</div>';
94                    break;
95            }
96            return true;
97        }
98        return false;
99    }
100
101    function _getAttribute($attributeString, $attribute, $default){
102        $retVal = $default;
103        $pos = strpos($attributeString, $attribute."=");
104        if ($pos === false) {
105            $pos = strpos($attributeString, $attribute." ");
106        }
107        if ($pos > 0) {
108            $pos = $pos + strlen($attribute);
109            $value = substr($attributeString,$pos);
110
111            //replace '=' and quote signs with null and trim leading spaces
112            $value = ltrim(str_replace(['=', "'", '"'], '', $value));
113
114            //grab the text before the next space
115            $pos = strpos($value, " ");
116            if ($pos > 0) {
117                $value = substr($value,0,$pos);
118            }
119            $retVal = hsc($value);
120        }
121        return $retVal;
122    }
123    function _getImages($namespace, $addimgs) {
124        global $conf;
125        $files  = array();
126        $images = '';
127        $target = $conf['target']['media'];
128        $relnf  = '';
129        if ($conf['relnofollow'] == 1) { $relnf = 'nofollow'; }
130        if ($namespace !== 0) { $files  = glob($conf['mediadir'].'/'.$namespace."/*.{jp*g,png,gif}", GLOB_BRACE); }
131        $files = array_merge((array)$files, (array)$addimgs);
132        foreach($files as $file) {
133            if (!is_file($file)) { break; }
134            $detail = str_replace($conf['mediadir'], '/_detail', $file);
135            $media  = str_replace($conf['mediadir'], '/_media', $file);
136            $meta  = new JpegMeta($file);
137            $title = $meta->getField('Simple.Title');
138            if ($title === "") { $title = " "; }
139            $alt   = $meta->getField('Iptc.Caption');
140            if ($alt === "") { $alt = " "; }
141            $images .= '<figure>';
142            if ($this->metadata === 1) { $images .= '<figcaption>'.$title.'</figcaption>'; }
143            $images .= '<a href="'.$detail.'" target="'.$target.'" rel ="'.$relnf.' noopener">';
144            $images .= '<img class="media" src="'.$media.'" title="'.$title.'" alt="'.$alt.'" style="object-fit: '.$this->objectfit.'; width: '.$this->width.'; height: '.$this->height.';" />';
145            $images .= '</a>';
146            if ( $this->metadata === 1 ) { $images .= '<figcaption>'.$alt.'</figcaption>'; }
147            $images .= '</figure>';
148        }
149        return $images;
150    }
151}
152//Setup VIM: ex: et ts=4 enc=utf-8 :
153