See Release Notes
Long Term Support Release
<?php namespace Sabberworm\CSS;< use Sabberworm\CSS\Parsing\OutputException; </** * Class OutputFormat *< * @method OutputFormat setSemicolonAfterLastRule( bool $bSemicolonAfterLastRule ) Set whether semicolons are added after last rule.> * @method OutputFormat setSemicolonAfterLastRule(bool $bSemicolonAfterLastRule) Set whether semicolons are added after > * last rule.*/< class OutputFormat {> class OutputFormat > {/**< * Value format> * Value format: `"` means double-quote, `'` means single-quote > * > * @var string*/< // " means double-quote, ' means single-quotepublic $sStringQuotingType = '"';< // Output RGB colors in hash notation if possible> > /** > * Output RGB colors in hash notation if possible > * > * @var string > */public $bRGBHashNotation = true; /** * Declaration format> * */ > * Semicolon after the last rule of a declaration block can be omitted. To do that, set this false. // Semicolon after the last rule of a declaration block can be omitted. To do that, set this false. > * public $bSemicolonAfterLastRule = true; > * @var bool< // Semicolon after the last rule of a declaration block can be omitted. To do that, set this false./** * Spacing * Note that these strings are not sanity-checked: the value should only consist of whitespace * Any newline character will be indented according to the current level. * The triples (After, Before, Between) can be set using a wildcard (e.g. `$oFormat->set('Space*Rules', "\n");`) */ public $sSpaceAfterRuleName = ' ';> /** public $sSpaceBeforeRules = ''; > * @var string public $sSpaceAfterRules = ''; > */public $sSpaceBetweenRules = '';> > /** public $sSpaceBeforeBlocks = ''; > * @var string public $sSpaceAfterBlocks = ''; > */public $sSpaceBetweenBlocks = "\n";> > /** // Content injected in and around @-rule blocks. > * @var string public $sBeforeAtRuleBlock = ''; > */public $sAfterAtRuleBlock = '';> /** > * @var string // This is what’s printed before and after the comma if a declaration block contains multiple selectors. > */public $sSpaceBeforeSelectorSeparator = '';> public $sSpaceAfterSelectorSeparator = ' '; > /** // This is what’s printed after the comma of value lists > * @var string public $sSpaceBeforeListArgumentSeparator = ''; > */public $sSpaceAfterListArgumentSeparator = '';> > /** public $sSpaceBeforeOpeningBrace = ' '; > * @var string > */< // Content injected in and around @-rule blocks.> /** > * Content injected in and around at-rule blocks. > * > * @var string > */public $sBeforeDeclarationBlock = '';> public $sAfterDeclarationBlockSelectors = ''; > /** public $sAfterDeclarationBlock = ''; > * @var string > */< // This is what’s printed before and after the comma if a declaration block contains multiple selectors.> /** > * This is what’s printed before and after the comma if a declaration block contains multiple selectors. > * > * @var string > */* Indentation> */ > /** // Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings. > * @var string public $sIndentation = "\t"; > */< // This is what’s printed after the comma of value lists> > /** > * This is what’s printed after the comma of value lists > * > * @var string > *//**> * Output exceptions. > /** */ > * @var string public $bIgnoreExceptions = false; > */> /** > * @var string private $oFormatter = null; > */< // Content injected in and around declaration blocks.> /** > * Content injected in and around declaration blocks. > * > * @var string > */private $iIndentationLevel = 0;> > /** public function __construct() { > * @var string } > */> public function get($sName) { > /** $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i'); > * @var string foreach($aVarPrefixes as $sPrefix) { > */< * Indentation> * Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings. > * > * @var string< // Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings.return $this->$sFieldName;> * } > * @var bool<> /** > * @var OutputFormatter|null > */return null;> } > /** > * @var OutputFormat|null public function set($aNames, $mValue) { > */$aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');> if(is_string($aNames) && strpos($aNames, '*') !== false) { > /** $aNames = array(str_replace('*', 'Before', $aNames), str_replace('*', 'Between', $aNames), str_replace('*', 'After', $aNames)); > * @var int } else if(!is_array($aNames)) { > */< public function __construct() {> public function __construct() > {< public function get($sName) { < $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');> /** > * @param string $sName > * > * @return string|null > */ > public function get($sName) > { > $aVarPrefixes = ['a', 's', 'm', 'b', 'f', 'o', 'c', 'i'];< public function set($aNames, $mValue) { < $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');> /** > * @param array<array-key, string>|string $aNames > * @param mixed $mValue > * > * @return self|false > */ > public function set($aNames, $mValue) > { > $aVarPrefixes = ['a', 's', 'm', 'b', 'f', 'o', 'c', 'i'];< $aNames = array(str_replace('*', 'Before', $aNames), str_replace('*', 'Between', $aNames), str_replace('*', 'After', $aNames));> $aNames = > [ > str_replace('*', 'Before', $aNames), > str_replace('*', 'Between', $aNames), > str_replace('*', 'After', $aNames), > ];< $aNames = array($aNames);> $aNames = [$aNames];$this->$sFieldName = $mValue; $bDidReplace = true; } } if($bDidReplace) { return $this; } } // Break the chain so the user knows this option is invalid return false; }< public function __call($sMethodName, $aArguments) {> /** > * @param string $sMethodName > * @param array<array-key, mixed> $aArguments > * > * @return mixed > * > * @throws \Exception > */ > public function __call($sMethodName, array $aArguments) > {if(strpos($sMethodName, 'set') === 0) { return $this->set(substr($sMethodName, 3), $aArguments[0]); } else if(strpos($sMethodName, 'get') === 0) { return $this->get(substr($sMethodName, 3));< } else if(method_exists('\\Sabberworm\\CSS\\OutputFormatter', $sMethodName)) { < return call_user_func_array(array($this->getFormatter(), $sMethodName), $aArguments);> } elseif (method_exists(OutputFormatter::class, $sMethodName)) { > return call_user_func_array([$this->getFormatter(), $sMethodName], $aArguments);} else { throw new \Exception('Unknown OutputFormat method called: '.$sMethodName); } }< public function indentWithTabs($iNumber = 1) {> /** > * @param int $iNumber > * > * @return self > */ > public function indentWithTabs($iNumber = 1) > {return $this->setIndentation(str_repeat("\t", $iNumber)); }< public function indentWithSpaces($iNumber = 2) {> /** > * @param int $iNumber > * > * @return self > */ > public function indentWithSpaces($iNumber = 2) > {return $this->setIndentation(str_repeat(" ", $iNumber)); }< public function nextLevel() {> /** > * @return OutputFormat > */ > public function nextLevel() > {if($this->oNextLevelFormat === null) { $this->oNextLevelFormat = clone $this; $this->oNextLevelFormat->iIndentationLevel++; $this->oNextLevelFormat->oFormatter = null; } return $this->oNextLevelFormat; }< public function beLenient() {> /** > * @return void > */ > public function beLenient() > {$this->bIgnoreExceptions = true; }< public function getFormatter() {> /** > * @return OutputFormatter > */ > public function getFormatter() > {if($this->oFormatter === null) { $this->oFormatter = new OutputFormatter($this); } return $this->oFormatter; }< public function level() {> /** > * @return int > */ > public function level() > {return $this->iIndentationLevel; } /**< * Create format.> * Creates an instance of this class without any particular formatting settings.*< * @return OutputFormat Format.> * @return self*/< public static function create() {> public static function create() > {return new OutputFormat(); } /**< * Create compact format.> * Creates an instance of this class with a preset for compact formatting.*< * @return OutputFormat Format.> * @return self*/< public static function createCompact() {> public static function createCompact() > {$format = self::create();< $format->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');> $format->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('') > ->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');return $format; } /**< * Create pretty format.> * Creates an instance of this class with a preset for pretty formatting.*< * @return OutputFormat Format.> * @return self*/< public static function createPretty() {> public static function createPretty() > {$format = self::create();< $format->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', array('default' => '', ',' => ' '));> $format->set('Space*Rules', "\n")->set('Space*Blocks', "\n") > ->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', ['default' => '', ',' => ' ']);return $format; }< } < < class OutputFormatter { < private $oFormat; < < public function __construct(OutputFormat $oFormat) { < $this->oFormat = $oFormat; < } < < public function space($sName, $sType = null) { < $sSpaceString = $this->oFormat->get("Space$sName"); < // If $sSpaceString is an array, we have multple values configured depending on the type of object the space applies to < if(is_array($sSpaceString)) { < if($sType !== null && isset($sSpaceString[$sType])) { < $sSpaceString = $sSpaceString[$sType]; < } else { < $sSpaceString = reset($sSpaceString); < } < } < return $this->prepareSpace($sSpaceString); < } < < public function spaceAfterRuleName() { < return $this->space('AfterRuleName'); < } < < public function spaceBeforeRules() { < return $this->space('BeforeRules'); < } < < public function spaceAfterRules() { < return $this->space('AfterRules'); < } < < public function spaceBetweenRules() { < return $this->space('BetweenRules'); < } < < public function spaceBeforeBlocks() { < return $this->space('BeforeBlocks'); < } < < public function spaceAfterBlocks() { < return $this->space('AfterBlocks'); < } < < public function spaceBetweenBlocks() { < return $this->space('BetweenBlocks'); < } < < public function spaceBeforeSelectorSeparator() { < return $this->space('BeforeSelectorSeparator'); < } < < public function spaceAfterSelectorSeparator() { < return $this->space('AfterSelectorSeparator'); < } < < public function spaceBeforeListArgumentSeparator($sSeparator) { < return $this->space('BeforeListArgumentSeparator', $sSeparator); < } < < public function spaceAfterListArgumentSeparator($sSeparator) { < return $this->space('AfterListArgumentSeparator', $sSeparator); < } < < public function spaceBeforeOpeningBrace() { < return $this->space('BeforeOpeningBrace'); < } < < /** < * Runs the given code, either swallowing or passing exceptions, depending on the bIgnoreExceptions setting. < */ < public function safely($cCode) { < if($this->oFormat->get('IgnoreExceptions')) { < // If output exceptions are ignored, run the code with exception guards < try { < return $cCode(); < } catch (OutputException $e) { < return null; < } //Do nothing < } else { < // Run the code as-is < return $cCode(); < } < } < < /** < * Clone of the implode function but calls ->render with the current output format instead of __toString() < */ < public function implode($sSeparator, $aValues, $bIncreaseLevel = false) { < $sResult = ''; < $oFormat = $this->oFormat; < if($bIncreaseLevel) { < $oFormat = $oFormat->nextLevel(); < } < $bIsFirst = true; < foreach($aValues as $mValue) { < if($bIsFirst) { < $bIsFirst = false; < } else { < $sResult .= $sSeparator; < } < if($mValue instanceof \Sabberworm\CSS\Renderable) { < $sResult .= $mValue->render($oFormat); < } else { < $sResult .= $mValue; < } < } < return $sResult; < } < < public function removeLastSemicolon($sString) { < if($this->oFormat->get('SemicolonAfterLastRule')) { < return $sString; < } < $sString = explode(';', $sString); < if(count($sString) < 2) { < return $sString[0]; < } < $sLast = array_pop($sString); < $sNextToLast = array_pop($sString); < array_push($sString, $sNextToLast.$sLast); < return implode(';', $sString); < } < < private function prepareSpace($sSpaceString) { < return str_replace("\n", "\n".$this->indent(), $sSpaceString); < } < < private function indent() { < return str_repeat($this->oFormat->sIndentation, $this->oFormat->level()); < }}