Skip to content

Commit

Permalink
Update InlineCss
Browse files Browse the repository at this point in the history
  • Loading branch information
euromark committed Apr 16, 2014
1 parent 9a18974 commit 8258d91
Show file tree
Hide file tree
Showing 4 changed files with 960 additions and 30 deletions.
4 changes: 3 additions & 1 deletion Lib/InlineCssLib.php
Expand Up @@ -56,8 +56,10 @@ public function process($html, $css = null) {
*/
protected function _processEmogrifier($html, $css) {
$css .= $this->_extractAndRemoveCss($html);
App::import('Vendor', 'Emogrifier', array('file' => 'emogrifier' . DS . 'emogrifier.php'));
App::import('Vendor', 'Tools.Emogrifier', array('file' => 'Emogrifier/Emogrifier.php'));

$Emogrifier = new Emogrifier($html, $css);
$Emogrifier->preserveEncoding = true;

return @$Emogrifier->emogrify();
}
Expand Down
148 changes: 134 additions & 14 deletions Test/Case/Lib/InlineCssLibTest.php
Expand Up @@ -7,22 +7,28 @@ class InlineCssLibTest extends MyCakeTestCase {
public function setUp() {
$this->InlineCss = new InlineCssLib();

$res = App::import('Vendor', 'Tools.CssToInlineStyles', array('file' => 'CssToInlineStyles' . DS . 'CssToInlineStyles.php'));
$this->skipIf(!$res);
$result = App::import('Vendor', 'Tools.CssToInlineStyles', array('file' => 'CssToInlineStyles' . DS . 'CssToInlineStyles.php'));
$this->skipIf(!$result);

parent::setUp();
}

/**
* InlineCssLibTest::testProcess()
*
* @return void
*/
public function testProcess() {
$res = $this->InlineCss->process($this->testHtml);
$result = $this->InlineCss->process($this->testHtml);
$this->debug($this->testHtml);
$this->debug($res);
}

public function testProcessAlternativeEngine() {
//TODO
$this->debug($result);
}

/**
* InlineCssLibTest::testProcessPlainPiece()
*
* @return void
*/
public function testProcessPlainPiece() {
$html = 'blabla
<style>
Expand All @@ -38,9 +44,9 @@ public function testProcessPlainPiece() {
</div>
bla';

$res = $this->InlineCss->process($html);
$result = $this->InlineCss->process($html);
$this->debug($html);
$this->debug($res);
$this->debug($result);
}

public $testHtml = '<!doctype html>
Expand All @@ -64,6 +70,11 @@ public function testProcessPlainPiece() {
</body>
</html>';

/**
* InlineCssLibTest::testProcessUtf8()
*
* @return void
*/
public function testProcessUtf8() {
$this->skipIf(version_compare(PHP_VERSION, '5.4.0') < 0, 'UTF8 only works with PHP5.4 and above');

Expand All @@ -76,14 +87,123 @@ public function testProcessUtf8() {
</style>
<div id="container">
<h1>チェック</h1>
<p>チェックインは15:00以降です。アーリーチェックインはリクエストにて</p>
<p>降です。アーリーチェックインはリクエ</p>
<p class="small">チェック\'foo\'</p>
</div>
bla';
$result = $this->InlineCss->process($html);
$this->debug($html);
$this->debug($result);
$this->assertTextStartsWith('チェック', $result);
$this->assertTextContains('<h1 style="font-size: 2em; font-weight: bold;">チェック</h1>', $result);
}

/**
* InlineCssLibTest::testProcessSpecialChars()
*
* @return void
*/
public function testProcessSpecialChars() {
$this->skipIf(version_compare(PHP_VERSION, '5.4.0') < 0, 'UTF8 only works with PHP5.4 and above');

$html = '<style>
div#container { margin: 1em auto; }
h1 { font-weight: bold; font-size: 2em; }
table tr td { margin-bottom: 1em; font-family: sans-serif; text-align: justify; }
</style>
<div id="container">
<h1>&laquo;X&raquo; &amp; Y &hellip;</h1>
<table>
<tr>
<td style="font-size: 0; line-height: 0;" height="20" colspan="2">&nbsp;</td>
</tr>
</table>
</div>
bla';
$result = $this->InlineCss->process($html);
$expected = '<td style="font-family: sans-serif; margin-bottom: 1em; text-align: justify; font-size: 0; line-height: 0;" height="20" colspan="2">&nbsp;</td>';
$this->debug($result);
$this->assertTextContains($expected, $result);
}

/**
* InlineCssLibTest::testProcessAlternativeEngine()
*
* @return void
*/
public function testProcessAlternativeEngine() {
$this->out('Emogrifier');
$this->InlineCss = new InlineCssLib(array('engine' => InlineCssLib::ENGINE_EMOGRIFIER));
$html = '<b>blabla</b><style>
div#container { margin: 1em auto; }
h1 { font-weight: bold; font-size: 2em; }
p { margin-bottom: 1em; font-family: sans-serif; text-align: justify; }
p.small { font-size: 70%; }
</style>
<div id="container">
<h1>Sample Page Title</h1>
<p>Bacon ipsum dolor sit amet in cow elit, in t-bone qui meatloaf corned beef aute ullamco minim. Consequat swine short ribs pastrami jerky.</p>
<p class="small">Some small note!</p>
</div>
bla';

$result = $this->InlineCss->process($html);
$this->debug($html);
$this->debug($result);
}

/**
* InlineCssLibTest::testProcessUtf8()
*
* @return void
*/
public function testProcessUtf8AlternativeEngine() {
$this->InlineCss = new InlineCssLib(array('engine' => InlineCssLib::ENGINE_EMOGRIFIER));

$html = 'チェック
<style>
div#container { margin: 1em auto; }
h1 { font-weight: bold; font-size: 2em; }
p { margin-bottom: 1em; font-family: sans-serif; text-align: justify; }
p.small { font-size: 70%; }
</style>
<div id="container">
<h1>チェック</h1>
<p>降です。アーリーチェックインはリクエ</p>
<p class="small">チェック\'foo\'</p>
</div>
bla';
$res = $this->InlineCss->process($html);
$result = $this->InlineCss->process($html);
$this->debug($html);
$this->debug($res);
$this->assertTextStartsWith('チェック', $res);
$this->debug($result);
//$this->assertTextStartsWith('チェック', $result);
//$this->assertTextContains('<h1 style="font-size: 2em; font-weight: bold;">チェック</h1>', $result);
}

/**
* InlineCssLibTest::testProcessSpecialChars()
*
* @return void
*/
public function testProcessSpecialCharsAlternativeEngine() {
$this->InlineCss = new InlineCssLib(array('engine' => InlineCssLib::ENGINE_EMOGRIFIER));

$html = '<style>
div#container { margin: 1em auto; }
h1 { font-weight: bold; font-size: 2em; }
table tr td { margin-bottom: 1em; font-family: sans-serif; text-align: justify; }
</style>
<div id="container">
<h1>&laquo;X&raquo; &amp; Y &hellip;</h1>
<table>
<tr>
<td style="font-size: 0; line-height: 0;" height="20" colspan="2">&nbsp;</td>
</tr>
</table>
</div>
bla';
$result = $this->InlineCss->process($html);
$this->debug($result);
}

}
45 changes: 30 additions & 15 deletions Vendor/CssToInlineStyles/CssToInlineStyles.php
Expand Up @@ -112,17 +112,17 @@ private function buildXPathQuery($selector)
// E + F, Matches any F element immediately preceded by an element
'/(\w)\s*\+\s*(\w)/',
// E[foo], Matches any E element with the "foo" attribute set (whatever the value)
'/(\w)\[([\w\-]+)]/',
'/(\w)\[([\w\-_]+)]/',
// E[foo="warning"], Matches any E element whose "foo" attribute value is exactly equal to "warning"
'/(\w)\[([\w\-]+)\=\"(.*)\"]/',
'/(\w)\[([\w\-_]+)\=\"(.*)\"]/',
// div.warning, HTML only. The same as DIV[class~="warning"]
'/(\w+|\*)+\.([\w\-]+)+/',
'/(\w+|\*)+\.([\w\-_]+)+/',
// .warning, HTML only. The same as *[class~="warning"]
'/\.([\w\-]+)/',
'/\.([\w\-_]+)/',
// E#myid, Matches any E element with id-attribute equal to "myid"
'/(\w+)+\#([\w\-]+)/',
'/(\w+)+\#([\w\-_]+)/',
// #myid, Matches any element with id-attribute equal to "myid"
'/\#([\w\-]+)/'
'/\#([\w\-_]+)/'
);

// the xPath-equivalent
Expand Down Expand Up @@ -164,13 +164,13 @@ private function buildXPathQuery($selector)
private function calculateCSSSpecifity($selector)
{
// cleanup selector
$selector = str_replace(array('>', '+'), array(' > ', ' + '), $selector);
$selector = preg_replace('/\s?(\>|\+)\s?/', '$1', $selector);

// init var
$specifity = 0;

// split the selector into chunks based on spaces
$chunks = explode(' ', $selector);
$chunks = preg_split( '/\>|\+|\s/', $selector);

// loop chunks
foreach ($chunks as $chunk) {
Expand Down Expand Up @@ -233,7 +233,7 @@ public function convert($outputXHTML = false)
// any style-blocks found?
if (!empty($matches[2])) {
// add
foreach($matches[2] as $match) $this->css .= trim($match) ."\n";
foreach($matches[2] as $match) $this->css .= "\n" . trim($match) ."\n";
}
}

Expand All @@ -246,6 +246,12 @@ public function convert($outputXHTML = false)
// set error level
libxml_use_internal_errors(true);

//Check if html has ISO encoding and convert to UTF-8
$encoding = mb_detect_encoding($this->html, array('UTF-8', 'ISO-8859-1'));
if ($encoding === 'ISO-8859-1') {
$this->html = utf8_encode($this->html);
}

// load HTML
$document->loadHTML($this->html);

Expand Down Expand Up @@ -442,7 +448,6 @@ public function convert($outputXHTML = false)

// should we output XHTML?
if ($outputXHTML) {
// set formating
$document->formatOutput = true;

// get the HTML as XML
Expand All @@ -457,21 +462,33 @@ public function convert($outputXHTML = false)
$endPosition = strpos($html, '?>', $startPosition);

// remove the XML-header
$html = ltrim(substr($html, $endPosition + 1));
$html = ltrim(substr($html, $endPosition + 2));
}
}

// just regular HTML 4.01 as it should be used in newsletters
else {
// get the HTML
$document->formatOutput = true;
$html = $document->saveHTML();
}

if ($this->correctUtf8) {
// Only for >PHP5.4
$chars = array(
'&nbsp;', '&laquo;', '&raquo;', '&lt;', '&gt;',
'&copy;', '&reg;', '&trade;', '&apos;', '&amp;', '&quot;',
);
// Make sure chars dont annihilate the result
foreach ($chars as $char) {
$html = str_replace($char, '[[' . substr($char, 1, -1) . ']]', $html);
}
// Correct scrambled UTF8 chars (&atilde;&#131;...) back to their correct representation.
$html = html_entity_decode($html, ENT_XHTML, 'UTF-8');
$html = html_entity_decode($html, ENT_XHTML);
$html = utf8_decode($html);
foreach ($chars as $char) {
$html = str_replace('[[' . substr($char, 1, -1) . ']]', $char, $html);
}
}

// cleanup the HTML if we need to
Expand All @@ -482,11 +499,9 @@ public function convert($outputXHTML = false)
$html = $this->stripOriginalStyleTags($html);
}

// return
return $html;
}


/**
* Get the encoding to use
*
Expand Down Expand Up @@ -517,7 +532,7 @@ private function processCSS()
// remove comments
$css = preg_replace('|/\*.*?\*/|', '', $css);

// remove spaces
// remove double spaces
$css = preg_replace('/\s\s+/', ' ', $css);

if ($this->excludeMediaQueries) {
Expand Down

0 comments on commit 8258d91

Please sign in to comment.