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