1<?php 2 3 4namespace ComboStrap; 5 6 7use dokuwiki\Extension\SyntaxPlugin; 8use syntax_plugin_combo_button; 9use syntax_plugin_combo_link; 10use syntax_plugin_combo_pageimage; 11 12class Dimension 13{ 14 /** 15 * The element that have an width and height 16 */ 17 const NATURAL_SIZING_ELEMENT = [SvgImageLink::CANONICAL, RasterImageLink::CANONICAL]; 18 19 const DESIGN_LAYOUT_CONSTRAINED = "constrained"; // fix value 20 const DESIGN_LAYOUT_FLUID = "fluid"; // adapt 21 22 /** 23 * On the width, if set, the design is fluid and will adapt to all screen 24 * with a min-width 25 */ 26 const WIDTH_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_FLUID; 27 /** 28 * On height, if set, the design is constrained and overflow 29 */ 30 const HEIGHT_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_CONSTRAINED; 31 const SCROLL = "scroll"; 32 33 /** 34 * Logical height and width 35 * used by default to define the width and height of an image or a css box 36 */ 37 const HEIGHT_KEY = 'height'; 38 const WIDTH_KEY = 'width'; 39 40 /** 41 * The ratio (16:9, ...) permits to change: 42 * * the viewBox in svg 43 * * the intrinsic dimension in raster 44 * 45 * It's then part of the request 46 * because in svg it is the definition of the viewBox 47 * 48 * The rendering function takes care of it 49 * and it's also passed in the fetch url 50 */ 51 public const RATIO_ATTRIBUTE = "ratio"; 52 53 54 /** 55 * @param TagAttributes $attributes 56 */ 57 public static function processWidthAndHeight(&$attributes) 58 { 59 $widthName = self::WIDTH_KEY; 60 if ($attributes->hasComponentAttribute($widthName)) { 61 62 $widthValue = trim($attributes->getValueAndRemove($widthName)); 63 64 if ($widthValue == "0") { 65 66 /** 67 * For an image, the dimension are restricted by height 68 */ 69 if ($attributes->hasComponentAttribute(self::HEIGHT_KEY)) { 70 $attributes->addStyleDeclarationIfNotSet("width", "auto"); 71 } 72 73 } else { 74 75 76 if ($widthValue == "fit") { 77 $widthValue = "fit-content"; 78 } else { 79 /** Numeric value */ 80 $widthValue = TagAttributes::toQualifiedCssValue($widthValue); 81 } 82 83 84 /** 85 * For an image (png, svg) 86 * They have width and height **element** attribute 87 */ 88 if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) { 89 90 /** 91 * If the image is not ask as static resource (ie HTTP request) 92 * but added in HTML 93 * (ie {@link \action_plugin_combo_svg}) 94 */ 95 $requestedMime = $attributes->getMime(); 96 if ($requestedMime == TagAttributes::TEXT_HTML_MIME) { 97 $attributes->addStyleDeclarationIfNotSet('max-width', $widthValue); 98 $attributes->addStyleDeclarationIfNotSet('width', "100%"); 99 } 100 101 } else { 102 103 /** 104 * For a block 105 */ 106 $attributes->addStyleDeclarationIfNotSet('max-width', $widthValue); 107 108 } 109 } 110 111 } 112 113 $heightName = self::HEIGHT_KEY; 114 if ($attributes->hasComponentAttribute($heightName)) { 115 $heightValue = trim($attributes->getValueAndRemove($heightName)); 116 if ($heightValue !== "") { 117 $heightValue = TagAttributes::toQualifiedCssValue($heightValue); 118 119 if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) { 120 121 /** 122 * A element with a natural height is responsive, we set only the max-height 123 * 124 * By default, the image has a `height: auto` due to the img-fluid class 125 * Making its height responsive 126 */ 127 $attributes->addStyleDeclarationIfNotSet("max-height", $heightValue); 128 129 } else { 130 131 /** 132 * HTML Block 133 * 134 * Without the height value, a block display will collapse 135 */ 136 if (self::HEIGHT_LAYOUT_DEFAULT == self::DESIGN_LAYOUT_CONSTRAINED) { 137 138 /** 139 * The box is constrained in height 140 * By default, a box is not constrained 141 */ 142 $attributes->addStyleDeclarationIfNotSet("height", $heightValue); 143 144 $scrollMechanism = $attributes->getValueAndRemoveIfPresent("scroll"); 145 if ($scrollMechanism != null) { 146 $scrollMechanism = trim(strtolower($scrollMechanism)); 147 } 148 switch ($scrollMechanism) { 149 case "toggle": 150 // https://jsfiddle.net/gerardnico/h0g6xw58/ 151 $attributes->addStyleDeclarationIfNotSet("overflow-y", "hidden"); 152 $attributes->addStyleDeclarationIfNotSet("position", "relative"); 153 $attributes->addStyleDeclarationIfNotSet("display", "block"); 154 // The block should collapse to this height 155 $attributes->addStyleDeclarationIfNotSet("min-height", $heightValue); 156 if ($attributes->hasComponentAttribute("id")) { 157 $id = $attributes->getValue("id"); 158 } else { 159 $id = $attributes->generateAndSetId(); 160 } 161 /** 162 * Css of the button and other standard attribute 163 */ 164 PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle"); 165 /** 166 * Set the color dynamically to the color of the parent 167 */ 168 PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("height-toggle"); 169 /** 170 * The height when there is not the show class 171 * is the original height 172 */ 173 $css = <<<EOF 174#$id:not(.show){ 175 height: $heightValue; 176 transition: height .35s ease; 177} 178EOF; 179 PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle-show", $css); 180 $bootstrapDataNameSpace = Bootstrap::getDataNamespace(); 181 $button = <<<EOF 182<button class="height-toggle-combo" data$bootstrapDataNameSpace-toggle="collapse" data$bootstrapDataNameSpace-target="#$id" aria-expanded="false"></button> 183EOF; 184 185 $attributes->addHtmlAfterEnterTag($button); 186 187 break; 188 case "lift"; 189 default: 190 $attributes->addStyleDeclarationIfNotSet("overflow", "auto"); 191 break; 192 193 } 194 195 196 } else { 197 198 /** 199 * if fluid 200 * min-height and not height to not constraint the box 201 */ 202 $attributes->addStyleDeclarationIfNotSet("min-height", $heightValue); 203 204 } 205 } 206 } 207 208 } 209 } 210 211 /** 212 * 213 * Toggle with a click on the collapsed element 214 * if there is no control element such as button or link inside 215 * 216 * This function is used at the {@link DOKU_LEXER_EXIT} state of a {@link SyntaxPlugin::handle()} 217 * 218 * @param CallStack $callStack 219 */ 220 public static function addScrollToggleOnClickIfNoControl(CallStack $callStack) 221 { 222 $callStack->moveToEnd(); 223 $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall(); 224 $scrollAttribute = $openingCall->getAttribute(Dimension::SCROLL); 225 if ($scrollAttribute != null && $scrollAttribute == "toggle") { 226 227 $controlFound = false; 228 while ($actualCall = $callStack->next()) { 229 if (in_array($actualCall->getTagName(), 230 [syntax_plugin_combo_button::TAG, syntax_plugin_combo_link::TAG, "internallink", "externallink"])) { 231 $controlFound = true; 232 break; 233 } 234 } 235 if (!$controlFound) { 236 $toggleOnClickId = "height-toggle-onclick"; 237 PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar($toggleOnClickId); 238 $openingCall->addClassName("{$toggleOnClickId}-combo"); 239 $openingCall->addCssStyle("cursor", "pointer"); 240 } 241 242 } 243 } 244 245 /** 246 * @param $value - a css value to a pixel 247 * @throws ExceptionCombo 248 */ 249 public static function toPixelValue($value): int 250 { 251 $targetValue = str_replace("px", "", $value); 252 return DataType::toInteger($targetValue); 253 } 254 255 /** 256 * Convert 16:9, ... to a float 257 * @param string $stringRatio 258 * @return float 259 * @throws ExceptionCombo 260 */ 261 public static function convertTextualRatioToNumber(string $stringRatio): float 262 { 263 list($width, $height) = explode(":", $stringRatio, 2); 264 try { 265 $width = DataType::toInteger($width); 266 } catch (ExceptionCombo $e) { 267 throw new ExceptionCombo("The width value ($width) of the ratio `$stringRatio` is not numeric", syntax_plugin_combo_pageimage::CANONICAL); 268 } 269 try { 270 $height = DataType::toInteger($height); 271 } catch (ExceptionCombo $e) { 272 throw new ExceptionCombo("The width value ($height) of the ratio `$stringRatio` is not numeric", syntax_plugin_combo_pageimage::CANONICAL); 273 } 274 if ($height == 0) { 275 throw new ExceptionCombo("The height value of the ratio `$stringRatio` should not be zero", syntax_plugin_combo_pageimage::CANONICAL); 276 } 277 return floatval($width / $height); 278 279 } 280 281 282} 283