Completed
Push — master ( 765a44...73a9cf )
by Lars
02:54
created

CssToInlineStyles::setLoadCSSFromHTML()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
namespace voku\CssToInlineStyles;
3
4
use Symfony\Component\CssSelector\CssSelectorConverter;
5
use Symfony\Component\CssSelector\Exception\ExceptionInterface;
6
7
/**
8
 * CSS to Inline Styles class
9
 *
10
 * @author     Tijs Verkoyen <[email protected]>
11
 */
12
class CssToInlineStyles
13
{
14
15
  /**
16
   * regular expression: css media queries
17
   *
18
   * @var string
19
   */
20
  private static $cssMediaQueriesRegEx = '#@media\\s+(?:only\\s)?(?:[\\s{\\(]|screen|all)\\s?[^{]+{.*}\\s*}\\s*#misU';
21
22
  /**
23
   * regular expression: conditional inline style tags
24
   *
25
   * @var string
26
   */
27
  private static $excludeConditionalInlineStylesBlockRegEx = '/<!--.*<style.*?-->/is';
28
29
  /**
30
   * regular expression: inline style tags
31
   *
32
   * @var string
33
   */
34
  private static $styleTagRegEx = '|<style(.*)>(.*)</style>|isU';
35
36
  /**
37
   * regular expression: css-comments
38
   *
39
   * @var string
40
   */
41
  private static $styleCommentRegEx = '/\\/\\*.*\\*\\//sU';
42
43
  /**
44
   * The CSS to use
45
   *
46
   * @var  string
47
   */
48
  private $css;
49
50
  /**
51
   * Should the generated HTML be cleaned
52
   *
53
   * @var  bool
54
   */
55
  private $cleanup = false;
56
57
  /**
58
   * The encoding to use.
59
   *
60
   * @var  string
61
   */
62
  private $encoding = 'UTF-8';
63
64
  /**
65
   * The HTML to process
66
   *
67
   * @var  string
68
   */
69
  private $html;
70
71
  /**
72
   * Use inline-styles block as CSS
73
   *
74
   * @var bool
75
   */
76
  private $useInlineStylesBlock = false;
77
78
  /**
79
   * Use link block reference as CSS
80
   *
81
   * @var bool
82
   */
83
  private $loadCSSFromHTML = false;
84
85
  /**
86
   * Strip original style tags
87
   *
88
   * @var bool
89
   */
90
  private $stripOriginalStyleTags = false;
91
92
  /**
93
   * Exclude conditional inline-style blocks
94
   *
95
   * @var bool
96
   */
97
  private $excludeConditionalInlineStylesBlock = true;
98
99
  /**
100
   * Exclude media queries from "$this->css" and keep media queries for inline-styles blocks
101
   *
102
   * @var bool
103
   */
104
  private $excludeMediaQueries = true;
105
106
  /**
107
   * Creates an instance, you could set the HTML and CSS here, or load it
108
   * later.
109
   *
110
   * @param  null|string $html The HTML to process.
111
   * @param  null|string $css  The CSS to use.
112
   */
113 44
  public function __construct($html = null, $css = null)
114
  {
115 44
    if (null !== $html) {
116 1
      $this->setHTML($html);
117 1
    }
118
119 44
    if (null !== $css) {
120 1
      $this->setCSS($css);
121 1
    }
122 44
  }
123
124
  /**
125
   * Set HTML to process
126
   *
127
   * @param  string $html The HTML to process.
128
   */
129 42
  public function setHTML($html)
130
  {
131
    // strip style definitions, if we use css-class "cleanup" on a style-element
132 42
    $this->html = (string)preg_replace('/<style[^>]+class="cleanup"[^>]*>.*<\/style>/Usi', ' ', $html);
133 42
  }
134
135
  /**
136
   * Set CSS to use
137
   *
138
   * @param  string $css The CSS to use.
139
   */
140 40
  public function setCSS($css)
141
  {
142 40
    $this->css = (string)$css;
143 40
  }
144
145
  /**
146
   * Sort an array on the specificity element
147
   *
148
   * @return int
149
   *
150
   * @param Specificity[] $e1 The first element.
151
   * @param Specificity[] $e2 The second element.
152
   */
153 15
  private static function sortOnSpecificity($e1, $e2)
154
  {
155
    // Compare the specificity
156 15
    $value = $e1['specificity']->compareTo($e2['specificity']);
157
158
    // if the specificity is the same, use the order in which the element appeared
159 15
    if (0 === $value) {
160 10
      $value = $e1['order'] - $e2['order'];
161 10
    }
162
163 15
    return $value;
164
  }
165
166
  /**
167
   * Converts the loaded HTML into an HTML-string with inline styles based on the loaded CSS
168
   *
169
   * @return string
170
   *
171
   * @param  bool $outputXHTML                 [optional] Should we output valid XHTML?
172
   * @param  int  $libXMLOptions               [optional] $libXMLOptions Since PHP 5.4.0 and Libxml 2.6.0, you may also
173
   *                                                      use the options parameter to specify additional Libxml
174
   *                                                      parameters. Recommend these options: LIBXML_HTML_NOIMPLIED |
175
   *                                                      LIBXML_HTML_NODEFDTD
176
   * @param false|string                       [optional] Set the path to your external css-files.
177
   *
178
   * @throws Exception
179
   */
180 42
  public function convert($outputXHTML = false, $libXMLOptions = 0, $path = false)
181
  {
182
    // redefine
183 42
    $outputXHTML = (bool)$outputXHTML;
184
185
    // validate
186 42
    if (!$this->html) {
187 1
      throw new Exception('No HTML provided.');
188
    }
189
190
    // use local variables
191 41
    $css = $this->css;
192
193
    // create new DOMDocument
194 41
    $document = $this->createDOMDocument($this->html, $libXMLOptions);
195
196
    // check if there is some link css reference
197 41
    if ($this->loadCSSFromHTML) {
198 1
      foreach ($document->getElementsByTagName('link') as $node) {
199 1
        $file = ($path ? $path : __DIR__) . '/' .  $node->getAttribute('href');
200
201 1
        if (file_exists($file)) {
202 1
          $css .= file_get_contents($file);
203
204
          // converting to inline css because we don't need/want to load css files, so remove the link
205 1
          $node->parentNode->removeChild($node);
206 1
        }
207 1
      }
208 1
    }
209
210
    // should we use inline style-block
211 41
    if ($this->useInlineStylesBlock) {
212
213 25
      if (true === $this->excludeConditionalInlineStylesBlock) {
214 21
        $this->html = preg_replace(self::$excludeConditionalInlineStylesBlockRegEx, '', $this->html);
215 21
      }
216
217 25
      $css .= $this->getCssFromInlineHtmlStyleBlock($this->html);
218 25
    }
219
220
    // process css
221 41
    $cssRules = $this->processCSS($css);
222
223
    // create new XPath
224 41
    $xPath = $this->createXPath($document, $cssRules);
225
226
    // strip original style tags if we need to
227 41
    if ($this->stripOriginalStyleTags === true) {
228 13
      $this->stripOriginalStyleTags($xPath);
229 13
    }
230
231
    // cleanup the HTML if we need to
232 41
    if (true === $this->cleanup) {
233 3
      $this->cleanupHTML($xPath);
234 3
    }
235
236
    // should we output XHTML?
237 41
    if (true === $outputXHTML) {
238
      // set formatting
239 5
      $document->formatOutput = true;
240
241
      // get the HTML as XML
242 5
      $html = $document->saveXML(null, LIBXML_NOEMPTYTAG);
243
244
      // remove the XML-header
245 5
      return ltrim(preg_replace('/<\?xml.*\?>/', '', $html));
246
    }
247
248
    // just regular HTML 4.01 as it should be used in newsletters
249 36
    return $document->saveHTML();
250
  }
251
252
  /**
253
   * get css from inline-html style-block
254
   *
255
   * @param string $html
256
   *
257
   * @return string
258
   */
259 27
  public function getCssFromInlineHtmlStyleBlock($html)
260
  {
261
    // init var
262 27
    $css = '';
263 27
    $matches = array();
264
265
    // match the style blocks
266 27
    preg_match_all(self::$styleTagRegEx, $html, $matches);
267
268
    // any style-blocks found?
269 27
    if (!empty($matches[2])) {
270
      // add
271 26
      foreach ($matches[2] as $match) {
272 26
        $css .= trim($match) . "\n";
273 26
      }
274 26
    }
275
276 27
    return $css;
277
  }
278
279
  /**
280
   * Process the loaded CSS
281
   *
282
   * @param $css
283
   *
284
   * @return array
285
   */
286 41
  private function processCSS($css)
287
  {
288
    //reset current set of rules
289 41
    $cssRules = array();
290
291
    // init vars
292 41
    $css = (string)$css;
293
294 41
    $css = $this->doCleanup($css);
295
296
    // rules are splitted by }
297 41
    $rules = (array)explode('}', $css);
298
299
    // init var
300 41
    $i = 1;
301
302
    // loop rules
303 41
    foreach ($rules as $rule) {
304
      // split into chunks
305 41
      $chunks = explode('{', $rule);
306
307
      // invalid rule?
308 41
      if (!isset($chunks[1])) {
309 41
        continue;
310
      }
311
312
      // set the selectors
313 31
      $selectors = trim($chunks[0]);
314
315
      // get cssProperties
316 31
      $cssProperties = trim($chunks[1]);
317
318
      // split multiple selectors
319 31
      $selectors = (array)explode(',', $selectors);
320
321
      // loop selectors
322 31
      foreach ($selectors as $selector) {
323
        // cleanup
324 31
        $selector = trim($selector);
325
326
        // build an array for each selector
327 31
        $ruleSet = array();
328
329
        // store selector
330 31
        $ruleSet['selector'] = $selector;
331
332
        // process the properties
333 31
        $ruleSet['properties'] = $this->processCSSProperties($cssProperties);
334
335
336
        // calculate specificity
337 31
        $ruleSet['specificity'] = Specificity::fromSelector($selector);
338
339
        // remember the order in which the rules appear
340 31
        $ruleSet['order'] = $i;
341
342
        // add into rules
343 31
        $cssRules[] = $ruleSet;
344
345
        // increment
346 31
        $i++;
347 31
      }
348 41
    }
349
350
    // sort based on specificity
351 41
    if (0 !== count($cssRules)) {
352 31
      usort($cssRules, array(__CLASS__, 'sortOnSpecificity'));
353 31
    }
354
355 41
    return $cssRules;
356
  }
357
358
  /**
359
   * @param string $css
360
   *
361
   * @return string
362
   */
363 41
  private function doCleanup($css)
364
  {
365
    // remove newlines & replace double quotes by single quotes
366 41
    $css = str_replace(
367 41
        array("\r", "\n", '"'),
368 41
        array('', '', '\''),
369
        $css
370 41
    );
371
372
    // remove comments
373 41
    $css = preg_replace(self::$styleCommentRegEx, '', $css);
374
375
    // remove spaces
376 41
    $css = preg_replace('/\s\s+/', ' ', $css);
377
378
    // remove css media queries
379 41
    if (true === $this->excludeMediaQueries) {
380 40
      $css = $this->stripeMediaQueries($css);
381 40
    }
382
383 41
    return (string)$css;
384
  }
385
386
  /**
387
   * remove css media queries from the string
388
   *
389
   * @param string $css
390
   *
391
   * @return string
392
   */
393 40
  private function stripeMediaQueries($css)
394
  {
395
    // remove comments previously to matching media queries
396 40
    $css = preg_replace(self::$styleCommentRegEx, '', $css);
397
398 40
    return (string)preg_replace(self::$cssMediaQueriesRegEx, '', $css);
399
  }
400
401
  /**
402
   * Process the CSS-properties
403
   *
404
   * @return array
405
   *
406
   * @param  string $propertyString The CSS-properties.
407
   */
408 31
  private function processCSSProperties($propertyString)
409
  {
410
    // split into chunks
411 31
    $properties = $this->splitIntoProperties($propertyString);
412
413
    // init var
414 31
    $pairs = array();
415
416
    // loop properties
417 31
    foreach ($properties as $property) {
418
      // split into chunks
419 31
      $chunks = (array)explode(':', $property, 2);
420
421
      // validate
422 31
      if (!isset($chunks[1])) {
423 25
        continue;
424
      }
425
426
      // cleanup
427 30
      $chunks[0] = trim($chunks[0]);
428 30
      $chunks[1] = trim($chunks[1]);
429
430
      // add to pairs array
431
      if (
432 30
          !isset($pairs[$chunks[0]])
433 30
          ||
434 3
          !in_array($chunks[1], $pairs[$chunks[0]], true)
435 30
      ) {
436 30
        $pairs[$chunks[0]][] = $chunks[1];
437 30
      }
438 31
    }
439
440
    // sort the pairs
441 31
    ksort($pairs);
442
443
    // return
444 31
    return $pairs;
445
  }
446
447
  /**
448
   * Split a style string into an array of properties.
449
   * The returned array can contain empty strings.
450
   *
451
   * @param string $styles ex: 'color:blue;font-size:12px;'
452
   *
453
   * @return array an array of strings containing css property ex: array('color:blue','font-size:12px')
454
   */
455 31
  private function splitIntoProperties($styles)
456
  {
457 31
    $properties = (array)explode(';', $styles);
458 31
    $propertiesCount = count($properties);
459
460 31
    for ($i = 0; $i < $propertiesCount; $i++) {
461
      // If next property begins with base64,
462
      // Then the ';' was part of this property (and we should not have split on it).
463
      if (
464 31
          isset($properties[$i + 1])
465 31
          &&
466 24
          strpos($properties[$i + 1], 'base64,') !== false
467 31
      ) {
468 1
        $properties[$i] .= ';' . $properties[$i + 1];
469 1
        $properties[$i + 1] = '';
470 1
        ++$i;
471 1
      }
472 31
    }
473
474 31
    return $properties;
475
  }
476
477
  /**
478
   * create DOMDocument from HTML
479
   *
480
   * @param $html
481
   *
482
   * @return \DOMDocument
483
   */
484 41
  private function createDOMDocument($html, $libXMLOptions)
485
  {
486
    // create new DOMDocument
487 41
    $document = new \DOMDocument('1.0', $this->getEncoding());
488
489
    // DOMDocument settings
490 41
    $document->preserveWhiteSpace = false;
491 41
    $document->formatOutput = true;
492
493
    // set error level
494 41
    $internalErrors = libxml_use_internal_errors(true);
495
496
    // load HTML
497
    //
498
    // with UTF-8 hack: http://php.net/manual/en/domdocument.loadhtml.php#95251
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
499
    //
500 41
    $document->loadHTML('<?xml encoding="' . $this->getEncoding() . '">' . $html, $libXMLOptions);
501
502
    // remove the "xml-encoding" hack
503 41
    foreach ($document->childNodes as $child) {
504 41
      if ($child->nodeType == XML_PI_NODE) {
505 41
        $document->removeChild($child);
506 41
      }
507 41
    }
508
509
    // set encoding
510 41
    $document->encoding = $this->getEncoding();
511
512
    // restore error level
513 41
    libxml_use_internal_errors($internalErrors);
514
515 41
    return $document;
516
  }
517
518
  /**
519
   * Get the encoding to use
520
   *
521
   * @return string
522
   */
523 41
  private function getEncoding()
524
  {
525 41
    return $this->encoding;
526
  }
527
528
  /**
529
   * create XPath
530
   *
531
   * @param \DOMDocument $document
532
   * @param array        $cssRules
533
   *
534
   * @return \DOMXPath
535
   */
536 41
  private function createXPath(\DOMDocument $document, array $cssRules)
537
  {
538 41
    $xPath = new \DOMXPath($document);
539
540
    // any rules?
541 41
    if (0 !== count($cssRules)) {
542
      // loop rules
543 31
      foreach ($cssRules as $rule) {
544
545
        try {
546 31
          $converter = new CssSelectorConverter();
547 31
          $query = $converter->toXPath($rule['selector']);
548 31
        } catch (ExceptionInterface $e) {
549 4
          $query = null;
550
        }
551 31
        $converter = null;
552
553
        // validate query
554 31
        if (null === $query) {
555 4
          continue;
556
        }
557
558
        // search elements
559 29
        $elements = $xPath->query($query);
560
561
        // validate elements
562 29
        if (false === $elements) {
563
          continue;
564
        }
565
566
        // loop found elements
567 29
        foreach ($elements as $element) {
568
569
          /**
570
           * @var $element \DOMElement
571
           */
572
573
          // no styles stored?
574 29
          if (null === $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')) {
575
576
            // init var
577 29
            $originalStyle = '';
578
579 29
            if (null !== $element->attributes->getNamedItem('style')) {
580 6
              $originalStyle = $element->attributes->getNamedItem('style')->value;
581 6
            }
582
583
            // store original styles
584 29
            $element->setAttribute('data-css-to-inline-styles-original-styles', $originalStyle);
585
586
            // clear the styles
587 29
            $element->setAttribute('style', '');
588 29
          }
589
590 29
          $propertiesString = $this->createPropertyChunks($element, $rule['properties']);
591
592
          // set attribute
593 29
          if ('' != $propertiesString) {
594 29
            $element->setAttribute('style', $propertiesString);
595 29
          }
596 29
        }
597 31
      }
598
599
      // reapply original styles
600
      // search elements
601 31
      $elements = $xPath->query('//*[@data-css-to-inline-styles-original-styles]');
602
603
      // loop found elements
604 31
      foreach ($elements as $element) {
605
        // get the original styles
606 29
        $originalStyle = $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')->value;
607
608 29
        if ('' != $originalStyle) {
609 6
          $originalStyles = $this->splitIntoProperties($originalStyle);
610
611 6
          $originalProperties = $this->splitStyleIntoChunks($originalStyles);
612
613 6
          $propertiesString = $this->createPropertyChunks($element, $originalProperties);
614
615
          // set attribute
616 6
          if ('' != $propertiesString) {
617 6
            $element->setAttribute('style', $propertiesString);
618 6
          }
619 6
        }
620
621
        // remove placeholder
622 29
        $element->removeAttribute('data-css-to-inline-styles-original-styles');
623 31
      }
624 31
    }
625
626 41
    return $xPath;
627
  }
628
629
  /**
630
   * @param \DOMElement $element
631
   * @param array       $ruleProperties
632
   *
633
   * @return array
634
   */
635 29
  private function createPropertyChunks(\DOMElement $element, array $ruleProperties)
636
  {
637
    // init var
638 29
    $properties = array();
639
640
    // get current styles
641 29
    $stylesAttribute = $element->attributes->getNamedItem('style');
642
643
    // any styles defined before?
644 29
    if (null !== $stylesAttribute) {
645
      // get value for the styles attribute
646 29
      $definedStyles = (string)$stylesAttribute->value;
647
648
      // split into properties
649 29
      $definedProperties = $this->splitIntoProperties($definedStyles);
650
651 29
      $properties = $this->splitStyleIntoChunks($definedProperties);
652 29
    }
653
654
    // add new properties into the list
655 29
    foreach ($ruleProperties as $key => $value) {
656
      // If one of the rules is already set and is !important, don't apply it,
657
      // except if the new rule is also important.
658
      if (
659 29
          !isset($properties[$key])
660 29
          ||
661 7
          false === stripos($properties[$key], '!important')
662 7
          ||
663 3
          false !== stripos(implode('', (array)$value), '!important')
664 29
      ) {
665 29
        $properties[$key] = $value;
666 29
      }
667 29
    }
668
669
    // build string
670 29
    $propertyChunks = array();
671
672
    // build chunks
673 29
    foreach ($properties as $key => $values) {
674 29
      foreach ((array)$values as $value) {
675 29
        $propertyChunks[] = $key . ': ' . $value . ';';
676 29
      }
677 29
    }
678
679 29
    return implode(' ', $propertyChunks);
680
  }
681
682
  /**
683
   * @param array $definedProperties
684
   *
685
   * @return array
686
   */
687 29
  private function splitStyleIntoChunks(array $definedProperties)
688
  {
689
    // init var
690 29
    $properties = array();
691
692
    // loop properties
693 29
    foreach ($definedProperties as $property) {
694
      // validate property
695
      if (
696
          !$property
697 29
          ||
698 14
          strpos($property, ':') === false
699 29
      ) {
700 29
        continue;
701
      }
702
703
      // split into chunks
704 14
      $chunks = (array)explode(':', trim($property), 2);
705
706
      // validate
707 14
      if (!isset($chunks[1])) {
708
        continue;
709
      }
710
711
      // loop chunks
712 14
      $properties[$chunks[0]] = trim($chunks[1]);
713 29
    }
714
715 29
    return $properties;
716
  }
717
718
  /**
719
   * Strip style tags into the generated HTML
720
   *
721
   * @param  \DOMXPath $xPath The DOMXPath for the entire document.
722
   *
723
   * @return string
724
   */
725 13
  private function stripOriginalStyleTags(\DOMXPath $xPath)
726
  {
727
    // get all style tags
728 13
    $nodes = $xPath->query('descendant-or-self::style');
729 13
    foreach ($nodes as $node) {
730 12
      if ($this->excludeMediaQueries === true) {
731
732
        // remove comments previously to matching media queries
733 11
        $node->nodeValue = preg_replace(self::$styleCommentRegEx, '', $node->nodeValue);
734
735
        // search for Media Queries
736 11
        preg_match_all(self::$cssMediaQueriesRegEx, $node->nodeValue, $mqs);
737
738
        // replace the nodeValue with just the Media Queries
739 11
        $node->nodeValue = implode("\n", $mqs[0]);
740
741 11
      } else {
742
        // remove the entire style tag
743 1
        $node->parentNode->removeChild($node);
744
      }
745 13
    }
746 13
  }
747
748
  /**
749
   * Remove id and class attributes.
750
   *
751
   * @param  \DOMXPath $xPath The DOMXPath for the entire document.
752
   *
753
   * @return string
754
   */
755 3
  private function cleanupHTML(\DOMXPath $xPath)
756
  {
757 3
    $nodes = $xPath->query('//@class | //@id');
758 3
    foreach ($nodes as $node) {
759 3
      $node->ownerElement->removeAttributeNode($node);
760 3
    }
761 3
  }
762
763
  /**
764
   * Should the IDs and classes be removed?
765
   *
766
   * @param  bool $on Should we enable cleanup?
767
   */
768 3
  public function setCleanup($on = true)
769
  {
770 3
    $this->cleanup = (bool)$on;
771 3
  }
772
773
  /**
774
   * Set the encoding to use with the DOMDocument
775
   *
776
   * @param  string $encoding The encoding to use.
777
   *
778
   * @deprecated Doesn't have any effect
779
   */
780
  public function setEncoding($encoding)
781
  {
782
    $this->encoding = (string)$encoding;
783
  }
784
785
  /**
786
   * Set use of inline styles block
787
   * If this is enabled the class will use the style-block in the HTML.
788
   *
789
   * @param  bool $on Should we process inline styles?
790
   */
791 25
  public function setUseInlineStylesBlock($on = true)
792
  {
793 25
    $this->useInlineStylesBlock = (bool)$on;
794 25
  }
795
796
  /**
797
       * Set use of inline link block
798
       * If this is enabled the class will use the links reference in the HTML.
799
       *
800
       * @return void
801
       * @param  bool [optional] $on Should we process link styles?
802
       */
803 1
    public function setLoadCSSFromHTML($on = true)
804
     {
805 1
         $this->loadCSSFromHTML = (bool) $on;
806 1
     }
807
808
  /**
809
   * Set strip original style tags
810
   * If this is enabled the class will remove all style tags in the HTML.
811
   *
812
   * @param  bool $on Should we process inline styles?
813
   */
814 16
  public function setStripOriginalStyleTags($on = true)
815
  {
816 16
    $this->stripOriginalStyleTags = (bool)$on;
817 16
  }
818
819
  /**
820
   * Set exclude media queries
821
   *
822
   * If this is enabled the media queries will be removed before inlining the rules.
823
   *
824
   * WARNING: If you use inline styles block "<style>" the this option will keep the media queries.
825
   *
826
   * @param bool $on
827
   */
828 13
  public function setExcludeMediaQueries($on = true)
829
  {
830 13
    $this->excludeMediaQueries = (bool)$on;
831 13
  }
832
833
  /**
834
   * Set exclude conditional inline-style blocks e.g.: <!--[if gte mso 9]><style>.foo { bar } </style><![endif]-->
835
   *
836
   * @param bool $on
837
   */
838 5
  public function setExcludeConditionalInlineStylesBlock($on = true)
839
  {
840 5
    $this->excludeConditionalInlineStylesBlock = (bool)$on;
841 5
  }
842
843
}
844