104fd306cSNickeau<?php 204fd306cSNickeau 304fd306cSNickeaunamespace ComboStrap; 404fd306cSNickeau 504fd306cSNickeauuse ComboStrap\TagAttribute\Align; 604fd306cSNickeau 704fd306cSNickeau/** 804fd306cSNickeau * Represents a conditional length / value 904fd306cSNickeau */ 1004fd306cSNickeauclass ConditionalLength 1104fd306cSNickeau{ 1204fd306cSNickeau 1304fd306cSNickeau 1404fd306cSNickeau const PERCENTAGE = "%"; 1504fd306cSNickeau 1604fd306cSNickeau /** 17*30e068fcSgerardnico * 'fit-content' value, ignore the max-width property 18*30e068fcSgerardnico * (max-content does not) 19*30e068fcSgerardnico */ 20*30e068fcSgerardnico const FIT_CONTENT = "fit-content"; 21*30e068fcSgerardnico 22*30e068fcSgerardnico /** 2304fd306cSNickeau * @var string - the length value (may be breakpoint conditional) 2404fd306cSNickeau */ 2504fd306cSNickeau private $conditionalLength; 2604fd306cSNickeau 2704fd306cSNickeau /** 2804fd306cSNickeau * @var string - the length value without breakpoint 2904fd306cSNickeau */ 3004fd306cSNickeau private $length; 3104fd306cSNickeau /** 3204fd306cSNickeau * @var string 3304fd306cSNickeau */ 3404fd306cSNickeau private $unitInLength; 3504fd306cSNickeau /** 3604fd306cSNickeau * The number in a length string 3704fd306cSNickeau * @var float 3804fd306cSNickeau */ 3904fd306cSNickeau private $numerator; 4004fd306cSNickeau /** 4104fd306cSNickeau * @var string 4204fd306cSNickeau */ 4304fd306cSNickeau private $breakpoint; 4404fd306cSNickeau private $defaultBreakpoint = "sm"; 4504fd306cSNickeau private $denominator; 4604fd306cSNickeau /** 4704fd306cSNickeau * @var string 4804fd306cSNickeau */ 4904fd306cSNickeau private $axis; 5004fd306cSNickeau /** 5104fd306cSNickeau * @var bool 5204fd306cSNickeau */ 5304fd306cSNickeau private $isRatio = false; 5404fd306cSNickeau 5504fd306cSNickeau 5604fd306cSNickeau /** 5704fd306cSNickeau * @throws ExceptionBadArgument 5804fd306cSNickeau */ 5904fd306cSNickeau public function __construct($value, $defaultBreakpoint) 6004fd306cSNickeau { 6104fd306cSNickeau $this->conditionalLength = $value; 6204fd306cSNickeau if ($defaultBreakpoint !== null) { 6304fd306cSNickeau $this->defaultBreakpoint = $defaultBreakpoint; 6404fd306cSNickeau } 6504fd306cSNickeau 6604fd306cSNickeau /** 6704fd306cSNickeau * Breakpoint Suffix 6804fd306cSNickeau */ 6904fd306cSNickeau $this->length = $value; 7004fd306cSNickeau try { 7104fd306cSNickeau $conditionalValue = ConditionalValue::createFrom($value); 7204fd306cSNickeau $this->length = $conditionalValue->getValue(); 7304fd306cSNickeau $this->breakpoint = $conditionalValue->getBreakpoint(); 7404fd306cSNickeau } catch (ExceptionBadSyntax $e) { 7504fd306cSNickeau // not conditional 7604fd306cSNickeau } 7704fd306cSNickeau 7804fd306cSNickeau /** 7904fd306cSNickeau * Axis prefix 8004fd306cSNickeau */ 8104fd306cSNickeau $axis = substr($value, 0, 2); 8204fd306cSNickeau switch ($axis) { 8304fd306cSNickeau case "x-": 8404fd306cSNickeau $this->axis = "x"; 8504fd306cSNickeau break; 8604fd306cSNickeau case "y-"; 8704fd306cSNickeau $this->axis = "y"; 8804fd306cSNickeau break; 8904fd306cSNickeau } 9004fd306cSNickeau 9104fd306cSNickeau try { 9204fd306cSNickeau $this->parseAsNumberWithOptionalUnit(); 9304fd306cSNickeau } catch (ExceptionBadSyntax $e) { 9404fd306cSNickeau try { 9504fd306cSNickeau $this->parseAsRatio(); 9604fd306cSNickeau } catch (ExceptionBadSyntax $e) { 9704fd306cSNickeau // string only 9804fd306cSNickeau } 9904fd306cSNickeau } 10004fd306cSNickeau 10104fd306cSNickeau 10204fd306cSNickeau } 10304fd306cSNickeau 10404fd306cSNickeau /** 10504fd306cSNickeau * @throws ExceptionBadArgument 10604fd306cSNickeau */ 10704fd306cSNickeau public static function createFromString(string $widthLength, string $defaultBreakpoint = null): ConditionalLength 10804fd306cSNickeau { 10904fd306cSNickeau return new ConditionalLength($widthLength, $defaultBreakpoint); 11004fd306cSNickeau } 11104fd306cSNickeau 11204fd306cSNickeau public function getLengthUnit(): ?string 11304fd306cSNickeau { 11404fd306cSNickeau return $this->unitInLength; 11504fd306cSNickeau } 11604fd306cSNickeau 11704fd306cSNickeau /** 11804fd306cSNickeau * @throws ExceptionBadArgument 11904fd306cSNickeau */ 12004fd306cSNickeau public function toPixelNumber(): int 12104fd306cSNickeau { 12204fd306cSNickeau 12304fd306cSNickeau switch ($this->unitInLength) { 12404fd306cSNickeau case "rem": 12504fd306cSNickeau $remValue = ExecutionContext::getActualOrCreateFromEnv()->getConfig()->getRemFontSizeOrDefault(); 12604fd306cSNickeau $targetValue = $this->numerator * $remValue; 12704fd306cSNickeau break; 12804fd306cSNickeau case "px": 12904fd306cSNickeau default: 13004fd306cSNickeau $targetValue = $this->numerator; 13104fd306cSNickeau } 13204fd306cSNickeau return DataType::toInteger($targetValue); 13304fd306cSNickeau 13404fd306cSNickeau } 13504fd306cSNickeau 13604fd306cSNickeau public function getNumerator(): ?float 13704fd306cSNickeau { 13804fd306cSNickeau return $this->numerator; 13904fd306cSNickeau } 14004fd306cSNickeau 14104fd306cSNickeau /** 14204fd306cSNickeau * @throws ExceptionBadArgument 14304fd306cSNickeau */ 14404fd306cSNickeau public function toColClass(): string 14504fd306cSNickeau { 14604fd306cSNickeau 14704fd306cSNickeau $ratio = $this->getRatio(); 14804fd306cSNickeau if ($ratio > 1) { 14904fd306cSNickeau throw new ExceptionBadArgument("The length ratio ($ratio) is greater than 1. It should be less than 1 to get a col class."); 15004fd306cSNickeau } 15104fd306cSNickeau $colsNumber = floor(GridTag::GRID_TOTAL_COLUMNS * $this->numerator / $this->denominator); 15204fd306cSNickeau $breakpoint = $this->getBreakpointOrDefault(); 15304fd306cSNickeau if ($breakpoint === "xs") { 15404fd306cSNickeau return "col-$colsNumber"; 15504fd306cSNickeau } 15604fd306cSNickeau return "col-{$breakpoint}-$colsNumber"; 15704fd306cSNickeau 15804fd306cSNickeau 15904fd306cSNickeau } 16004fd306cSNickeau 16104fd306cSNickeau /** 16204fd306cSNickeau * @throws ExceptionBadArgument 16304fd306cSNickeau */ 16404fd306cSNickeau public function toRowColsClass(): string 16504fd306cSNickeau { 16604fd306cSNickeau 16704fd306cSNickeau if ($this->numerator === null) { 16804fd306cSNickeau if ($this->getLength() === "auto") { 16904fd306cSNickeau if (Bootstrap::getBootStrapMajorVersion() != Bootstrap::BootStrapFiveMajorVersion) { 17004fd306cSNickeau // row-cols-auto is not in 4.0 17104fd306cSNickeau PluginUtility::getSnippetManager()->attachCssInternalStyleSheet("row-cols-auto"); 17204fd306cSNickeau } 17304fd306cSNickeau return "row-cols-auto"; 17404fd306cSNickeau } 17504fd306cSNickeau throw new ExceptionBadArgument("A row col class can be calculated only from a number ({$this}) or from the `auto` value"); 17604fd306cSNickeau } 17704fd306cSNickeau 17804fd306cSNickeau $colsNumber = intval($this->numerator); 17904fd306cSNickeau $totalColumns = GridTag::GRID_TOTAL_COLUMNS; 18004fd306cSNickeau if ($colsNumber > $totalColumns) { 18104fd306cSNickeau throw new ExceptionBadArgument("A row col class can be calculated only from a number below $totalColumns ({$this}"); 18204fd306cSNickeau } 18304fd306cSNickeau $breakpoint = $this->getBreakpointOrDefault(); 18404fd306cSNickeau if ($breakpoint === "xs") { 18504fd306cSNickeau return "row-cols-$colsNumber"; 18604fd306cSNickeau } 18704fd306cSNickeau return "row-cols-{$breakpoint}-$colsNumber"; 18804fd306cSNickeau } 18904fd306cSNickeau 19004fd306cSNickeau public 19104fd306cSNickeau function getBreakpoint(): ?string 19204fd306cSNickeau { 19304fd306cSNickeau return $this->breakpoint; 19404fd306cSNickeau } 19504fd306cSNickeau 19604fd306cSNickeau 19704fd306cSNickeau public 19804fd306cSNickeau function getLength() 19904fd306cSNickeau { 20004fd306cSNickeau return $this->length; 20104fd306cSNickeau } 20204fd306cSNickeau 20304fd306cSNickeau public 20404fd306cSNickeau function __toString() 20504fd306cSNickeau { 20604fd306cSNickeau return $this->conditionalLength; 20704fd306cSNickeau } 20804fd306cSNickeau 20904fd306cSNickeau /** 21004fd306cSNickeau * For CSS a unit is mandatory (not for HTML or SVG attributes) 21104fd306cSNickeau * @throws ExceptionBadArgument 21204fd306cSNickeau */ 21304fd306cSNickeau public 21404fd306cSNickeau function toCssLength() 21504fd306cSNickeau { 21604fd306cSNickeau switch ($this->unitInLength){ 21704fd306cSNickeau case "vh": 21804fd306cSNickeau case "wh": 21904fd306cSNickeau case "rem": 22004fd306cSNickeau return $this->length; 22104fd306cSNickeau } 22204fd306cSNickeau /** 22304fd306cSNickeau * A length value may be also `fit-content` 22404fd306cSNickeau * we just check that if there is a number, 22504fd306cSNickeau * we add the pixel 22604fd306cSNickeau */ 22704fd306cSNickeau if ($this->numerator !== null) { 22804fd306cSNickeau return $this->toPixelNumber() . "px"; 22904fd306cSNickeau } else { 23004fd306cSNickeau if ($this->length === "fit") { 231*30e068fcSgerardnico return self::FIT_CONTENT; 23204fd306cSNickeau } 23304fd306cSNickeau return $this->length; 23404fd306cSNickeau } 23504fd306cSNickeau } 23604fd306cSNickeau 23704fd306cSNickeau public 23804fd306cSNickeau function getBreakpointOrDefault(): string 23904fd306cSNickeau { 24004fd306cSNickeau if ($this->breakpoint !== null) { 24104fd306cSNickeau return $this->breakpoint; 24204fd306cSNickeau } 24304fd306cSNickeau return $this->defaultBreakpoint; 24404fd306cSNickeau } 24504fd306cSNickeau 24604fd306cSNickeau 24704fd306cSNickeau public 24804fd306cSNickeau function getDenominator(): ?float 24904fd306cSNickeau { 25004fd306cSNickeau return $this->denominator; 25104fd306cSNickeau } 25204fd306cSNickeau 25304fd306cSNickeau /** 25404fd306cSNickeau * @throws ExceptionBadSyntax 25504fd306cSNickeau */ 25604fd306cSNickeau private 25704fd306cSNickeau function parseAsNumberWithOptionalUnit() 25804fd306cSNickeau { 25904fd306cSNickeau /** 26004fd306cSNickeau * Not a numeric alone 26104fd306cSNickeau * Does the length value has an unit ? 26204fd306cSNickeau */ 26304fd306cSNickeau preg_match("/^([0-9.]+)([^0-9]*)$/i", $this->length, $matches, PREG_OFFSET_CAPTURE); 26404fd306cSNickeau if (sizeof($matches) === 0) { 26504fd306cSNickeau throw new ExceptionBadSyntax("Length is not a number with optional unit"); 26604fd306cSNickeau } 26704fd306cSNickeau $localNumber = $matches[1][0]; 26804fd306cSNickeau try { 26904fd306cSNickeau $this->numerator = DataType::toFloat($localNumber); 27004fd306cSNickeau } catch (ExceptionBadArgument $e) { 27104fd306cSNickeau // should not happen due to the match but yeah 27204fd306cSNickeau throw new ExceptionBadSyntax("The number value ($localNumber) of the length value ($this->length) is not a valid float format."); 27304fd306cSNickeau } 27404fd306cSNickeau $this->denominator = 1; 27504fd306cSNickeau 27604fd306cSNickeau $secondMatch = $matches[2][0]; 27704fd306cSNickeau if ($secondMatch == "") { 27804fd306cSNickeau return; 27904fd306cSNickeau } 28004fd306cSNickeau $this->unitInLength = $secondMatch; 28104fd306cSNickeau if ($this->unitInLength === self::PERCENTAGE) { 28204fd306cSNickeau $this->denominator = 100; 28304fd306cSNickeau } 28404fd306cSNickeau 28504fd306cSNickeau } 28604fd306cSNickeau 28704fd306cSNickeau /** 28804fd306cSNickeau * @throws ExceptionBadSyntax 28904fd306cSNickeau */ 29004fd306cSNickeau private 29104fd306cSNickeau function parseAsRatio() 29204fd306cSNickeau { 29304fd306cSNickeau preg_match("/^([0-9]+):([0-9]+)$/i", $this->length, $matches, PREG_OFFSET_CAPTURE); 29404fd306cSNickeau if (sizeof($matches) === 0) { 29504fd306cSNickeau throw new ExceptionBadSyntax("Length is not a ratio"); 29604fd306cSNickeau } 29704fd306cSNickeau $numerator = $matches[1][0]; 29804fd306cSNickeau try { 29904fd306cSNickeau $this->numerator = DataType::toFloat($numerator); 30004fd306cSNickeau } catch (ExceptionBadArgument $e) { 30104fd306cSNickeau // should not happen due to the match but yeah 30204fd306cSNickeau throw new ExceptionBadSyntax("The number value ($numerator) of the length value ($this->length) is not a valid float format."); 30304fd306cSNickeau } 30404fd306cSNickeau $denominator = $matches[2][0]; 30504fd306cSNickeau try { 30604fd306cSNickeau $this->denominator = DataType::toFloat($denominator); 30704fd306cSNickeau } catch (ExceptionBadArgument $e) { 30804fd306cSNickeau // should not happen due to the match but yeah 30904fd306cSNickeau throw new ExceptionBadSyntax("The number value ($denominator) of the length value ($this->length) is not a valid float format."); 31004fd306cSNickeau } 31104fd306cSNickeau $this->isRatio = true; 31204fd306cSNickeau } 31304fd306cSNickeau 31404fd306cSNickeau /** 31504fd306cSNickeau * @throws ExceptionBadArgument 31604fd306cSNickeau */ 31704fd306cSNickeau public 31804fd306cSNickeau function getRatio() 31904fd306cSNickeau { 32004fd306cSNickeau if (!$this->isRatio()) { 32104fd306cSNickeau return null; 32204fd306cSNickeau } 32304fd306cSNickeau if ($this->numerator == null) { 32404fd306cSNickeau return null; 32504fd306cSNickeau } 32604fd306cSNickeau if ($this->denominator == null) { 32704fd306cSNickeau return null; 32804fd306cSNickeau } 32904fd306cSNickeau if ($this->denominator == 0) { 33004fd306cSNickeau throw new ExceptionBadArgument("The denominator of the conditional length ($this) is 0. You can't ask a ratio."); 33104fd306cSNickeau } 33204fd306cSNickeau return $this->numerator / $this->denominator; 33304fd306cSNickeau } 33404fd306cSNickeau 33504fd306cSNickeau public function getAxis(): string 33604fd306cSNickeau { 33704fd306cSNickeau return $this->axis; 33804fd306cSNickeau } 33904fd306cSNickeau 34004fd306cSNickeau public function getAxisOrDefault(): string 34104fd306cSNickeau { 34204fd306cSNickeau if ($this->axis !== null) { 34304fd306cSNickeau return $this->axis; 34404fd306cSNickeau } 34504fd306cSNickeau return Align::DEFAULT_AXIS; 34604fd306cSNickeau } 34704fd306cSNickeau 34804fd306cSNickeau public function isRatio(): bool 34904fd306cSNickeau { 35004fd306cSNickeau if ($this->getLengthUnit() === self::PERCENTAGE) { 35104fd306cSNickeau return true; 35204fd306cSNickeau } 35304fd306cSNickeau return $this->isRatio; 35404fd306cSNickeau } 35504fd306cSNickeau 35604fd306cSNickeau /** 35704fd306cSNickeau * @return string - the breakpoint value that should be added into a bootstrap class 35804fd306cSNickeau * 35904fd306cSNickeau * For instance, for ''xs'', you would get ''-xs'' 36004fd306cSNickeau * If there is no breakpoint, the empty string is returned 36104fd306cSNickeau */ 36204fd306cSNickeau public function getBreakpointForBootstrapClass(): string 36304fd306cSNickeau { 36404fd306cSNickeau 36504fd306cSNickeau if ($this->breakpoint !== null) { 36604fd306cSNickeau if($this->breakpoint==="xs"){ 36704fd306cSNickeau return ""; 36804fd306cSNickeau } 36904fd306cSNickeau return "-{$this->breakpoint}"; 37004fd306cSNickeau } else { 37104fd306cSNickeau return ""; 37204fd306cSNickeau } 37304fd306cSNickeau } 37404fd306cSNickeau 37504fd306cSNickeau 37604fd306cSNickeau} 377