composer package updates
[openemr.git] / vendor / sabberworm / php-css-parser / lib / Sabberworm / CSS / OutputFormat.php
blob1b1798402685ef5dd4af57e81c20e6fae7192a18
1 <?php
3 namespace Sabberworm\CSS;
5 use Sabberworm\CSS\Parsing\OutputException;
7 class OutputFormat {
8 /**
9 * Value format
11 // " means double-quote, ' means single-quote
12 public $sStringQuotingType = '"';
13 // Output RGB colors in hash notation if possible
14 public $bRGBHashNotation = true;
16 /**
17 * Declaration format
19 // Semicolon after the last rule of a declaration block can be omitted. To do that, set this false.
20 public $bSemicolonAfterLastRule = true;
22 /**
23 * Spacing
24 * Note that these strings are not sanity-checked: the value should only consist of whitespace
25 * Any newline character will be indented according to the current level.
26 * The triples (After, Before, Between) can be set using a wildcard (e.g. `$oFormat->set('Space*Rules', "\n");`)
28 public $sSpaceAfterRuleName = ' ';
30 public $sSpaceBeforeRules = '';
31 public $sSpaceAfterRules = '';
32 public $sSpaceBetweenRules = '';
34 public $sSpaceBeforeBlocks = '';
35 public $sSpaceAfterBlocks = '';
36 public $sSpaceBetweenBlocks = "\n";
38 // This is what’s printed before and after the comma if a declaration block contains multiple selectors.
39 public $sSpaceBeforeSelectorSeparator = '';
40 public $sSpaceAfterSelectorSeparator = ' ';
41 // This is what’s printed after the comma of value lists
42 public $sSpaceBeforeListArgumentSeparator = '';
43 public $sSpaceAfterListArgumentSeparator = '';
45 public $sSpaceBeforeOpeningBrace = ' ';
47 /**
48 * Indentation
50 // Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings.
51 public $sIndentation = "\t";
53 /**
54 * Output exceptions.
56 public $bIgnoreExceptions = false;
59 private $oFormatter = null;
60 private $oNextLevelFormat = null;
61 private $iIndentationLevel = 0;
63 public function __construct() {
66 public function get($sName) {
67 $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');
68 foreach($aVarPrefixes as $sPrefix) {
69 $sFieldName = $sPrefix.ucfirst($sName);
70 if(isset($this->$sFieldName)) {
71 return $this->$sFieldName;
74 return null;
77 public function set($aNames, $mValue) {
78 $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');
79 if(is_string($aNames) && strpos($aNames, '*') !== false) {
80 $aNames = array(str_replace('*', 'Before', $aNames), str_replace('*', 'Between', $aNames), str_replace('*', 'After', $aNames));
81 } else if(!is_array($aNames)) {
82 $aNames = array($aNames);
84 foreach($aVarPrefixes as $sPrefix) {
85 $bDidReplace = false;
86 foreach($aNames as $sName) {
87 $sFieldName = $sPrefix.ucfirst($sName);
88 if(isset($this->$sFieldName)) {
89 $this->$sFieldName = $mValue;
90 $bDidReplace = true;
93 if($bDidReplace) {
94 return $this;
97 // Break the chain so the user knows this option is invalid
98 return false;
101 public function __call($sMethodName, $aArguments) {
102 if(strpos($sMethodName, 'set') === 0) {
103 return $this->set(substr($sMethodName, 3), $aArguments[0]);
104 } else if(strpos($sMethodName, 'get') === 0) {
105 return $this->get(substr($sMethodName, 3));
106 } else if(method_exists('\\Sabberworm\\CSS\\OutputFormatter', $sMethodName)) {
107 return call_user_func_array(array($this->getFormatter(), $sMethodName), $aArguments);
108 } else {
109 throw new \Exception('Unknown OutputFormat method called: '.$sMethodName);
113 public function indentWithTabs($iNumber = 1) {
114 return $this->setIndentation(str_repeat("\t", $iNumber));
117 public function indentWithSpaces($iNumber = 2) {
118 return $this->setIndentation(str_repeat(" ", $iNumber));
121 public function nextLevel() {
122 if($this->oNextLevelFormat === null) {
123 $this->oNextLevelFormat = clone $this;
124 $this->oNextLevelFormat->iIndentationLevel++;
125 $this->oNextLevelFormat->oFormatter = null;
127 return $this->oNextLevelFormat;
130 public function beLenient() {
131 $this->bIgnoreExceptions = true;
134 public function getFormatter() {
135 if($this->oFormatter === null) {
136 $this->oFormatter = new OutputFormatter($this);
138 return $this->oFormatter;
141 public function level() {
142 return $this->iIndentationLevel;
145 public static function create() {
146 return new OutputFormat();
149 public static function createCompact() {
150 return self::create()->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');
153 public static function createPretty() {
154 return self::create()->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', array('default' => '', ',' => ' '));
158 class OutputFormatter {
159 private $oFormat;
161 public function __construct(OutputFormat $oFormat) {
162 $this->oFormat = $oFormat;
165 public function space($sName, $sType = null) {
166 $sSpaceString = $this->oFormat->get("Space$sName");
167 // If $sSpaceString is an array, we have multple values configured depending on the type of object the space applies to
168 if(is_array($sSpaceString)) {
169 if($sType !== null && isset($sSpaceString[$sType])) {
170 $sSpaceString = $sSpaceString[$sType];
171 } else {
172 $sSpaceString = reset($sSpaceString);
175 return $this->prepareSpace($sSpaceString);
178 public function spaceAfterRuleName() {
179 return $this->space('AfterRuleName');
182 public function spaceBeforeRules() {
183 return $this->space('BeforeRules');
186 public function spaceAfterRules() {
187 return $this->space('AfterRules');
190 public function spaceBetweenRules() {
191 return $this->space('BetweenRules');
194 public function spaceBeforeBlocks() {
195 return $this->space('BeforeBlocks');
198 public function spaceAfterBlocks() {
199 return $this->space('AfterBlocks');
202 public function spaceBetweenBlocks() {
203 return $this->space('BetweenBlocks');
206 public function spaceBeforeSelectorSeparator() {
207 return $this->space('BeforeSelectorSeparator');
210 public function spaceAfterSelectorSeparator() {
211 return $this->space('AfterSelectorSeparator');
214 public function spaceBeforeListArgumentSeparator($sSeparator) {
215 return $this->space('BeforeListArgumentSeparator', $sSeparator);
218 public function spaceAfterListArgumentSeparator($sSeparator) {
219 return $this->space('AfterListArgumentSeparator', $sSeparator);
222 public function spaceBeforeOpeningBrace() {
223 return $this->space('BeforeOpeningBrace');
227 * Runs the given code, either swallowing or passing exceptions, depending on the bIgnoreExceptions setting.
229 public function safely($cCode) {
230 if($this->oFormat->get('IgnoreExceptions')) {
231 // If output exceptions are ignored, run the code with exception guards
232 try {
233 return $cCode();
234 } catch (OutputException $e) {
235 return null;
236 } //Do nothing
237 } else {
238 // Run the code as-is
239 return $cCode();
244 * Clone of the implode function but calls ->render with the current output format instead of __toString()
246 public function implode($sSeparator, $aValues, $bIncreaseLevel = false) {
247 $sResult = '';
248 $oFormat = $this->oFormat;
249 if($bIncreaseLevel) {
250 $oFormat = $oFormat->nextLevel();
252 $bIsFirst = true;
253 foreach($aValues as $mValue) {
254 if($bIsFirst) {
255 $bIsFirst = false;
256 } else {
257 $sResult .= $sSeparator;
259 if($mValue instanceof \Sabberworm\CSS\Renderable) {
260 $sResult .= $mValue->render($oFormat);
261 } else {
262 $sResult .= $mValue;
265 return $sResult;
268 public function removeLastSemicolon($sString) {
269 if($this->oFormat->get('SemicolonAfterLastRule')) {
270 return $sString;
272 $sString = explode(';', $sString);
273 if(count($sString) < 2) {
274 return $sString[0];
276 $sLast = array_pop($sString);
277 $sNextToLast = array_pop($sString);
278 array_push($sString, $sNextToLast.$sLast);
279 return implode(';', $sString);
282 private function prepareSpace($sSpaceString) {
283 return str_replace("\n", "\n".$this->indent(), $sSpaceString);
286 private function indent() {
287 return str_repeat($this->oFormat->sIndentation, $this->oFormat->level());