137748cd8SNickeau<?php 237748cd8SNickeau 337748cd8SNickeau 437748cd8SNickeaunamespace ComboStrap; 537748cd8SNickeau 637748cd8SNickeau 737748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin; 837748cd8SNickeauuse syntax_plugin_combo_button; 937748cd8SNickeauuse syntax_plugin_combo_link; 10*82a60d03SNickeauuse syntax_plugin_combo_pageimage; 1137748cd8SNickeau 1237748cd8SNickeauclass Dimension 1337748cd8SNickeau{ 1437748cd8SNickeau /** 1537748cd8SNickeau * The element that have an width and height 1637748cd8SNickeau */ 1737748cd8SNickeau const NATURAL_SIZING_ELEMENT = [SvgImageLink::CANONICAL, RasterImageLink::CANONICAL]; 1837748cd8SNickeau 1937748cd8SNickeau const DESIGN_LAYOUT_CONSTRAINED = "constrained"; // fix value 2037748cd8SNickeau const DESIGN_LAYOUT_FLUID = "fluid"; // adapt 2137748cd8SNickeau 2237748cd8SNickeau /** 2337748cd8SNickeau * On the width, if set, the design is fluid and will adapt to all screen 2437748cd8SNickeau * with a min-width 2537748cd8SNickeau */ 2637748cd8SNickeau const WIDTH_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_FLUID; 2737748cd8SNickeau /** 2837748cd8SNickeau * On height, if set, the design is constrained and overflow 2937748cd8SNickeau */ 3037748cd8SNickeau const HEIGHT_LAYOUT_DEFAULT = self::DESIGN_LAYOUT_CONSTRAINED; 3137748cd8SNickeau const SCROLL = "scroll"; 32*82a60d03SNickeau 33*82a60d03SNickeau /** 34*82a60d03SNickeau * Logical height and width 35*82a60d03SNickeau * used by default to define the width and height of an image or a css box 36*82a60d03SNickeau */ 3737748cd8SNickeau const HEIGHT_KEY = 'height'; 3837748cd8SNickeau const WIDTH_KEY = 'width'; 3937748cd8SNickeau 40*82a60d03SNickeau /** 41*82a60d03SNickeau * The ratio (16:9, ...) permits to change: 42*82a60d03SNickeau * * the viewBox in svg 43*82a60d03SNickeau * * the intrinsic dimension in raster 44*82a60d03SNickeau * 45*82a60d03SNickeau * It's then part of the request 46*82a60d03SNickeau * because in svg it is the definition of the viewBox 47*82a60d03SNickeau * 48*82a60d03SNickeau * The rendering function takes care of it 49*82a60d03SNickeau * and it's also passed in the fetch url 50*82a60d03SNickeau */ 51*82a60d03SNickeau public const RATIO_ATTRIBUTE = "ratio"; 52*82a60d03SNickeau 5337748cd8SNickeau 5437748cd8SNickeau /** 5537748cd8SNickeau * @param TagAttributes $attributes 5637748cd8SNickeau */ 5737748cd8SNickeau public static function processWidthAndHeight(&$attributes) 5837748cd8SNickeau { 5937748cd8SNickeau $widthName = self::WIDTH_KEY; 6037748cd8SNickeau if ($attributes->hasComponentAttribute($widthName)) { 6137748cd8SNickeau 6237748cd8SNickeau $widthValue = trim($attributes->getValueAndRemove($widthName)); 6337748cd8SNickeau 6437748cd8SNickeau if ($widthValue == "0") { 6537748cd8SNickeau 6637748cd8SNickeau /** 6737748cd8SNickeau * For an image, the dimension are restricted by height 6837748cd8SNickeau */ 6937748cd8SNickeau if ($attributes->hasComponentAttribute(self::HEIGHT_KEY)) { 70*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("width", "auto"); 7137748cd8SNickeau } 7237748cd8SNickeau 7337748cd8SNickeau } else { 7437748cd8SNickeau 7537748cd8SNickeau 7637748cd8SNickeau if ($widthValue == "fit") { 7737748cd8SNickeau $widthValue = "fit-content"; 7837748cd8SNickeau } else { 7937748cd8SNickeau /** Numeric value */ 8037748cd8SNickeau $widthValue = TagAttributes::toQualifiedCssValue($widthValue); 8137748cd8SNickeau } 8237748cd8SNickeau 8337748cd8SNickeau 8437748cd8SNickeau /** 85*82a60d03SNickeau * For an image (png, svg) 86*82a60d03SNickeau * They have width and height **element** attribute 8737748cd8SNickeau */ 8837748cd8SNickeau if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) { 8937748cd8SNickeau 9037748cd8SNickeau /** 9137748cd8SNickeau * If the image is not ask as static resource (ie HTTP request) 9237748cd8SNickeau * but added in HTML 9337748cd8SNickeau * (ie {@link \action_plugin_combo_svg}) 9437748cd8SNickeau */ 9537748cd8SNickeau $requestedMime = $attributes->getMime(); 9637748cd8SNickeau if ($requestedMime == TagAttributes::TEXT_HTML_MIME) { 97*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet('max-width', $widthValue); 98*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet('width', "100%"); 9937748cd8SNickeau } 10037748cd8SNickeau 10137748cd8SNickeau } else { 10237748cd8SNickeau 10337748cd8SNickeau /** 10437748cd8SNickeau * For a block 10537748cd8SNickeau */ 106*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet('max-width', $widthValue); 10737748cd8SNickeau 10837748cd8SNickeau } 10937748cd8SNickeau } 11037748cd8SNickeau 11137748cd8SNickeau } 11237748cd8SNickeau 11337748cd8SNickeau $heightName = self::HEIGHT_KEY; 11437748cd8SNickeau if ($attributes->hasComponentAttribute($heightName)) { 11537748cd8SNickeau $heightValue = trim($attributes->getValueAndRemove($heightName)); 11637748cd8SNickeau if ($heightValue !== "") { 11737748cd8SNickeau $heightValue = TagAttributes::toQualifiedCssValue($heightValue); 11837748cd8SNickeau 11937748cd8SNickeau if (in_array($attributes->getLogicalTag(), self::NATURAL_SIZING_ELEMENT)) { 12037748cd8SNickeau 12137748cd8SNickeau /** 12237748cd8SNickeau * A element with a natural height is responsive, we set only the max-height 12337748cd8SNickeau * 12437748cd8SNickeau * By default, the image has a `height: auto` due to the img-fluid class 12537748cd8SNickeau * Making its height responsive 12637748cd8SNickeau */ 127*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("max-height", $heightValue); 12837748cd8SNickeau 12937748cd8SNickeau } else { 13037748cd8SNickeau 13137748cd8SNickeau /** 13237748cd8SNickeau * HTML Block 13337748cd8SNickeau * 13437748cd8SNickeau * Without the height value, a block display will collapse 13537748cd8SNickeau */ 13637748cd8SNickeau if (self::HEIGHT_LAYOUT_DEFAULT == self::DESIGN_LAYOUT_CONSTRAINED) { 13737748cd8SNickeau 13837748cd8SNickeau /** 13937748cd8SNickeau * The box is constrained in height 14037748cd8SNickeau * By default, a box is not constrained 14137748cd8SNickeau */ 142*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("height", $heightValue); 14337748cd8SNickeau 14437748cd8SNickeau $scrollMechanism = $attributes->getValueAndRemoveIfPresent("scroll"); 14537748cd8SNickeau if ($scrollMechanism != null) { 14637748cd8SNickeau $scrollMechanism = trim(strtolower($scrollMechanism)); 14737748cd8SNickeau } 14837748cd8SNickeau switch ($scrollMechanism) { 14937748cd8SNickeau case "toggle": 15037748cd8SNickeau // https://jsfiddle.net/gerardnico/h0g6xw58/ 151*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("overflow-y", "hidden"); 152*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("position", "relative"); 153*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("display", "block"); 15437748cd8SNickeau // The block should collapse to this height 155*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("min-height", $heightValue); 15637748cd8SNickeau if ($attributes->hasComponentAttribute("id")) { 15737748cd8SNickeau $id = $attributes->getValue("id"); 15837748cd8SNickeau } else { 15937748cd8SNickeau $id = $attributes->generateAndSetId(); 16037748cd8SNickeau } 16137748cd8SNickeau /** 16237748cd8SNickeau * Css of the button and other standard attribute 16337748cd8SNickeau */ 16437748cd8SNickeau PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle"); 16537748cd8SNickeau /** 16637748cd8SNickeau * Set the color dynamically to the color of the parent 16737748cd8SNickeau */ 16837748cd8SNickeau PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("height-toggle"); 16937748cd8SNickeau /** 17037748cd8SNickeau * The height when there is not the show class 17137748cd8SNickeau * is the original height 17237748cd8SNickeau */ 17337748cd8SNickeau $css = <<<EOF 17437748cd8SNickeau#$id:not(.show){ 17537748cd8SNickeau height: $heightValue; 17637748cd8SNickeau transition: height .35s ease; 17737748cd8SNickeau} 17837748cd8SNickeauEOF; 17937748cd8SNickeau PluginUtility::getSnippetManager()->attachCssSnippetForBar("height-toggle-show", $css); 18037748cd8SNickeau $bootstrapDataNameSpace = Bootstrap::getDataNamespace(); 18137748cd8SNickeau $button = <<<EOF 18237748cd8SNickeau<button class="height-toggle-combo" data$bootstrapDataNameSpace-toggle="collapse" data$bootstrapDataNameSpace-target="#$id" aria-expanded="false"></button> 18337748cd8SNickeauEOF; 18437748cd8SNickeau 18537748cd8SNickeau $attributes->addHtmlAfterEnterTag($button); 18637748cd8SNickeau 18737748cd8SNickeau break; 18837748cd8SNickeau case "lift"; 18937748cd8SNickeau default: 190*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("overflow", "auto"); 19137748cd8SNickeau break; 19237748cd8SNickeau 19337748cd8SNickeau } 19437748cd8SNickeau 19537748cd8SNickeau 19637748cd8SNickeau } else { 19737748cd8SNickeau 19837748cd8SNickeau /** 19937748cd8SNickeau * if fluid 20037748cd8SNickeau * min-height and not height to not constraint the box 20137748cd8SNickeau */ 202*82a60d03SNickeau $attributes->addStyleDeclarationIfNotSet("min-height", $heightValue); 20337748cd8SNickeau 20437748cd8SNickeau } 20537748cd8SNickeau } 20637748cd8SNickeau } 20737748cd8SNickeau 20837748cd8SNickeau } 20937748cd8SNickeau } 21037748cd8SNickeau 21137748cd8SNickeau /** 21237748cd8SNickeau * 213*82a60d03SNickeau * Toggle with a click on the collapsed element 21437748cd8SNickeau * if there is no control element such as button or link inside 21537748cd8SNickeau * 21637748cd8SNickeau * This function is used at the {@link DOKU_LEXER_EXIT} state of a {@link SyntaxPlugin::handle()} 21737748cd8SNickeau * 21837748cd8SNickeau * @param CallStack $callStack 21937748cd8SNickeau */ 22037748cd8SNickeau public static function addScrollToggleOnClickIfNoControl(CallStack $callStack) 22137748cd8SNickeau { 22237748cd8SNickeau $callStack->moveToEnd(); 22337748cd8SNickeau $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall(); 22437748cd8SNickeau $scrollAttribute = $openingCall->getAttribute(Dimension::SCROLL); 22537748cd8SNickeau if ($scrollAttribute != null && $scrollAttribute == "toggle") { 22637748cd8SNickeau 22737748cd8SNickeau $controlFound = false; 22837748cd8SNickeau while ($actualCall = $callStack->next()) { 22937748cd8SNickeau if (in_array($actualCall->getTagName(), 23037748cd8SNickeau [syntax_plugin_combo_button::TAG, syntax_plugin_combo_link::TAG, "internallink", "externallink"])) { 23137748cd8SNickeau $controlFound = true; 23237748cd8SNickeau break; 23337748cd8SNickeau } 23437748cd8SNickeau } 23537748cd8SNickeau if (!$controlFound) { 23637748cd8SNickeau $toggleOnClickId = "height-toggle-onclick"; 23737748cd8SNickeau PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar($toggleOnClickId); 23837748cd8SNickeau $openingCall->addClassName("{$toggleOnClickId}-combo"); 23937748cd8SNickeau $openingCall->addCssStyle("cursor", "pointer"); 24037748cd8SNickeau } 24137748cd8SNickeau 24237748cd8SNickeau } 24337748cd8SNickeau } 244*82a60d03SNickeau 245*82a60d03SNickeau /** 246*82a60d03SNickeau * @param $value - a css value to a pixel 247*82a60d03SNickeau * @throws ExceptionCombo 248*82a60d03SNickeau */ 249*82a60d03SNickeau public static function toPixelValue($value): int 250*82a60d03SNickeau { 251*82a60d03SNickeau $targetValue = str_replace("px", "", $value); 252*82a60d03SNickeau return DataType::toInteger($targetValue); 253*82a60d03SNickeau } 254*82a60d03SNickeau 255*82a60d03SNickeau /** 256*82a60d03SNickeau * Convert 16:9, ... to a float 257*82a60d03SNickeau * @param string $stringRatio 258*82a60d03SNickeau * @return float 259*82a60d03SNickeau * @throws ExceptionCombo 260*82a60d03SNickeau */ 261*82a60d03SNickeau public static function convertTextualRatioToNumber(string $stringRatio): float 262*82a60d03SNickeau { 263*82a60d03SNickeau list($width, $height) = explode(":", $stringRatio, 2); 264*82a60d03SNickeau try { 265*82a60d03SNickeau $width = DataType::toInteger($width); 266*82a60d03SNickeau } catch (ExceptionCombo $e) { 267*82a60d03SNickeau throw new ExceptionCombo("The width value ($width) of the ratio `$stringRatio` is not numeric", syntax_plugin_combo_pageimage::CANONICAL); 268*82a60d03SNickeau } 269*82a60d03SNickeau try { 270*82a60d03SNickeau $height = DataType::toInteger($height); 271*82a60d03SNickeau } catch (ExceptionCombo $e) { 272*82a60d03SNickeau throw new ExceptionCombo("The width value ($height) of the ratio `$stringRatio` is not numeric", syntax_plugin_combo_pageimage::CANONICAL); 273*82a60d03SNickeau } 274*82a60d03SNickeau if ($height == 0) { 275*82a60d03SNickeau throw new ExceptionCombo("The height value of the ratio `$stringRatio` should not be zero", syntax_plugin_combo_pageimage::CANONICAL); 276*82a60d03SNickeau } 277*82a60d03SNickeau return floatval($width / $height); 278*82a60d03SNickeau 279*82a60d03SNickeau } 280*82a60d03SNickeau 281*82a60d03SNickeau 28237748cd8SNickeau} 283