1<?php
2/**
3 * DokuWiki Plugin pageredirect (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Elan Ruusamäe <glen@delfi.ee>
7 * @author  David Lorentsen <zyberdog@quakenet.org>
8 */
9
10// must be run within Dokuwiki
11if(!defined('DOKU_INC')) die();
12
13class syntax_plugin_pageredirect extends DokuWiki_Syntax_Plugin {
14    /**
15     * @return string Syntax mode type
16     */
17    public function getType() {
18        return 'substition';
19    }
20
21    /**
22     * @return string Paragraph type
23     */
24    public function getPType() {
25        return 'block';
26    }
27
28    /**
29     * @return int Sort order - Low numbers go before high numbers
30     */
31    public function getSort() {
32        return 1;
33    }
34
35    /**
36     * Connect lookup pattern to lexer.
37     *
38     * @param string $mode Parser mode
39     */
40    public function connectTo($mode) {
41        // NOTE: each document is surrounted with \n by dokuwiki parser
42        // so it's safe to use \n in the pattern
43        // this fixes creole greedyness:
44        // https://github.com/glensc/dokuwiki-plugin-pageredirect/issues/18#issuecomment-249386268
45        $this->Lexer->addSpecialPattern('(?:~~REDIRECT>.+?~~|\n#(?i:redirect) [^\r\n]+)', $mode, 'plugin_pageredirect');
46    }
47
48    /**
49     * Handler to prepare matched data for the rendering process
50     *
51     * This function can only pass data to render() via its return value
52     * render() may be not be run during the object's current life.
53     *
54     * Usually you should only need the $match param.
55     *
56     * @param   string       $match   The text matched by the patterns
57     * @param   int          $state   The lexer state for the match
58     * @param   int          $pos     The character position of the matched text
59     * @param   Doku_Handler $handler Reference to the Doku_Handler object
60     * @return  array Return an array with all data you want to use in render
61     */
62    public function handle($match, $state, $pos, Doku_Handler $handler) {
63        // strip leading "\n" from creole-compatible pattern
64        $match = trim($match);
65
66        // extract target page from match pattern
67        if($match[0] == '#') {
68            # #REDIRECT PAGE
69            $id = substr($match, 10);
70        } else {
71            # ~~REDIRECT>PAGE~~
72            $id = substr($match, 11, -2);
73        }
74        $id = trim($id);
75
76        $is_external = preg_match('#^https?://#i', $id);
77
78        // resolve and clean the $id if it is not external
79        if(!$is_external) {
80            global $ID;
81            resolve_pageid(getNS($ID), $id, $exists);
82        }
83
84        return array($id, $is_external);
85    }
86
87    /**
88     * Handles the actual output creation.
89     *
90     * The function must not assume any other of the classes methods have been run
91     * during the object's current life. The only reliable data it receives are its
92     * parameters.
93     *
94     * The function should always check for the given output format and return false
95     * when a format isn't supported.
96     *
97     * $renderer contains a reference to the renderer object which is
98     * currently handling the rendering. You need to use it for writing
99     * the output. How this is done depends on the renderer used (specified
100     * by $format
101     *
102     * The contents of the $data array depends on what the handler() function above
103     * created
104     *
105     * @param string        $format   output format being rendered
106     * @param Doku_Renderer $renderer reference to the current renderer object
107     * @param array         $data     data created by handler()
108     * @return boolean return true if rendered correctly
109     */
110    public function render($format, Doku_Renderer $renderer, $data) {
111        if($format == 'xhtml') {
112            // add prepared note about redirection
113            $renderer->doc .= $this->redirect_message($data);
114
115            // hook into the post render event to allow the page to be redirected
116            global $EVENT_HANDLER;
117            /** @var action_plugin_pageredirect $action */
118            $action = plugin_load('action', 'pageredirect');
119            $EVENT_HANDLER->register_hook('TPL_ACT_RENDER', 'AFTER', $action, 'handle_dokuwiki_started');
120
121            return true;
122        }
123
124        if($format == 'metadata') {
125            // add redirection to metadata
126            $renderer->meta['relation']['isreplacedby'] = $data;
127
128            return true;
129        }
130
131        return false;
132    }
133
134    /**
135     * Create redirection message html
136     *
137     * @param string $page
138     * @return string
139     */
140    private function redirect_message($metadata) {
141        list($page, $is_external) = $metadata;
142        if(!$is_external) {
143            $link = html_wikilink($page);
144        } else {
145            $link = '<a href="' . hsc($page) . '" class="urlextern">' . hsc($page) . '</a>';
146        }
147
148        // prepare message here instead of in render
149        $message = '<div class="noteredirect">' . sprintf($this->getLang('redirect_to'), $link) . '</div>';
150
151        return $message;
152    }
153}
154