xref: /plugin/combo/ComboStrap/Dimension.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1<?php
2
3
4namespace ComboStrap;
5
6
7use dokuwiki\Extension\SyntaxPlugin;
8use syntax_plugin_combo_button;
9use syntax_plugin_combo_link;
10
11class Dimension
12{
13    /**
14     * The element that have an width and height
15     */
16    const NATURAL_SIZING_ELEMENT = [SvgImageLink::CANONICAL, RasterImageLink::CANONICAL];
17
18    const DESIGN_LAYOUT_CONSTRAINED = "constrained"; // fix value
19    const DESIGN_LAYOUT_FLUID = "fluid"; // adapt
20
21    /**
22     * On the width, if set, the design is fluid and will adapt to all screen
23     * with a min-width
24     */
25    const WIDTH_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_FLUID;
26    /**
27     * On height, if set, the design is constrained and overflow
28     */
29    const HEIGHT_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_CONSTRAINED;
30    const SCROLL = "scroll";
31    const HEIGHT_KEY = 'height';
32    const WIDTH_KEY = 'width';
33
34
35    /**
36     * @param TagAttributes $attributes
37     */
38    public static function processWidthAndHeight(&$attributes)
39    {
40        $widthName = self::WIDTH_KEY;
41        if ($attributes->hasComponentAttribute($widthName)) {
42
43            $widthValue = trim($attributes->getValueAndRemove($widthName));
44
45            if ($widthValue == "0") {
46
47                /**
48                 * For an image, the dimension are restricted by height
49                 */
50                if ($attributes->hasComponentAttribute(self::HEIGHT_KEY)) {
51                    $attributes->addStyleDeclaration("width", "auto");
52                }
53
54            } else {
55
56
57                if ($widthValue == "fit") {
58                    $widthValue = "fit-content";
59                } else {
60                    /** Numeric value */
61                    $widthValue = TagAttributes::toQualifiedCssValue($widthValue);
62                }
63
64
65                /**
66                 * For an image
67                 */
68                if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) {
69
70                    /**
71                     * If the image is not ask as static resource (ie HTTP request)
72                     * but added in HTML
73                     * (ie {@link \action_plugin_combo_svg})
74                     */
75                    $requestedMime = $attributes->getMime();
76                    if ($requestedMime == TagAttributes::TEXT_HTML_MIME) {
77                        $attributes->addStyleDeclaration('max-width', $widthValue);
78                        $attributes->addStyleDeclaration('width', "100%");
79                    }
80
81                } else {
82
83                    /**
84                     * For a block
85                     */
86                    $attributes->addStyleDeclaration('max-width', $widthValue);
87
88                }
89            }
90
91        }
92
93        $heightName = self::HEIGHT_KEY;
94        if ($attributes->hasComponentAttribute($heightName)) {
95            $heightValue = trim($attributes->getValueAndRemove($heightName));
96            if ($heightValue !== "") {
97                $heightValue = TagAttributes::toQualifiedCssValue($heightValue);
98
99                if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) {
100
101                    /**
102                     * A element with a natural height is responsive, we set only the max-height
103                     *
104                     * By default, the image has a `height: auto` due to the img-fluid class
105                     * Making its height responsive
106                     */
107                    $attributes->addStyleDeclaration("max-height", $heightValue);
108
109                } else {
110
111                    /**
112                     * HTML Block
113                     *
114                     * Without the height value, a block display will collapse
115                     */
116                    if (self::HEIGHT_LAYOUT_DEFAULT == self::DESIGN_LAYOUT_CONSTRAINED) {
117
118                        /**
119                         * The box is constrained in height
120                         * By default, a box is not constrained
121                         */
122                        $attributes->addStyleDeclaration("height", $heightValue);
123
124                        $scrollMechanism = $attributes->getValueAndRemoveIfPresent("scroll");
125                        if ($scrollMechanism != null) {
126                            $scrollMechanism = trim(strtolower($scrollMechanism));
127                        }
128                        switch ($scrollMechanism) {
129                            case "toggle":
130                                // https://jsfiddle.net/gerardnico/h0g6xw58/
131                                $attributes->addStyleDeclaration("overflow-y", "hidden");
132                                $attributes->addStyleDeclaration("position", "relative");
133                                $attributes->addStyleDeclaration("display", "block");
134                                // The block should collapse to this height
135                                $attributes->addStyleDeclaration("min-height", $heightValue);
136                                if ($attributes->hasComponentAttribute("id")) {
137                                    $id = $attributes->getValue("id");
138                                } else {
139                                    $id = $attributes->generateAndSetId();
140                                }
141                                /**
142                                 * Css of the button and other standard attribute
143                                 */
144                                PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle");
145                                /**
146                                 * Set the color dynamically to the color of the parent
147                                 */
148                                PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("height-toggle");
149                                /**
150                                 * The height when there is not the show class
151                                 * is the original height
152                                 */
153                                $css = <<<EOF
154#$id:not(.show){
155  height: $heightValue;
156  transition: height .35s ease;
157}
158EOF;
159                                PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle-show", $css);
160                                $bootstrapDataNameSpace = Bootstrap::getDataNamespace();
161                                $button = <<<EOF
162<button class="height-toggle-combo" data$bootstrapDataNameSpace-toggle="collapse" data$bootstrapDataNameSpace-target="#$id" aria-expanded="false"></button>
163EOF;
164
165                                $attributes->addHtmlAfterEnterTag($button);
166
167                                break;
168                            case "lift";
169                            default:
170                                $attributes->addStyleDeclaration("overflow", "auto");
171                                break;
172
173                        }
174
175
176                    } else {
177
178                        /**
179                         * if fluid
180                         * min-height and not height to not constraint the box
181                         */
182                        $attributes->addStyleDeclaration("min-height", $heightValue);
183
184                    }
185                }
186            }
187
188        }
189    }
190
191    /**
192     *
193     * Toggle with a click on the collpased element
194     * if there is no control element such as button or link inside
195     *
196     * This function is used at the {@link DOKU_LEXER_EXIT} state of a {@link SyntaxPlugin::handle()}
197     *
198     * @param CallStack $callStack
199     */
200    public static function addScrollToggleOnClickIfNoControl(CallStack $callStack)
201    {
202        $callStack->moveToEnd();
203        $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall();
204        $scrollAttribute = $openingCall->getAttribute(Dimension::SCROLL);
205        if ($scrollAttribute != null && $scrollAttribute == "toggle") {
206
207            $controlFound = false;
208            while ($actualCall = $callStack->next()) {
209                if (in_array($actualCall->getTagName(),
210                    [syntax_plugin_combo_button::TAG, syntax_plugin_combo_link::TAG, "internallink", "externallink"])) {
211                    $controlFound = true;
212                    break;
213                }
214            }
215            if (!$controlFound) {
216                $toggleOnClickId = "height-toggle-onclick";
217                PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar($toggleOnClickId);
218                $openingCall->addClassName("{$toggleOnClickId}-combo");
219                $openingCall->addCssStyle("cursor", "pointer");
220            }
221
222        }
223    }
224}
225