1<?php
2
3use ComboStrap\DisqusIdentifier;
4use ComboStrap\ExceptionNotExists;
5use ComboStrap\LogUtility;
6use ComboStrap\Meta\Store\MetadataDokuWikiStore;
7use ComboStrap\MarkupPath;
8use ComboStrap\PluginUtility;
9
10
11/**
12 * Disqus integration
13 * https://combostrap.com/disqus
14 */
15class syntax_plugin_combo_disqus extends DokuWiki_Syntax_Plugin
16{
17
18    const CONF_DEFAULT_ATTRIBUTES = 'disqusDefaultAttributes';
19
20    const ATTRIBUTE_SHORTNAME = "shortname";
21    const ATTRIBUTE_IDENTIFIER = 'id';
22    const ATTRIBUTE_TITLE = 'title';
23    const ATTRIBUTE_URL = 'url';
24
25    const TAG = 'disqus';
26
27    const ATTRIBUTE_CATEGORY = "category";
28
29    /**
30     * Syntax Type.
31     *
32     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
33     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
34     */
35    function getType()
36    {
37        return 'substition';
38    }
39
40    /**
41     * Syntax Type.
42     *
43     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
44     * @see DokuWiki_Syntax_Plugin::getType()
45     */
46    function getPType()
47    {
48        return 'block';
49    }
50
51    /**
52     * Plugin priority
53     *
54     * @see Doku_Parser_Mode::getSort()
55     *
56     * the mode with the lowest sort number will win out
57     */
58    function getSort()
59    {
60        return 160;
61    }
62
63    /**
64     * Create a pattern that will called this plugin
65     *
66     * @param string $mode
67     * @see Doku_Parser_Mode::connectTo()
68     */
69    function connectTo($mode)
70    {
71        $pattern = PluginUtility::getEmptyTagPattern(self::TAG);
72        $this->Lexer->addSpecialPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
73    }
74
75    /**
76     *
77     * The handle function goal is to parse the matched syntax through the pattern function
78     * and to return the result for use in the renderer
79     * This result is always cached until the page is modified.
80     * @param string $match
81     * @param int $state
82     * @param int $pos
83     * @param Doku_Handler $handler
84     * @return array|bool
85     * @see DokuWiki_Syntax_Plugin::handle()
86     *
87     */
88    function handle($match, $state, $pos, Doku_Handler $handler)
89    {
90
91
92        $attributes = PluginUtility::getTagAttributes($match);
93        return array($attributes);
94
95
96    }
97
98    /**
99     * Render the output
100     * @param string $format
101     * @param Doku_Renderer $renderer
102     * @param array $data - what the function handle() return'ed
103     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
104     * @see DokuWiki_Syntax_Plugin::render()
105     *
106     */
107    function render($format, Doku_Renderer $renderer, $data): bool
108    {
109
110        switch ($format) {
111
112            case 'xhtml':
113
114                list($attributes) = $data;
115                /** @var Doku_Renderer_xhtml $renderer */
116
117                $page = MarkupPath::createFromRequestedPage();
118
119                /**
120                 * Disqus configuration
121                 * https://help.disqus.com/en/articles/1717084-javascript-configuration-variables
122                 */
123                $default = PluginUtility::getTagAttributes($this->getConf(self::CONF_DEFAULT_ATTRIBUTES));
124                $attributes = PluginUtility::mergeAttributes($attributes, $default);
125                $forumShortName = $attributes[self::ATTRIBUTE_SHORTNAME];
126                if (empty($forumShortName)) {
127                    LogUtility::msg("The disqus forum shortName should not be empty", LogUtility::LVL_MSG_ERROR, self::TAG);
128                    return false;
129                }
130                $forumShortName = hsc($forumShortName);
131
132                /**
133                 * @deprecated the page id is used
134                 */
135                $disqusIdentifier = MetadataDokuWikiStore::getOrCreateFromResource($page)
136                    ->getFromName(DisqusIdentifier::PROPERTY_NAME);
137                if (empty($disqusIdentifier)) {
138
139                    $disqusIdentifier = $attributes[self::ATTRIBUTE_IDENTIFIER];
140                    if (empty($disqusIdentifier)) {
141                        try {
142                            $disqusIdentifier = $page->getPageId();
143                        } catch (ExceptionNotExists $e) {
144                            // the page does not exists
145                            return false;
146                        }
147                    }
148
149                }
150                $disqusConfig = "this.page.identifier = \"$disqusIdentifier\";";
151
152                $url = $attributes[self::ATTRIBUTE_URL];
153                if (empty($url)) {
154                    $url = $page->getCanonicalUrl();
155                }
156                $disqusConfig .= "this.page.url = $url;";
157
158
159                $title = $attributes[self::ATTRIBUTE_TITLE];
160                if (empty($title)) {
161                    $title = action_plugin_combo_metatitle::getHtmlTitle();
162                    if (!empty($title)) {
163                        $disqusConfig .= "this.page.title = $title;";
164                    }
165                }
166
167                $category = $attributes[self::ATTRIBUTE_CATEGORY];
168                if (empty($category)) {
169                    $disqusConfig .= "this.page.category_id = $category;";
170                }
171
172
173                /**
174                 * The javascript
175                 */
176                $renderer->doc .= <<<EOD
177<script charset="utf-8" type="text/javascript">
178
179    // Configuration
180
181    // The disqus_config should be a var to give it the global scope
182    // Otherwise, disqus will see no config
183    // noinspection ES6ConvertVarToLetConst
184    var disqus_config = function () {
185        $disqusConfig
186    };
187
188    // Embed the library
189    (function() {
190        const d = document, s = d.createElement('script');
191        s.src = 'https://$forumShortName.disqus.com/embed.js';
192        s.setAttribute('data-timestamp', (+new Date()).toString());
193        (d.head || d.body).appendChild(s);
194    })();
195
196</script>
197<noscript><a href="https://disqus.com/home/discussion/$forumShortName/$disqusIdentifier/">View the discussion thread.</a></noscript>
198EOD;
199                // The tag
200                $renderer->doc .= '<div id="disqus_thread"></div>';
201
202                return true;
203
204            case 'metadata':
205
206        }
207        return false;
208
209    }
210
211
212}
213
214