1<?php
2
3use dokuwiki\plugin\doi\Resolver\AbstractResolver;
4use \dokuwiki\plugin\doi\Resolver\DoiResolver;
5
6
7/**
8 * DokuWiki Plugin doi (Syntax Component)
9 *
10 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
11 * @author  Andreas Gohr <gohr@cosmocode.de>
12 */
13class syntax_plugin_doi_doi extends \dokuwiki\Extension\SyntaxPlugin
14{
15    /** @inheritDoc */
16    public function getType()
17    {
18        return 'substition';
19    }
20
21    /** @inheritDoc */
22    public function getPType()
23    {
24        return 'normal';
25    }
26
27    /** @inheritDoc */
28    public function getSort()
29    {
30        return 155;
31    }
32
33    /** @inheritDoc */
34    public function connectTo($mode)
35    {
36        $this->Lexer->addSpecialPattern('\[\[doi>[^\]]+\]\]', $mode, 'plugin_doi_doi');
37    }
38
39    /** @inheritDoc */
40    public function handle($match, $state, $pos, Doku_Handler $handler)
41    {
42        $match = substr($match, 2, -2);
43        list(, $id) = sexplode('>', $match, 2);
44        list($id, $title) = sexplode('|', $id, 2);
45        return ['id' => $id, 'title' => $title];
46    }
47
48    /** @inheritDoc */
49    public function render($mode, Doku_Renderer $renderer, $data)
50    {
51        $resolver = $this->getResolver();
52        $data['id'] = $resolver->cleanID($data['id']);
53
54        try {
55            $publication = $resolver->getData($data['id']);
56        } catch (Exception $e) {
57            msg(hsc($e->getMessage()), -1);
58            $url = $resolver->getFallbackURL($data['id']);
59            $title = empty($data['title']) ? $data['id'] : $data['title'];
60
61            $renderer->externallink($url, $title);
62            return true;
63        }
64
65        // overwritten title?
66        if (!empty($data['title'])) $publication['title'] = $data['title'];
67
68        if ($mode === 'xhtml') {
69            /** @var Doku_Renderer_xhtml $renderer */
70            $this->renderXHTML($publication, $renderer);
71        } else {
72            $this->renderAny($publication, $renderer);
73        }
74
75        return true;
76    }
77
78    /**
79     * @return AbstractResolver
80     */
81    protected function getResolver()
82    {
83        return new DoiResolver();
84    }
85
86    /**
87     * Render the given data on the XHTML renderer
88     *
89     * Adds various classes to the output for CSS styling
90     *
91     * @param array $data
92     * @param Doku_Renderer_xhtml $renderer
93     * @return void
94     */
95    protected function renderXHTML($data, $renderer)
96    {
97        $renderer->doc .= '<div class="plugin_doi ' . hsc($data['type']) . '">';
98        $renderer->externallink($data['url'], $data['title']);
99
100        if ($data['published']) {
101            $renderer->doc .= ' <span>(' . hsc($data['published']) . ')</span>';
102        }
103
104        $renderer->doc .= '<div class="meta">';
105        if ($data['authors']) {
106            $authors = array_map(function ($author) {
107                return '<strong>' . hsc($author) . '</strong>';
108            }, $data['authors']);
109            $renderer->doc .= '<span class="authors">' . join(', ', $authors) . '</span>';
110        }
111        if ($data['journal']) {
112            $journal = $data['journal'];
113            $journal .= ' ' . join('/', array_filter([$data['volume'] ?? null, $data['issue'] ?? null]));
114            $journal = '<span>' . hsc($journal) . '</span>';
115            if ($data['page']) {
116                $journal .= ' <i>p' . hsc($data['page']) . '</i>';
117            }
118            $renderer->doc .= ' <span class="journal">' . $journal . '</span>';
119        }
120        $renderer->doc .= '</div>';
121
122        $renderer->doc .= '<div class="meta">';
123        if ($data['publisher']) {
124            $renderer->doc .= '<span class="publisher">' . hsc($data['publisher']) . '</span>';
125        }
126        $renderer->doc .= ' <code class="id">' . $data['idtype'] . ':' . hsc($data['id']) . '</code>';
127        $renderer->doc .= '</div>';
128
129        $renderer->doc .= '</div>';
130    }
131
132    /**
133     * Render the given data on any renderer
134     *
135     * Uses renderer methods only
136     *
137     * @param array $data
138     * @param Doku_Renderer $renderer
139     * @return void
140     */
141    protected function renderAny($data, $renderer)
142    {
143        $renderer->p_open();
144        $renderer->externallink($data['url'], $data['title']);
145
146        if ($data['published']) {
147            $renderer->cdata(' (' . hsc($data['published']) . ')');
148        }
149        $renderer->linebreak();
150
151        if ($data['authors']) {
152            $len = count($data['authors']);
153            for ($i = 0; $i < $len; $i++) {
154                $renderer->strong_open();
155                $renderer->cdata($data['authors'][$i]);
156                $renderer->strong_close();
157                if ($i < $len - 1) {
158                    $renderer->cdata(', ');
159                }
160            }
161
162            if ($data['journal']) {
163                $journal = $data['journal'];
164                $journal .= ' ' . join('/', array_filter([$data['volume'] ?? null, $data['issue'] ?? null]));
165                $renderer->cdata(' ' . $journal);
166            }
167
168            if ($data['page']) {
169                $renderer->cdata(' ');
170                $renderer->emphasis_open();
171                $renderer->cdata('p' . $data['page']);
172                $renderer->emphasis_close();
173            }
174        }
175        $renderer->linebreak();
176
177        if ($data['publisher']) {
178            $renderer->cdata($data['publisher']);
179            $renderer->cdata(' ');
180        }
181        $renderer->monospace_open();
182        $renderer->cdata($data['idtype'] . ':' . hsc($data['id']));
183        $renderer->monospace_close();
184
185        $renderer->p_close();
186    }
187}
188
189