1<?php
2
3require_once(__DIR__ . "/../ComboStrap/PluginUtility.php");
4
5use ComboStrap\BrandButton;
6use ComboStrap\CacheManager;
7use ComboStrap\CacheDependencies;
8use ComboStrap\Call;
9use ComboStrap\CallStack;
10use ComboStrap\ExceptionCombo;
11use ComboStrap\Icon;
12use ComboStrap\LogUtility;
13use ComboStrap\Page;
14use ComboStrap\CacheRuntimeDependencies2;
15use ComboStrap\PluginUtility;
16use ComboStrap\TagAttributes;
17
18
19/**
20 *
21 * See also:
22 * Mobile sharing: https://web.dev/web-share/
23 * https://twitter.com/addyosmani/status/1490055796704497665?s=21
24 */
25class syntax_plugin_combo_share extends DokuWiki_Syntax_Plugin
26{
27
28
29    const TAG = "share";
30    const CANONICAL = self::TAG;
31
32
33    function getType(): string
34    {
35        return 'substition';
36    }
37
38    /**
39     * How Dokuwiki will add P element
40     *
41     *  * 'normal' - The plugin can be used inside paragraphs (inline)
42     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
43     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
44     *
45     * @see DokuWiki_Syntax_Plugin::getPType()
46     */
47    function getPType(): string
48    {
49        return 'normal';
50    }
51
52    /**
53     * @return array
54     * Allow which kind of plugin inside
55     *
56     * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
57     * because we manage self the content and we call self the parser
58     */
59    function getAllowedTypes(): array
60    {
61        return array('substition', 'formatting', 'disabled');
62    }
63
64    function getSort(): int
65    {
66        return 201;
67    }
68
69
70    function connectTo($mode)
71    {
72
73        /**
74         * The empty tag pattern should be before the container pattern
75         */
76        $this->Lexer->addSpecialPattern(PluginUtility::getEmptyTagPattern(self::TAG), $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
77
78        /**
79         * Container
80         */
81        $entryPattern = PluginUtility::getContainerTagPattern(self::TAG);
82        $this->Lexer->addEntryPattern($entryPattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
83
84
85    }
86
87    public function postConnect()
88    {
89
90        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
91
92    }
93
94    function handle($match, $state, $pos, Doku_Handler $handler): array
95    {
96
97        $returnArray = array(
98            PluginUtility::STATE => $state,
99        );
100        switch ($state) {
101
102            case DOKU_LEXER_ENTER:
103            case DOKU_LEXER_SPECIAL:
104
105                $defaultAttributes = [];
106                $types = null;
107                $shareAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, $types)
108                    ->setLogicalTag(self::TAG);
109
110
111                /**
112                 * Return the data to add the snippet style in rendering
113                 */
114                $returnArray[PluginUtility::ATTRIBUTES] = $shareAttributes->toCallStackArray();
115                return $returnArray;
116
117
118            case DOKU_LEXER_EXIT:
119
120                return $returnArray;
121
122            case DOKU_LEXER_UNMATCHED:
123
124                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
125
126
127        }
128        return $returnArray;
129
130    }
131
132    /**
133     * Render the output
134     * @param string $format
135     * @param Doku_Renderer $renderer
136     * @param array $data - what the function handle() return'ed
137     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
138     * @see DokuWiki_Syntax_Plugin::render()
139     *
140     *
141     */
142    function render($format, Doku_Renderer $renderer, $data): bool
143    {
144        if ($format === "xhtml") {
145            $state = $data[PluginUtility::STATE];
146            switch ($state) {
147                case DOKU_LEXER_SPECIAL:
148                case DOKU_LEXER_ENTER:
149
150                    $shareAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]);
151
152                    /**
153                     * The channel
154                     */
155                    try {
156                        $brandButton = syntax_plugin_combo_brand::createButtonFromAttributes($shareAttributes, BrandButton::TYPE_BUTTON_SHARE);
157                    } catch (ExceptionCombo $e) {
158                        $renderer->doc .= LogUtility::wrapInRedForHtml("The brand creation returns an error ({$e->getMessage()}");
159                        return false;
160                    }
161
162
163                    /**
164                     * Standard link attribute
165                     * and Runtime Cache key dependencies
166                     */
167                    CacheManager::getOrCreate()->addDependencyForCurrentSlot(CacheDependencies::REQUESTED_PAGE_DEPENDENCY);
168                    try {
169                        $requestedPage = Page::createPageFromRequestedPage();
170                    } catch (ExceptionCombo $e) {
171                        $renderer->doc .= LogUtility::wrapInRedForHtml("The requested page could not be determined. Error: ({$e->getMessage()}");
172                        return false;
173                    }
174                    try {
175                        $linkAttributes = $brandButton->getLinkAttributes($requestedPage)
176                            ->setType($shareAttributes->getType())
177                            ->setLogicalTag(self::TAG);
178                    } catch (ExceptionCombo $e) {
179                        $renderer->doc .= LogUtility::wrapInRedForHtml("The social channel creation returns an error when creating the link ({$e->getMessage()}");
180                        return false;
181                    }
182
183                    /**
184                     * Add the link
185                     */
186                    $renderer->doc .= $linkAttributes->toHtmlEnterTag("a");
187
188                    /**
189                     * Icon
190                     */
191                    if ($brandButton->hasIcon()) {
192                        try {
193                            $iconAttributes = $brandButton->getIconAttributes();
194                            $name = $iconAttributes[\syntax_plugin_combo_icon::ICON_NAME_ATTRIBUTE];
195                            unset($iconAttributes[\syntax_plugin_combo_icon::ICON_NAME_ATTRIBUTE]);
196                            $iconAttributes = TagAttributes::createFromCallStackArray($iconAttributes);
197                            $renderer->doc .= Icon::create($name, $iconAttributes)
198                                ->render();
199                        } catch (ExceptionCombo $e) {
200                            $renderer->doc .= LogUtility::wrapInRedForHtml("Getting the icon for the social channel ($brandButton) returns an error ({$e->getMessage()}");
201                            // don't return because the anchor link is open
202                        }
203                    }
204
205
206                    if ($state === DOKU_LEXER_SPECIAL) {
207                        $renderer->doc .= "</a>";
208                    }
209
210
211                    try {
212                        $style = $brandButton->getStyle();
213                    } catch (ExceptionCombo $e) {
214                        $renderer->doc .= LogUtility::wrapInRedForHtml("The style of the share button ($brandButton) could not be determined. Error: {$e->getMessage()}");
215                        return false;
216                    }
217                    $snippetId = $brandButton->getStyleScriptIdentifier();
218                    PluginUtility::getSnippetManager()->attachCssInternalStyleSheetForSlot($snippetId, $style);
219                    break;
220                case DOKU_LEXER_EXIT:
221                    $renderer->doc .= "</a>";
222                    break;
223                case DOKU_LEXER_UNMATCHED:
224                    $renderer->doc .= PluginUtility::renderUnmatched($data);
225                    break;
226                default:
227
228            }
229            return true;
230        }
231
232        // unsupported $mode
233        return false;
234    }
235
236
237    private function closeLinkInCallStack(CallStack $callStack)
238    {
239        $callStack->appendCallAtTheEnd(
240            Call::createComboCall(
241                syntax_plugin_combo_link::TAG,
242                DOKU_LEXER_EXIT
243            ));
244    }
245
246
247}
248
249