xref: /plugin/combo/syntax/toggle.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeau
4*04fd306cSNickeauuse ComboStrap\Bootstrap;
5*04fd306cSNickeauuse ComboStrap\BrandButton;
6*04fd306cSNickeauuse ComboStrap\ButtonTag;
7*04fd306cSNickeauuse ComboStrap\CallStack;
8*04fd306cSNickeauuse ComboStrap\LogUtility;
9*04fd306cSNickeauuse ComboStrap\PluginUtility;
10*04fd306cSNickeauuse ComboStrap\TagAttributes;
11*04fd306cSNickeauuse ComboStrap\TagAttribute\Toggle;
12*04fd306cSNickeauuse ComboStrap\XmlTagProcessing;
13*04fd306cSNickeau
14*04fd306cSNickeau
15*04fd306cSNickeauclass syntax_plugin_combo_toggle extends DokuWiki_Syntax_Plugin
16*04fd306cSNickeau{
17*04fd306cSNickeau
18*04fd306cSNickeau    const TAG = "toggle";
19*04fd306cSNickeau    const CANONICAL = self::TAG;
20*04fd306cSNickeau    const WIDGET_ATTRIBUTE = "widget";
21*04fd306cSNickeau
22*04fd306cSNickeau
23*04fd306cSNickeau    /**
24*04fd306cSNickeau     * Syntax Type.
25*04fd306cSNickeau     *
26*04fd306cSNickeau     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
27*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::getType()
28*04fd306cSNickeau     */
29*04fd306cSNickeau    function getType(): string
30*04fd306cSNickeau    {
31*04fd306cSNickeau        return 'substition';
32*04fd306cSNickeau    }
33*04fd306cSNickeau
34*04fd306cSNickeau    /**
35*04fd306cSNickeau     * How Dokuwiki will add P element
36*04fd306cSNickeau     *
37*04fd306cSNickeau     *  * 'normal' - The plugin can be used inside paragraphs
38*04fd306cSNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
39*04fd306cSNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
40*04fd306cSNickeau     *
41*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
42*04fd306cSNickeau     */
43*04fd306cSNickeau    function getPType(): string
44*04fd306cSNickeau    {
45*04fd306cSNickeau        // button or link
46*04fd306cSNickeau        return 'normal';
47*04fd306cSNickeau    }
48*04fd306cSNickeau
49*04fd306cSNickeau    /**
50*04fd306cSNickeau     * @return array
51*04fd306cSNickeau     * Allow which kind of plugin inside
52*04fd306cSNickeau     *
53*04fd306cSNickeau     * array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
54*04fd306cSNickeau     *
55*04fd306cSNickeau     */
56*04fd306cSNickeau    function getAllowedTypes(): array
57*04fd306cSNickeau    {
58*04fd306cSNickeau        return array('baseonly', 'formatting', 'substition', 'protected', 'disabled');
59*04fd306cSNickeau    }
60*04fd306cSNickeau
61*04fd306cSNickeau    function getSort(): int
62*04fd306cSNickeau    {
63*04fd306cSNickeau        return 201;
64*04fd306cSNickeau    }
65*04fd306cSNickeau
66*04fd306cSNickeau    public
67*04fd306cSNickeau    function accepts($mode): bool
68*04fd306cSNickeau    {
69*04fd306cSNickeau        return syntax_plugin_combo_preformatted::disablePreformatted($mode)
70*04fd306cSNickeau            && Toggle::disableEntity($mode);
71*04fd306cSNickeau    }
72*04fd306cSNickeau
73*04fd306cSNickeau
74*04fd306cSNickeau    /**
75*04fd306cSNickeau     * Create a pattern that will called this plugin
76*04fd306cSNickeau     *
77*04fd306cSNickeau     * @param string $mode
78*04fd306cSNickeau     * @see Doku_Parser_Mode::connectTo()
79*04fd306cSNickeau     */
80*04fd306cSNickeau    function connectTo($mode)
81*04fd306cSNickeau    {
82*04fd306cSNickeau
83*04fd306cSNickeau        $pattern = XmlTagProcessing::getContainerTagPattern(self::getTag());
84*04fd306cSNickeau        $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
85*04fd306cSNickeau
86*04fd306cSNickeau
87*04fd306cSNickeau    }
88*04fd306cSNickeau
89*04fd306cSNickeau    function postConnect()
90*04fd306cSNickeau    {
91*04fd306cSNickeau
92*04fd306cSNickeau        $this->Lexer->addExitPattern('</' . self::getTag() . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
93*04fd306cSNickeau
94*04fd306cSNickeau    }
95*04fd306cSNickeau
96*04fd306cSNickeau    function handle($match, $state, $pos, Doku_Handler $handler)
97*04fd306cSNickeau    {
98*04fd306cSNickeau
99*04fd306cSNickeau
100*04fd306cSNickeau        switch ($state) {
101*04fd306cSNickeau
102*04fd306cSNickeau            case DOKU_LEXER_ENTER :
103*04fd306cSNickeau
104*04fd306cSNickeau                /**
105*04fd306cSNickeau                 * Default parameters, type definition and parsing
106*04fd306cSNickeau                 */
107*04fd306cSNickeau                $defaultParameters[self::WIDGET_ATTRIBUTE] = BrandButton::WIDGET_BUTTON_VALUE;
108*04fd306cSNickeau                $knownTypes = ButtonTag::TYPES;
109*04fd306cSNickeau                $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultParameters, $knownTypes)
110*04fd306cSNickeau                    ->setLogicalTag(self::TAG);
111*04fd306cSNickeau
112*04fd306cSNickeau                return array(
113*04fd306cSNickeau                    PluginUtility::STATE => $state,
114*04fd306cSNickeau                    PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray()
115*04fd306cSNickeau                );
116*04fd306cSNickeau
117*04fd306cSNickeau            case DOKU_LEXER_UNMATCHED :
118*04fd306cSNickeau                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
119*04fd306cSNickeau
120*04fd306cSNickeau            case DOKU_LEXER_EXIT :
121*04fd306cSNickeau
122*04fd306cSNickeau                return array(
123*04fd306cSNickeau                    PluginUtility::STATE => $state
124*04fd306cSNickeau                );
125*04fd306cSNickeau
126*04fd306cSNickeau
127*04fd306cSNickeau        }
128*04fd306cSNickeau        return array();
129*04fd306cSNickeau
130*04fd306cSNickeau    }
131*04fd306cSNickeau
132*04fd306cSNickeau    /**
133*04fd306cSNickeau     * Render the output
134*04fd306cSNickeau     * @param string $format
135*04fd306cSNickeau     * @param Doku_Renderer $renderer
136*04fd306cSNickeau     * @param array $data - what the function handle() return
137*04fd306cSNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
138*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::render()
139*04fd306cSNickeau     *
140*04fd306cSNickeau     *
141*04fd306cSNickeau     */
142*04fd306cSNickeau    function render($format, Doku_Renderer $renderer, $data): bool
143*04fd306cSNickeau    {
144*04fd306cSNickeau
145*04fd306cSNickeau        if ($format === "xhtml") {
146*04fd306cSNickeau            $state = $data[PluginUtility::STATE];
147*04fd306cSNickeau            switch ($state) {
148*04fd306cSNickeau                case DOKU_LEXER_ENTER:
149*04fd306cSNickeau
150*04fd306cSNickeau                    $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES])
151*04fd306cSNickeau                        ->setLogicalTag(self::CANONICAL);
152*04fd306cSNickeau
153*04fd306cSNickeau                    $targetId = $tagAttributes->getValueAndRemoveIfPresent("target-id");
154*04fd306cSNickeau                    if ($targetId === null) {
155*04fd306cSNickeau                        $renderer->doc .= LogUtility::wrapInRedForHtml("The target id is mandatory");
156*04fd306cSNickeau                        return false;
157*04fd306cSNickeau                    }
158*04fd306cSNickeau                    /**
159*04fd306cSNickeau                     * Snippet
160*04fd306cSNickeau                     */
161*04fd306cSNickeau                    PluginUtility::getSnippetManager()->attachCssInternalStyleSheet(self::CANONICAL);
162*04fd306cSNickeau
163*04fd306cSNickeau                    $bootstrapNamespace = "bs-";
164*04fd306cSNickeau                    if (Bootstrap::getBootStrapMajorVersion() == Bootstrap::BootStrapFourMajorVersion) {
165*04fd306cSNickeau                        $bootstrapNamespace = "";
166*04fd306cSNickeau                    }
167*04fd306cSNickeau                    /**
168*04fd306cSNickeau                     * Types
169*04fd306cSNickeau                     */
170*04fd306cSNickeau                    $type = $tagAttributes->getType();
171*04fd306cSNickeau                    if ($type !== null) {
172*04fd306cSNickeau                        $tagAttributes->addClassName("btn-$type");
173*04fd306cSNickeau                    }
174*04fd306cSNickeau                    /**
175*04fd306cSNickeau                     * Should be in link form for bootstrap
176*04fd306cSNickeau                     */
177*04fd306cSNickeau                    if (substr($targetId, 0, 1) != "#") {
178*04fd306cSNickeau                        $targetId = "#" . $targetId;
179*04fd306cSNickeau                    }
180*04fd306cSNickeau                    $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}toggle", "collapse");
181*04fd306cSNickeau                    $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}target", $targetId);
182*04fd306cSNickeau
183*04fd306cSNickeau                    /**
184*04fd306cSNickeau                     * Aria
185*04fd306cSNickeau                     */
186*04fd306cSNickeau                    $toggleState = $tagAttributes->getValueAndRemove(Toggle::TOGGLE_STATE, Toggle::TOGGLE_STATE_COLLAPSED);
187*04fd306cSNickeau                    switch ($toggleState) {
188*04fd306cSNickeau                        case Toggle::TOGGLE_STATE_EXPANDED:
189*04fd306cSNickeau                            $tagAttributes->addComponentAttributeValue("aria-expanded", true);
190*04fd306cSNickeau                            break;
191*04fd306cSNickeau                        case Toggle::TOGGLE_STATE_COLLAPSED:
192*04fd306cSNickeau                            $tagAttributes->addComponentAttributeValue("aria-expanded", false);
193*04fd306cSNickeau                            $tagAttributes->addClassName("collapsed");
194*04fd306cSNickeau                            break;
195*04fd306cSNickeau                    }
196*04fd306cSNickeau
197*04fd306cSNickeau
198*04fd306cSNickeau                    $targetLabel = $tagAttributes->getValueAndRemoveIfPresent("targetLabel");
199*04fd306cSNickeau                    if ($targetLabel === null) {
200*04fd306cSNickeau                        $targetLabel = "Toggle $targetId";
201*04fd306cSNickeau                    }
202*04fd306cSNickeau                    $tagAttributes->addComponentAttributeValue("aria-label", $targetLabel);
203*04fd306cSNickeau                    $tagAttributes->addClassName("btn");
204*04fd306cSNickeau                    $renderer->doc .= $tagAttributes->toHtmlEnterTag("button");
205*04fd306cSNickeau                    break;
206*04fd306cSNickeau                case DOKU_LEXER_UNMATCHED:
207*04fd306cSNickeau                    $renderer->doc .= PluginUtility::renderUnmatched($data);
208*04fd306cSNickeau                    break;
209*04fd306cSNickeau                case DOKU_LEXER_EXIT:
210*04fd306cSNickeau                    $renderer->doc .= "</button>";
211*04fd306cSNickeau                    break;
212*04fd306cSNickeau
213*04fd306cSNickeau            }
214*04fd306cSNickeau            return true;
215*04fd306cSNickeau        }
216*04fd306cSNickeau
217*04fd306cSNickeau        // unsupported $mode
218*04fd306cSNickeau        return false;
219*04fd306cSNickeau    }
220*04fd306cSNickeau
221*04fd306cSNickeau    public
222*04fd306cSNickeau    static function getTag(): string
223*04fd306cSNickeau    {
224*04fd306cSNickeau        return self::TAG;
225*04fd306cSNickeau    }
226*04fd306cSNickeau
227*04fd306cSNickeau
228*04fd306cSNickeau}
229*04fd306cSNickeau
230