1<?php
2/**
3 * Tag Plugin: displays list of keywords with links to categories this page
4 * belongs to. The links are marked as tags for Technorati and other services
5 * using tagging.
6 *
7 * Usage: {{tag>category tags space separated}}
8 *
9 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 * @author   Esther Brunner <wikidesign@gmail.com>
11 */
12
13/**
14 * Tag syntax plugin, allows to specify tags in a page
15 */
16class syntax_plugin_tag_tag extends DokuWiki_Syntax_Plugin {
17
18    /**
19     * @return string Syntax type
20     */
21    function getType() { return 'substition'; }
22    /**
23     * @return int Sort order
24     */
25    function getSort() { return 305; }
26    /**
27     * @return string Paragraph type
28     */
29    function getPType() { return 'block';}
30
31    /**
32     * @param string $mode Parser mode
33     */
34    function connectTo($mode) {
35        $this->Lexer->addSpecialPattern('\{\{tag>.*?\}\}', $mode, 'plugin_tag_tag');
36    }
37
38    /**
39     * Handle matches of the tag syntax
40     *
41     * @param string $match The match of the syntax
42     * @param int    $state The state of the handler
43     * @param int    $pos The position in the document
44     * @param Doku_Handler    $handler The handler
45     * @return array|false Data for the renderer
46     */
47    function handle($match, $state, $pos, Doku_Handler $handler) {
48        $tags = trim(substr($match, 6, -2));     // strip markup & whitespace
49        $tags = trim($tags, "\xe2\x80\x8b"); // strip word/wordpad breaklines
50        $tags = preg_replace(['/[[:blank:]]+/', '/\s+/'], " ", $tags);    // replace linebreaks and multiple spaces with one space character
51        $tags = preg_replace('/[\x00-\x1F\x7F]/u', '', $tags); // strip unprintable ascii code out of utf-8 coded string
52
53        if (!$tags) return false;
54
55        // load the helper_plugin_tag
56        /** @var helper_plugin_tag $helper */
57        if (!$helper = $this->loadHelper('tag')) {
58            return false;
59        }
60
61        // split tags and returns for renderer
62        return $helper->parseTagList($tags);
63    }
64
65    /**
66     * Render xhtml output or metadata
67     *
68     * @param string         $format      Renderer mode (supported modes: xhtml and metadata)
69     * @param Doku_Renderer  $renderer  The renderer
70     * @param array          $data      The data from the handler function
71     * @return bool If rendering was successful.
72     */
73    function render($format, Doku_Renderer $renderer, $data) {
74        if ($data === false) return false;
75        /** @var helper_plugin_tag $helper */
76        if (!$helper = $this->loadHelper('tag')) return false;
77
78        // XHTML output
79        if ($format == 'xhtml') {
80            $tags = $helper->tagLinks($data);
81            if (!$tags) {
82                return true;
83            }
84            $renderer->doc .= '<div class="'.$this->getConf('tags_list_css').'">'
85                . '<span>'.DOKU_LF
86                . DOKU_TAB.$tags.DOKU_LF
87                . '</span>'
88                . '</div>'.DOKU_LF;
89            return true;
90
91        // for metadata renderer
92        } elseif ($format == 'metadata') {
93            /** @var Doku_Renderer_metadata $renderer */
94            // erase tags on persistent metadata no more used
95            if (isset($renderer->persistent['subject'])) {
96                unset($renderer->persistent['subject']);
97                $renderer->meta['subject'] = [];
98            }
99
100            if (!isset($renderer->meta['subject'])) {
101                $renderer->meta['subject'] = [];
102            }
103
104            // each registered tags in metadata and index should be valid IDs
105            $data = array_map('cleanID', $data);
106            // merge with previous tags and make the values unique
107            $renderer->meta['subject'] = array_unique(array_merge($renderer->meta['subject'], $data));
108
109            if ($renderer->capture) {
110                $renderer->doc .= DOKU_LF.implode(' ', $data).DOKU_LF;
111            }
112
113            // add references if tag page exists
114            foreach ($data as $tag) {
115                // resolve shortcuts
116                // Igor and later
117                if (class_exists('dokuwiki\File\PageResolver')) {
118                    $resolver = new dokuwiki\File\PageResolver($helper->getNamespace() . ':something');
119                    $tag = $resolver->resolveId($tag);
120                } else {
121                    // Compatibility with older releases
122                    resolve_pageid($helper->getNamespace(), $tag, $exists);
123                }
124                $renderer->meta['relation']['references'][$tag] = page_exists($tag);
125            }
126
127            return true;
128        }
129        return false;
130    }
131}
132