Server IP : 66.29.132.124 / Your IP : 52.14.140.108 Web Server : LiteSpeed System : Linux business141.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : wavevlvu ( 1524) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/wavevlvu/book24.ng/vendor/tijsverkoyen/css-to-inline-styles/src/ |
Upload File : |
<?php namespace TijsVerkoyen\CssToInlineStyles; use Symfony\Component\CssSelector\CssSelector; use Symfony\Component\CssSelector\CssSelectorConverter; use Symfony\Component\CssSelector\Exception\ExceptionInterface; use TijsVerkoyen\CssToInlineStyles\Css\Processor; use TijsVerkoyen\CssToInlineStyles\Css\Property\Processor as PropertyProcessor; use TijsVerkoyen\CssToInlineStyles\Css\Rule\Processor as RuleProcessor; class CssToInlineStyles { private $cssConverter; public function __construct() { if (class_exists('Symfony\Component\CssSelector\CssSelectorConverter')) { $this->cssConverter = new CssSelectorConverter(); } } /** * Will inline the $css into the given $html * * Remark: if the html contains <style>-tags those will be used, the rules * in $css will be appended. * * @param string $html * @param string $css * * @return string */ public function convert($html, $css = null) { $document = $this->createDomDocumentFromHtml($html); $processor = new Processor(); // get all styles from the style-tags $rules = $processor->getRules( $processor->getCssFromStyleTags($html) ); if ($css !== null) { $rules = $processor->getRules($css, $rules); } $document = $this->inline($document, $rules); return $this->getHtmlFromDocument($document); } /** * Inline the given properties on an given DOMElement * * @param \DOMElement $element * @param Css\Property\Property[] $properties * * @return \DOMElement */ public function inlineCssOnElement(\DOMElement $element, array $properties) { if (empty($properties)) { return $element; } $cssProperties = array(); $inlineProperties = array(); foreach ($this->getInlineStyles($element) as $property) { $inlineProperties[$property->getName()] = $property; } foreach ($properties as $property) { if (!isset($inlineProperties[$property->getName()])) { $cssProperties[$property->getName()] = $property; } } $rules = array(); foreach (array_merge($cssProperties, $inlineProperties) as $property) { $rules[] = $property->toString(); } $element->setAttribute('style', implode(' ', $rules)); return $element; } /** * Get the current inline styles for a given DOMElement * * @param \DOMElement $element * * @return Css\Property\Property[] */ public function getInlineStyles(\DOMElement $element) { $processor = new PropertyProcessor(); return $processor->convertArrayToObjects( $processor->splitIntoSeparateProperties( $element->getAttribute('style') ) ); } /** * @param string $html * * @return \DOMDocument */ protected function createDomDocumentFromHtml($html) { $document = new \DOMDocument('1.0', 'UTF-8'); $internalErrors = libxml_use_internal_errors(true); $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); libxml_use_internal_errors($internalErrors); $document->formatOutput = true; return $document; } /** * @param \DOMDocument $document * * @return string */ protected function getHtmlFromDocument(\DOMDocument $document) { // retrieve the document element // we do it this way to preserve the utf-8 encoding $htmlElement = $document->documentElement; $html = $document->saveHTML($htmlElement); $html = trim($html); // retrieve the doctype $document->removeChild($htmlElement); $doctype = $document->saveHTML(); $doctype = trim($doctype); // if it is the html5 doctype convert it to lowercase if ($doctype === '<!DOCTYPE html>') { $doctype = strtolower($doctype); } return $doctype."\n".$html; } /** * @param \DOMDocument $document * @param Css\Rule\Rule[] $rules * * @return \DOMDocument */ protected function inline(\DOMDocument $document, array $rules) { if (empty($rules)) { return $document; } $propertyStorage = new \SplObjectStorage(); $xPath = new \DOMXPath($document); usort($rules, array(RuleProcessor::class, 'sortOnSpecificity')); foreach ($rules as $rule) { try { if (null !== $this->cssConverter) { $expression = $this->cssConverter->toXPath($rule->getSelector()); } else { // Compatibility layer for Symfony 2.7 and older $expression = CssSelector::toXPath($rule->getSelector()); } } catch (ExceptionInterface $e) { continue; } $elements = $xPath->query($expression); if ($elements === false) { continue; } foreach ($elements as $element) { $propertyStorage[$element] = $this->calculatePropertiesToBeApplied( $rule->getProperties(), $propertyStorage->contains($element) ? $propertyStorage[$element] : array() ); } } foreach ($propertyStorage as $element) { $this->inlineCssOnElement($element, $propertyStorage[$element]); } return $document; } /** * Merge the CSS rules to determine the applied properties. * * @param Css\Property\Property[] $properties * @param Css\Property\Property[] $cssProperties existing applied properties indexed by name * * @return Css\Property\Property[] updated properties, indexed by name */ private function calculatePropertiesToBeApplied(array $properties, array $cssProperties) { if (empty($properties)) { return $cssProperties; } foreach ($properties as $property) { if (isset($cssProperties[$property->getName()])) { $existingProperty = $cssProperties[$property->getName()]; //skip check to overrule if existing property is important and current is not if ($existingProperty->isImportant() && !$property->isImportant()) { continue; } //overrule if current property is important and existing is not, else check specificity $overrule = !$existingProperty->isImportant() && $property->isImportant(); if (!$overrule) { $overrule = $existingProperty->getOriginalSpecificity()->compareTo($property->getOriginalSpecificity()) <= 0; } if ($overrule) { unset($cssProperties[$property->getName()]); $cssProperties[$property->getName()] = $property; } } else { $cssProperties[$property->getName()] = $property; } } return $cssProperties; } }