pax_global_header00006660000000000000000000000064135627445030014523gustar00rootroot0000000000000052 comment=11b37cf2d5552076e7e6b506aaa8dd79e69592fe php-tijsverkoyen-css-to-inline-styles-2.2.2/000077500000000000000000000000001356274450300210525ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/.editorconfig000066400000000000000000000002631356274450300235300ustar00rootroot00000000000000root = true [*] charset = utf-8 end_of_line = lf indent_style = space indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true [*.{json,yml}] indent_size = 2 php-tijsverkoyen-css-to-inline-styles-2.2.2/.gitignore000066400000000000000000000000261356274450300230400ustar00rootroot00000000000000/vendor composer.lock php-tijsverkoyen-css-to-inline-styles-2.2.2/.travis.yml000066400000000000000000000016121356274450300231630ustar00rootroot00000000000000language: php sudo: false dist: trusty cache: directories: - $HOME/.composer/cache/files matrix: include: - php: 5.5 - php: 5.5 env: setup=lowest - php: 5.6 - php: 7.0 - php: 7.0 env: setup=lowest - php: 7.1 - php: 7.2 - php: 7.3 - php: 7.4snapshot env: global: - setup=basic install: - if [[ $setup = 'basic' ]]; then travis_retry composer install --prefer-dist --no-interaction; fi - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable; fi script: - vendor/bin/phpunit --verbose --coverage-clover=coverage.clover after_success: - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi php-tijsverkoyen-css-to-inline-styles-2.2.2/CHANGELOG.md000066400000000000000000000166331356274450300226740ustar00rootroot00000000000000# Changelog since 2.1.0 * Better ordering of style rules and properties, thx to [Hikariii](https://github.com/Hikariii), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/160) * Some Travis improvements, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/158) * Refactor the storage of the computed properties, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/153) * Use possessive quantifiers to avoid reaching PCRE limits, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/146) * Reuse the same CssSelectorConverter, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/152) * Add a test for the removal of comments, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/147) * Add the PHP requirement in the composer.json, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/148) * Fix the detection of style tags, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/149) * Remove the useless Selector class, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/150) # Changelog since 2.0.0 * Remove the charset in css-files before processing, thx to [mdio](https://github.com/mdio) * Several fixes related to UTF8-encoding, thx to [techi602](https://github.com/techi602), [josh18](https://github.com/josh18) * php-syntax-highlighting in the examples, thx to [Big-Shark](https://github.com/Big-Shark) # Changelog since 1.5.5 The 2.0 version is a major overhaul, which is *not* backwards compatible. * From now on you can re-use the class for multiple mails. * A lot less complicated options, as in: no more options at all. * More separate classes which handle their own (tested) methods. * A lot more tests The reason why I did this was to made the class more usable. # Changelog since 1.5.4 * Better README + License * Use DOM instead of regexp in cleanupHTML() * Use Selector class * Fixed stripping of XML-header * Converted $cssRules to a local variable returned by processCSS * Allow Symfony/CssSelector 3.0 * Removed unneeded stability change # Changelog since 1.5.3 * Fix properties split on base64 encoded url content, thx to [tguyard](https://github.com/Giga-gg), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/79) * Reset the xml error handling after usage, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/80) * Remove version from require, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/85) # Changelog since 1.5.2 * Make sure the XML header is removed. # Changelog since 1.5.1 * Refactor removing style tags, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/72) * Set excludeMediaQueries to true as default, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/69) * Normalised eof and removed extra whitespace, thx to [GrahamCampbell](https://github.com/GrahamCampbell), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/68) * Testing Improvements, thx to [GrahamCampbell](https://github.com/GrahamCampbell), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/70) * Add note about charset, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/73) * Deprecate encoding, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/74) * Added a .gitattributes file, thx to [GrahamCampbell](https://github.com/GrahamCampbell), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/71) # Changelog since 1.5.0 * Exclude vendor files from coverage, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/67) * Add tests for Specificity and !important, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/65) # Changelog since 1.4.4 * Made the class compliant with PSR4 # Changelog since 1.4.3 * Removed the .lock-file for real. # Changelog since 1.4.2 * Refactor specificity, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/59) # Changelog since 1.4.1 * Ignore the composer.lock-file as it doesn't make any sense * Tests. Massive thumbs up for [jbboehr](https://github.com/jbboehr), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/61) * Tweak for the `!important` attributes-fix, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/62) # Changelog since 1.4.0 * Skip `!important` attributes if needed, thx to [barryvdh](https://github.com/barryvdh), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/58) # Changelog since 1.3.0 * Use Xpath instead of regex, thx to [stof](https://github.com/stof), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/52) # Changelog since 1.2.1 * sortOnSpecifity is now working correctly, thx to [lifo101](https://github.com/lifo101), for more information see the [Pull Request](https://github.com/tijsverkoyen/CssToInlineStyles/pull/37) # Changelog since 1.2.0 * introduced a flag to remove media queries before inlining. thx to [Stof](https://github.com/stof). # Changelog since 1.1.0 * require php 5.3 # Changelog since 1.0.6 * made the class compliant with PSR2. # Changelog since 1.0.5 * made the class available through composer # Changelog since 1.0.4 * beter handling of XHTML output, thx to Michele Locati. * preserve original styles. # Changelog since 1.0.3 * fixed some code-styling issues * added support for multiple values # Changelog since 1.0.2 * .class are matched from now on. * fixed issue with #id * new beta-feature: added a way to output valid XHTML (thx to Matt Hornsby) * added setEncoding() to indicate the encoding # Changelog since 1.0.1 * fixed some stuff on specifity # Changelog since 1.0.0 * rewrote the buildXPathQuery-method * fixed some stuff on specifity * added a way to use inline style-blocks php-tijsverkoyen-css-to-inline-styles-2.2.2/LICENSE.md000066400000000000000000000027231356274450300224620ustar00rootroot00000000000000Copyright (c) Tijs Verkoyen. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. php-tijsverkoyen-css-to-inline-styles-2.2.2/README.md000066400000000000000000000041401356274450300223300ustar00rootroot00000000000000# CssToInlineStyles class [![Build Status](https://travis-ci.org/tijsverkoyen/CssToInlineStyles.svg?branch=master)](https://travis-ci.org/tijsverkoyen/CssToInlineStyles) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/tijsverkoyen/CssToInlineStyles/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/tijsverkoyen/CssToInlineStyles/?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/tijsverkoyen/CssToInlineStyles/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/tijsverkoyen/CssToInlineStyles/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/5c0ce94f-de6d-403e-9e0a-431268deb75c/mini.png)](https://insight.sensiolabs.com/projects/5c0ce94f-de6d-403e-9e0a-431268deb75c) ## Installation > CssToInlineStyles is a class that enables you to convert HTML-pages/files into > HTML-pages/files with inline styles. This is very usefull when you're sending > emails. ## About PHP CssToInlineStyles is a class to convert HTML into HTML with inline styles. ## Installation The recommended installation way is through [Composer](https://getcomposer.org). ```bash $ composer require tijsverkoyen/css-to-inline-styles ``` ## Example ```php use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles; // create instance $cssToInlineStyles = new CssToInlineStyles(); $html = file_get_contents(__DIR__ . '/examples/sumo/index.htm'); $css = file_get_contents(__DIR__ . '/examples/sumo/style.css'); // output echo $cssToInlineStyles->convert( $html, $css ); ``` ## Known issues * no support for pseudo selectors * no support for [css-escapes](https://mathiasbynens.be/notes/css-escapes) * UTF-8 charset is not always detected correctly. Make sure you set the charset to UTF-8 using the following meta-tag in the head: ``. _(Note: using `` does NOT work!)_ ## Sites using this class * [Each site based on Fork CMS](http://www.fork-cms.com) * [Print en Bind](http://www.printenbind.nl) * [Tiki Wiki CMS Groupware](http://sourceforge.net/p/tikiwiki/code/49505) (starting in Tiki 13) php-tijsverkoyen-css-to-inline-styles-2.2.2/composer.json000066400000000000000000000015621356274450300236000ustar00rootroot00000000000000{ "name": "tijsverkoyen/css-to-inline-styles", "type": "library", "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "license": "BSD-3-Clause", "authors": [ { "name": "Tijs Verkoyen", "email": "css_to_inline_styles@verkoyen.eu", "role": "Developer" } ], "require": { "php": "^5.5 || ^7.0", "ext-dom": "*", "ext-libxml": "*", "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "autoload": { "psr-4": { "TijsVerkoyen\\CssToInlineStyles\\": "src" } }, "extra": { "branch-alias": { "dev-master": "2.2.x-dev" } } } php-tijsverkoyen-css-to-inline-styles-2.2.2/example/000077500000000000000000000000001356274450300225055ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/example/examples/000077500000000000000000000000001356274450300243235ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/example/examples/sumo/000077500000000000000000000000001356274450300253065ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/example/examples/sumo/index.htm000066400000000000000000000132241356274450300271310ustar00rootroot00000000000000 *|MC:SUBJECT|*
Use this area to offer a short teaser of your email's content. Text here will show in the preview area of some email clients.

Heading 1

Heading 2

Heading 3

Heading 4

Getting started: Customize your template by clicking on the style editor tabs up above. Set your fonts, colors, and styles. After setting your styling is all done you can click here in this area, delete the text, and start adding your own awesome content!

After you enter your content, highlight the text you want to style and select the options you set in the style editor in the "styles" drop down box. Want to get rid of styling on a bit of text, but having trouble doing it? Just use the "remove formatting" button to strip the text of any formatting and reset your style.

Copyright © *|CURRENT_YEAR|* *|LIST:COMPANY|*, All rights reserved.
*|IFNOT:ARCHIVE_PAGE|* *|LIST:DESCRIPTION|*
Our mailing address is:
*|HTML:LIST_ADDRESS_HTML|**|END:IF|*

*|IF:REWARDS|* *|HTML:REWARDS|* *|END:IF|*

php-tijsverkoyen-css-to-inline-styles-2.2.2/example/examples/sumo/style.css000066400000000000000000000204571356274450300271700ustar00rootroot00000000000000/* Client-specific Styles */ #outlook a{padding:0;} /* Force Outlook to provide a "view in browser" button. */ body{width:100% !important;} .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */ body{-webkit-text-size-adjust:none;} /* Prevent Webkit platforms from changing default text sizes. */ /* Reset Styles */ body{margin:0; padding:0;} img{border:0; outline:none; text-decoration:none;} table td{border-collapse:collapse;} #backgroundTable{height:100% !important; margin:0; padding:0; width:100% !important;} /* Template Styles */ /* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: COMMON PAGE ELEMENTS /\/\/\/\/\/\/\/\/\/\ */ /** * @tab Page * @section background color * @tip Set the background color for your email. You may want to choose one that matches your company's branding. * @theme page */ body, #backgroundTable{ /*@editable*/ background-color:#FAFAFA; } /** * @tab Page * @section email border * @tip Set the border for your email. */ #templateContainer{ /*@editable*/ border: 1px solid #DDDDDD; } /** * @tab Page * @section heading 1 * @tip Set the styling for all first-level headings in your emails. These should be the largest of your headings. * @style heading 1 */ h1, .h1{ /*@editable*/ color:#202020; display:block; /*@editable*/ font-family:Arial; /*@editable*/ font-size:34px; /*@editable*/ font-weight:bold; /*@editable*/ line-height:100%; margin-top:0; margin-right:0; margin-bottom:10px; margin-left:0; /*@editable*/ text-align:left; } /** * @tab Page * @section heading 2 * @tip Set the styling for all second-level headings in your emails. * @style heading 2 */ h2, .h2{ /*@editable*/ color:#202020; display:block; /*@editable*/ font-family:Arial; /*@editable*/ font-size:30px; /*@editable*/ font-weight:bold; /*@editable*/ line-height:100%; margin-top:0; margin-right:0; margin-bottom:10px; margin-left:0; /*@editable*/ text-align:left; } /** * @tab Page * @section heading 3 * @tip Set the styling for all third-level headings in your emails. * @style heading 3 */ h3, .h3{ /*@editable*/ color:#202020; display:block; /*@editable*/ font-family:Arial; /*@editable*/ font-size:26px; /*@editable*/ font-weight:bold; /*@editable*/ line-height:100%; margin-top:0; margin-right:0; margin-bottom:10px; margin-left:0; /*@editable*/ text-align:left; } /** * @tab Page * @section heading 4 * @tip Set the styling for all fourth-level headings in your emails. These should be the smallest of your headings. * @style heading 4 */ h4, .h4{ /*@editable*/ color:#202020; display:block; /*@editable*/ font-family:Arial; /*@editable*/ font-size:22px; /*@editable*/ font-weight:bold; /*@editable*/ line-height:100%; margin-top:0; margin-right:0; margin-bottom:10px; margin-left:0; /*@editable*/ text-align:left; } /* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: PREHEADER /\/\/\/\/\/\/\/\/\/\ */ /** * @tab Header * @section preheader style * @tip Set the background color for your email's preheader area. * @theme page */ #templatePreheader{ /*@editable*/ background-color:#FAFAFA; } /** * @tab Header * @section preheader text * @tip Set the styling for your email's preheader text. Choose a size and color that is easy to read. */ .preheaderContent div{ /*@editable*/ color:#505050; /*@editable*/ font-family:Arial; /*@editable*/ font-size:10px; /*@editable*/ line-height:100%; /*@editable*/ text-align:left; } /** * @tab Header * @section preheader link * @tip Set the styling for your email's preheader links. Choose a color that helps them stand out from your text. */ .preheaderContent div a:link, .preheaderContent div a:visited, /* Yahoo! Mail Override */ .preheaderContent div a .yshortcuts /* Yahoo! Mail Override */{ /*@editable*/ color:#336699; /*@editable*/ font-weight:normal; /*@editable*/ text-decoration:underline; } .preheaderContent img{ display:inline; height:auto; margin-bottom:10px; max-width:280px; } /* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: HEADER /\/\/\/\/\/\/\/\/\/\ */ /** * @tab Header * @section header style * @tip Set the background color and border for your email's header area. * @theme header */ #templateHeader{ /*@editable*/ background-color:#FFFFFF; /*@editable*/ border-bottom:0; } /** * @tab Header * @section header text * @tip Set the styling for your email's header text. Choose a size and color that is easy to read. */ .headerContent{ /*@editable*/ color:#202020; /*@editable*/ font-family:Arial; /*@editable*/ font-size:34px; /*@editable*/ font-weight:bold; /*@editable*/ line-height:100%; /*@editable*/ padding:0; /*@editable*/ text-align:center; /*@editable*/ vertical-align:middle; } /** * @tab Header * @section header link * @tip Set the styling for your email's header links. Choose a color that helps them stand out from your text. */ .headerContent a:link, .headerContent a:visited, /* Yahoo! Mail Override */ .headerContent a .yshortcuts /* Yahoo! Mail Override */{ /*@editable*/ color:#336699; /*@editable*/ font-weight:normal; /*@editable*/ text-decoration:underline; } #headerImage{ height:auto; max-width:320px !important; } /* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: MAIN BODY /\/\/\/\/\/\/\/\/\/\ */ /** * @tab Body * @section body style * @tip Set the background color for your email's body area. */ #templateContainer, .bodyContent{ /*@editable*/ background-color:#FFFFFF; } /** * @tab Body * @section body text * @tip Set the styling for your email's main content text. Choose a size and color that is easy to read. * @theme main */ .bodyContent div{ /*@editable*/ color:#505050; /*@editable*/ font-family:Arial; /*@editable*/ font-size:12px; /*@editable*/ line-height:150%; /*@editable*/ text-align:left; } /** * @tab Body * @section body link * @tip Set the styling for your email's main content links. Choose a color that helps them stand out from your text. */ .bodyContent div a:link, .bodyContent div a:visited, /* Yahoo! Mail Override */ .bodyContent div a .yshortcuts /* Yahoo! Mail Override */{ /*@editable*/ color:#336699; /*@editable*/ font-weight:normal; /*@editable*/ text-decoration:underline; } .bodyContent img{ display:inline; height:auto; margin-bottom:10px; max-width:280px; } /* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: FOOTER /\/\/\/\/\/\/\/\/\/\ */ /** * @tab Footer * @section footer style * @tip Set the background color and top border for your email's footer area. * @theme footer */ #templateFooter{ /*@editable*/ background-color:#FFFFFF; /*@editable*/ border-top:0; } /** * @tab Footer * @section footer text * @tip Set the styling for your email's footer text. Choose a size and color that is easy to read. * @theme footer */ .footerContent div{ /*@editable*/ color:#707070; /*@editable*/ font-family:Arial; /*@editable*/ font-size:11px; /*@editable*/ line-height:150%; /*@editable*/ text-align:left; } /** * @tab Footer * @section footer link * @tip Set the styling for your email's footer links. Choose a color that helps them stand out from your text. */ .footerContent div a:link, .footerContent div a:visited, /* Yahoo! Mail Override */ .footerContent div a .yshortcuts /* Yahoo! Mail Override */{ /*@editable*/ color:#336699; /*@editable*/ font-weight:normal; /*@editable*/ text-decoration:underline; } .footerContent img{ display:inline; } /** * @tab Footer * @section social bar style * @tip Set the background color and border for your email's footer social bar. * @theme footer */ #social{ /*@editable*/ background-color:#FAFAFA; /*@editable*/ border:0; } /** * @tab Footer * @section social bar style * @tip Set the background color and border for your email's footer social bar. */ #social div{ /*@editable*/ text-align:left; } /** * @tab Footer * @section utility bar style * @tip Set the background color and border for your email's footer utility bar. * @theme footer */ #utility{ /*@editable*/ background-color:#FFFFFF; /*@editable*/ border:0; } /** * @tab Footer * @section utility bar style * @tip Set the background color and border for your email's footer utility bar. */ #utility div{ /*@editable*/ text-align:left; } #monkeyRewards img{ display:inline; height:auto; max-width:280px; } php-tijsverkoyen-css-to-inline-styles-2.2.2/example/index.php000066400000000000000000000005701356274450300243270ustar00rootroot00000000000000convert( $html, $css ); php-tijsverkoyen-css-to-inline-styles-2.2.2/phpunit.xml.dist000066400000000000000000000010771356274450300242320ustar00rootroot00000000000000 ./tests/ php-tijsverkoyen-css-to-inline-styles-2.2.2/src/000077500000000000000000000000001356274450300216415ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/000077500000000000000000000000001356274450300223715ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Processor.php000066400000000000000000000035171356274450300250670ustar00rootroot00000000000000doCleanup($css); $rulesProcessor = new RuleProcessor(); $rules = $rulesProcessor->splitIntoSeparateRules($css); return $rulesProcessor->convertArrayToObjects($rules, $existingRules); } /** * Get the CSS from the style-tags in the given HTML-string * * @param string $html * * @return string */ public function getCssFromStyleTags($html) { $css = ''; $matches = array(); $htmlNoComments = preg_replace('||s', '', $html); preg_match_all('|(.*)|isU', $htmlNoComments, $matches); if (!empty($matches[1])) { foreach ($matches[1] as $match) { $css .= trim($match) . "\n"; } } return $css; } /** * @param string $css * * @return string */ private function doCleanup($css) { // remove charset $css = preg_replace('/@charset "[^"]++";/', '', $css); // remove media queries $css = preg_replace('/@media [^{]*+{([^{}]++|{[^{}]*+})*+}/', '', $css); $css = str_replace(array("\r", "\n"), '', $css); $css = str_replace(array("\t"), ' ', $css); $css = str_replace('"', '\'', $css); $css = preg_replace('|/\*.*?\*/|', '', $css); $css = preg_replace('/\s\s++/', ' ', $css); $css = trim($css); return $css; } } php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Property/000077500000000000000000000000001356274450300242155ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Property/Processor.php000066400000000000000000000061771356274450300267200ustar00rootroot00000000000000cleanup($propertiesString); $properties = (array) explode(';', $propertiesString); $keysToRemove = array(); $numberOfProperties = count($properties); for ($i = 0; $i < $numberOfProperties; $i++) { $properties[$i] = trim($properties[$i]); // if the new property begins with base64 it is part of the current property if (isset($properties[$i + 1]) && strpos(trim($properties[$i + 1]), 'base64,') === 0) { $properties[$i] .= ';' . trim($properties[$i + 1]); $keysToRemove[] = $i + 1; } } if (!empty($keysToRemove)) { foreach ($keysToRemove as $key) { unset($properties[$key]); } } return array_values($properties); } /** * @param string $string * * @return string */ private function cleanup($string) { $string = str_replace(array("\r", "\n"), '', $string); $string = str_replace(array("\t"), ' ', $string); $string = str_replace('"', '\'', $string); $string = preg_replace('|/\*.*?\*/|', '', $string); $string = preg_replace('/\s\s+/', ' ', $string); $string = trim($string); $string = rtrim($string, ';'); return $string; } /** * Converts a property-string into an object * * @param string $property * * @return Property|null */ public function convertToObject($property, Specificity $specificity = null) { if (strpos($property, ':') === false) { return null; } list($name, $value) = explode(':', $property, 2); $name = trim($name); $value = trim($value); if ($value === '') { return null; } return new Property($name, $value, $specificity); } /** * Converts an array of property-strings into objects * * @param string[] $properties * * @return Property[] */ public function convertArrayToObjects(array $properties, Specificity $specificity = null) { $objects = array(); foreach ($properties as $property) { $object = $this->convertToObject($property, $specificity); if ($object === null) { continue; } $objects[] = $object; } return $objects; } /** * Build the property-string for multiple properties * * @param Property[] $properties * * @return string */ public function buildPropertiesString(array $properties) { $chunks = array(); foreach ($properties as $property) { $chunks[] = $property->toString(); } return implode(' ', $chunks); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Property/Property.php000066400000000000000000000030631356274450300265540ustar00rootroot00000000000000name = $name; $this->value = $value; $this->originalSpecificity = $specificity; } /** * Get name * * @return string */ public function getName() { return $this->name; } /** * Get value * * @return string */ public function getValue() { return $this->value; } /** * Get originalSpecificity * * @return Specificity */ public function getOriginalSpecificity() { return $this->originalSpecificity; } /** * Is this property important? * * @return bool */ public function isImportant() { return (stripos($this->value, '!important') !== false); } /** * Get the textual representation of the property * * @return string */ public function toString() { return sprintf( '%1$s: %2$s;', $this->name, $this->value ); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Rule/000077500000000000000000000000001356274450300233005ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Rule/Processor.php000066400000000000000000000117321356274450300257740ustar00rootroot00000000000000cleanup($rulesString); return (array) explode('}', $rulesString); } /** * @param string $string * * @return string */ private function cleanup($string) { $string = str_replace(array("\r", "\n"), '', $string); $string = str_replace(array("\t"), ' ', $string); $string = str_replace('"', '\'', $string); $string = preg_replace('|/\*.*?\*/|', '', $string); $string = preg_replace('/\s\s+/', ' ', $string); $string = trim($string); $string = rtrim($string, '}'); return $string; } /** * Converts a rule-string into an object * * @param string $rule * @param int $originalOrder * * @return Rule[] */ public function convertToObjects($rule, $originalOrder) { $rule = $this->cleanup($rule); $chunks = explode('{', $rule); if (!isset($chunks[1])) { return array(); } $propertiesProcessor = new PropertyProcessor(); $rules = array(); $selectors = (array) explode(',', trim($chunks[0])); $properties = $propertiesProcessor->splitIntoSeparateProperties($chunks[1]); foreach ($selectors as $selector) { $selector = trim($selector); $specificity = $this->calculateSpecificityBasedOnASelector($selector); $rules[] = new Rule( $selector, $propertiesProcessor->convertArrayToObjects($properties, $specificity), $specificity, $originalOrder ); } return $rules; } /** * Calculates the specificity based on a CSS Selector string, * Based on the patterns from premailer/css_parser by Alex Dunae * * @see https://github.com/premailer/css_parser/blob/master/lib/css_parser/regexps.rb * * @param string $selector * * @return Specificity */ public function calculateSpecificityBasedOnASelector($selector) { $idSelectorsPattern = " \#"; $classAttributesPseudoClassesSelectorsPattern = " (\.[\w]+) # classes | \[(\w+) # attributes | (\:( # pseudo classes link|visited|active |hover|focus |lang |target |enabled|disabled|checked|indeterminate |root |nth-child|nth-last-child|nth-of-type|nth-last-of-type |first-child|last-child|first-of-type|last-of-type |only-child|only-of-type |empty|contains ))"; $typePseudoElementsSelectorPattern = " ((^|[\s\+\>\~]+)[\w]+ # elements | \:{1,2}( # pseudo-elements after|before |first-letter|first-line |selection ) )"; return new Specificity( preg_match_all("/{$idSelectorsPattern}/ix", $selector, $matches), preg_match_all("/{$classAttributesPseudoClassesSelectorsPattern}/ix", $selector, $matches), preg_match_all("/{$typePseudoElementsSelectorPattern}/ix", $selector, $matches) ); } /** * @param string[] $rules * @param Rule[] $objects * * @return Rule[] */ public function convertArrayToObjects(array $rules, array $objects = array()) { $order = 1; foreach ($rules as $rule) { $objects = array_merge($objects, $this->convertToObjects($rule, $order)); $order++; } return $objects; } /** * Sorts an array on the specificity element in an ascending way * Lower specificity will be sorted to the beginning of the array * * @param Rule $e1 The first element. * @param Rule $e2 The second element. * * @return int */ public static function sortOnSpecificity(Rule $e1, Rule $e2) { $e1Specificity = $e1->getSpecificity(); $value = $e1Specificity->compareTo($e2->getSpecificity()); // if the specificity is the same, use the order in which the element appeared if ($value === 0) { $value = $e1->getOrder() - $e2->getOrder(); } return $value; } } php-tijsverkoyen-css-to-inline-styles-2.2.2/src/Css/Rule/Rule.php000066400000000000000000000027111356274450300247210ustar00rootroot00000000000000selector = $selector; $this->properties = $properties; $this->specificity = $specificity; $this->order = $order; } /** * Get selector * * @return string */ public function getSelector() { return $this->selector; } /** * Get properties * * @return Property[] */ public function getProperties() { return $this->properties; } /** * Get specificity * * @return Specificity */ public function getSpecificity() { return $this->specificity; } /** * Get order * * @return int */ public function getOrder() { return $this->order; } } php-tijsverkoyen-css-to-inline-styles-2.2.2/src/CssToInlineStyles.php000066400000000000000000000162451356274450300257600ustar00rootroot00000000000000cssConverter = new CssSelectorConverter(); } } /** * Will inline the $css into the given $html * * Remark: if the html contains

foo

EOF ) ); } public function testStyleTagsWithAttributeInHtml() { $expected = 'p { color: #F00; }' . "\n"; $this->assertEquals( $expected, $this->processor->getCssFromStyleTags( <<

foo

HTML ) ); } public function testMultipleStyleTagsInHtml() { $expected = 'p { color: #F00; }' . "\n" . 'p { color: #0F0; }' . "\n"; $this->assertEquals( $expected, $this->processor->getCssFromStyleTags( <<

foo

EOF ) ); } public function testWeirdTagsInHtml() { $expected = 'p { color: #F00; }' . "\n"; $this->assertEquals( $expected, $this->processor->getCssFromStyleTags( <<

foo

HTML ) ); } public function testStyleTagsInCommentInHtml() { $expected = 'p { color: #F00; }' . "\n"; $this->assertEquals( $expected, $this->processor->getCssFromStyleTags( <<

foo

EOF ) ); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Property/000077500000000000000000000000001356274450300245705ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Property/ProcessorTest.php000066400000000000000000000050111356274450300301150ustar00rootroot00000000000000processor = new Processor(); } public function tearDown() { $this->processor = null; } public function testMostBasicProperty() { $propertiesString = 'padding: 0;'; $this->assertEquals( array( 'padding: 0', ), $this->processor->splitIntoSeparateProperties($propertiesString) ); } public function testInvalidProperty() { $this->assertNull( $this->processor->convertToObject('foo:') ); } public function testBase64ContainsSemiColon() { $propertiesString = <<assertEquals( array( 'background: url(data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7) no-repeat left center', 'padding: 5px 0 5px 25px', ), $this->processor->splitIntoSeparateProperties($propertiesString) ); } public function testBuildingPropertiesString() { $properties = array( new Property('padding', '5px'), new Property('display', 'block'), ); $this->assertEquals( 'padding: 5px; display: block;', $this->processor->buildPropertiesString($properties) ); } public function testFaultyProperties() { $this->assertNull($this->processor->convertToObject('foo')); $this->assertNull($this->processor->convertToObject('foo:')); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Property/PropertyTest.php000066400000000000000000000016321356274450300277670ustar00rootroot00000000000000assertEquals('padding', $property->getName()); $this->assertEquals('5px', $property->getValue()); } public function testSimplePropertyToString() { $property = new Property('padding', '5px'); $this->assertEquals( 'padding: 5px;', $property->toString() ); } public function testIfImportantIsDetected() { $property = new Property('padding', '5px !important'); $this->assertTrue($property->isImportant()); $property = new Property('padding', '5px'); $this->assertFalse($property->isImportant()); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Rule/000077500000000000000000000000001356274450300236535ustar00rootroot00000000000000php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Rule/ProcessorTest.php000066400000000000000000000054371356274450300272140ustar00rootroot00000000000000processor = new Processor(); } public function tearDown() { $this->processor = null; } public function testMostBasicRule() { $css = <<processor->convertToObjects($css, 1); $this->assertCount(1, $rules); $this->assertInstanceOf('TijsVerkoyen\CssToInlineStyles\Css\Rule\Rule', $rules[0]); $this->assertEquals('a', $rules[0]->getSelector()); $this->assertCount(2, $rules[0]->getProperties()); $this->assertEquals('padding', $rules[0]->getProperties()[0]->getName()); $this->assertEquals('5px', $rules[0]->getProperties()[0]->getValue()); $this->assertEquals('display', $rules[0]->getProperties()[1]->getName()); $this->assertEquals('block', $rules[0]->getProperties()[1]->getValue()); $this->assertEquals(1, $rules[0]->getOrder()); } public function testMaintainOrderOfProperties() { $css = <<processor->convertToObjects($css, 1); $this->assertCount(1, $rules); $this->assertInstanceOf('TijsVerkoyen\CssToInlineStyles\Css\Rule\Rule', $rules[0]); $this->assertEquals('div', $rules[0]->getSelector()); $this->assertCount(2, $rules[0]->getProperties()); $this->assertEquals('width', $rules[0]->getProperties()[0]->getName()); $this->assertEquals('200px', $rules[0]->getProperties()[0]->getValue()); $this->assertEquals('_width', $rules[0]->getProperties()[1]->getName()); $this->assertEquals('211px', $rules[0]->getProperties()[1]->getValue()); $this->assertEquals(1, $rules[0]->getOrder()); } public function testSingleIdSelector() { $this->assertEquals( new Specificity(1, 0, 0), $this->processor->calculateSpecificityBasedOnASelector('#foo') ); } public function testSingleClassSelector() { $this->assertEquals( new Specificity(0, 1, 0), $this->processor->calculateSpecificityBasedOnASelector('.foo') ); } public function testSingleElementSelector() { $this->assertEquals( new Specificity(0, 0, 1), $this->processor->calculateSpecificityBasedOnASelector('a') ); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/Rule/RuleTest.php000066400000000000000000000014611356274450300261350ustar00rootroot00000000000000assertEquals('a', $rule->getSelector()); $this->assertEquals(array($property), $rule->getProperties()); $this->assertEquals($specificity, $rule->getSpecificity()); $this->assertEquals(1, $rule->getOrder()); } } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/Css/test.css000066400000000000000000000500661356274450300244440ustar00rootroot00000000000000#outlook a { padding: 0; } body { width: 100% !important; min-width: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; margin: 0; padding: 0; } .ExternalClass { width: 100%; } .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; } #backgroundTable { margin: 0; padding: 0; width: 100% !important; line-height: 100% !important; } img { outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; width: auto; max-width: 100%; float: left; clear: both; display: block; } center { width: 100%; min-width: 580px; } a img { border: none; } p { margin: 0 0 0 10px; } table { border-spacing: 0; border-collapse: collapse; } td { -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; border-collapse: collapse !important; } table, tr, td { padding: 0; vertical-align: top; text-align: left; } hr { color: #d9d9d9; background-color: #d9d9d9; height: 1px; border: none; } table.body { height: 100%; width: 100%; } table.container { width: 580px; margin: 0 auto; text-align: inherit; } table.row { padding: 0; width: 100%; position: relative; } table.container table.row { display: block; } td.wrapper { padding: 10px 20px 0 0; position: relative; } table.columns, table.column { margin: 0 auto; } table.columns td, table.column td { padding: 0 0 10px; } table.columns td.sub-columns, table.column td.sub-columns, table.columns td.sub-column, table.column td.sub-column { padding-right: 10px; } td.sub-column, td.sub-columns { min-width: 0; } table.row td.last, table.container td.last { padding-right: 0; } table.one { width: 30px; } table.two { width: 80px; } table.three { width: 130px; } table.four { width: 180px; } table.five { width: 230px; } table.six { width: 280px; } table.seven { width: 330px; } table.eight { width: 380px; } table.nine { width: 430px; } table.ten { width: 480px; } table.eleven { width: 530px; } table.twelve { width: 580px; } table.one center { min-width: 30px; } table.two center { min-width: 80px; } table.three center { min-width: 130px; } table.four center { min-width: 180px; } table.five center { min-width: 230px; } table.six center { min-width: 280px; } table.seven center { min-width: 330px; } table.eight center { min-width: 380px; } table.nine center { min-width: 430px; } table.ten center { min-width: 480px; } table.eleven center { min-width: 530px; } table.twelve center { min-width: 580px; } table.one .panel center { min-width: 10px; } table.two .panel center { min-width: 60px; } table.three .panel center { min-width: 110px; } table.four .panel center { min-width: 160px; } table.five .panel center { min-width: 210px; } table.six .panel center { min-width: 260px; } table.seven .panel center { min-width: 310px; } table.eight .panel center { min-width: 360px; } table.nine .panel center { min-width: 410px; } table.ten .panel center { min-width: 460px; } table.eleven .panel center { min-width: 510px; } table.twelve .panel center { min-width: 560px; } .body .columns td.one, .body .column td.one { width: 8.333333%; } .body .columns td.two, .body .column td.two { width: 16.666666%; } .body .columns td.three, .body .column td.three { width: 25%; } .body .columns td.four, .body .column td.four { width: 33.333333%; } .body .columns td.five, .body .column td.five { width: 41.666666%; } .body .columns td.six, .body .column td.six { width: 50%; } .body .columns td.seven, .body .column td.seven { width: 58.333333%; } .body .columns td.eight, .body .column td.eight { width: 66.666666%; } .body .columns td.nine, .body .column td.nine { width: 75%; } .body .columns td.ten, .body .column td.ten { width: 83.333333%; } .body .columns td.eleven, .body .column td.eleven { width: 91.666666%; } .body .columns td.twelve, .body .column td.twelve { width: 100%; } td.offset-by-one { padding-left: 50px; } td.offset-by-two { padding-left: 100px; } td.offset-by-three { padding-left: 150px; } td.offset-by-four { padding-left: 200px; } td.offset-by-five { padding-left: 250px; } td.offset-by-six { padding-left: 300px; } td.offset-by-seven { padding-left: 350px; } td.offset-by-eight { padding-left: 400px; } td.offset-by-nine { padding-left: 450px; } td.offset-by-ten { padding-left: 500px; } td.offset-by-eleven { padding-left: 550px; } td.expander { visibility: hidden; width: 0; padding: 0 !important; } table.columns .text-pad, table.column .text-pad { padding-left: 10px; padding-right: 10px; } table.columns .left-text-pad, table.columns .text-pad-left, table.column .left-text-pad, table.column .text-pad-left { padding-left: 10px; } table.columns .right-text-pad, table.columns .text-pad-right, table.column .right-text-pad, table.column .text-pad-right { padding-right: 10px; } .block-grid { width: 100%; max-width: 580px; } .block-grid td { display: inline-block; padding: 10px; } .two-up td { width: 270px; } .three-up td { width: 173px; } .four-up td { width: 125px; } .five-up td { width: 96px; } .six-up td { width: 76px; } .seven-up td { width: 62px; } .eight-up td { width: 52px; } table.center, td.center { text-align: center; } h1.center, h2.center, h3.center, h4.center, h5.center, h6.center { text-align: center; } span.center { display: block; width: 100%; text-align: center; } img.center { margin: 0 auto; float: none; } .show-for-small, .hide-for-desktop { display: none; } body, table.body, h1, h2, h3, h4, h5, h6, p, td { color: #222222; font-family: 'Helvetica', 'Arial', sans-serif; font-weight: normal; padding: 0; margin: 0; text-align: left; line-height: 1.3; } h1, h2, h3, h4, h5, h6 { word-break: normal; } h1 { font-size: 40px; } h2 { font-size: 36px; } h3 { font-size: 32px; } h4 { font-size: 28px; } h5 { font-size: 24px; } h6 { font-size: 20px; } body, table.body, p, td { font-size: 14px; line-height: 19px; } p.lead, p.lede, p.leed { font-size: 18px; line-height: 21px; } p { margin-bottom: 10px; } small { font-size: 10px; } a { color: #2ba6cb; text-decoration: none; } a:hover { color: #2795b6 !important; } a:active { color: #2795b6 !important; } a:visited { color: #2ba6cb !important; } h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { color: #2ba6cb; } h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active { color: #2ba6cb !important; } h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited { color: #2ba6cb !important; } .panel { background: #f2f2f2; border: 1px solid #d9d9d9; padding: 10px !important; } .sub-grid table { width: 100%; } .sub-grid td.sub-columns { padding-bottom: 0; } table.button, table.tiny-button, table.small-button, table.medium-button, table.large-button { width: 100%; overflow: hidden; } table.button td, table.tiny-button td, table.small-button td, table.medium-button td, table.large-button td { display: block; width: auto !important; text-align: center; background: #2ba6cb; border: 1px solid #2284a1; color: #ffffff; padding: 8px 0; } table.tiny-button td { padding: 5px 0 4px; } table.small-button td { padding: 8px 0 7px; } table.medium-button td { padding: 12px 0 10px; } table.large-button td { padding: 21px 0 18px; } table.button td a, table.tiny-button td a, table.small-button td a, table.medium-button td a, table.large-button td a { font-weight: bold; text-decoration: none; font-family: Helvetica, Arial, sans-serif; color: #ffffff; font-size: 16px; } table.tiny-button td a { font-size: 12px; font-weight: normal; } table.small-button td a { font-size: 16px; } table.medium-button td a { font-size: 20px; } table.large-button td a { font-size: 24px; } table.button:hover td, table.button:visited td, table.button:active td { background: #2795b6 !important; } table.button:hover td a, table.button:visited td a, table.button:active td a { color: #fff !important; } table.button:hover td, table.tiny-button:hover td, table.small-button:hover td, table.medium-button:hover td, table.large-button:hover td { background: #2795b6 !important; } table.button:hover td a, table.button:active td a, table.button td a:visited, table.tiny-button:hover td a, table.tiny-button:active td a, table.tiny-button td a:visited, table.small-button:hover td a, table.small-button:active td a, table.small-button td a:visited, table.medium-button:hover td a, table.medium-button:active td a, table.medium-button td a:visited, table.large-button:hover td a, table.large-button:active td a, table.large-button td a:visited { color: #ffffff !important; } table.secondary td { background: #e9e9e9; border-color: #d0d0d0; color: #555; } table.secondary td a { color: #555; } table.secondary:hover td { background: #d0d0d0 !important; color: #555; } table.secondary:hover td a, table.secondary td a:visited, table.secondary:active td a { color: #555 !important; } table.success td { background: #5da423; border-color: #457a1a; } table.success:hover td { background: #457a1a !important; } table.alert td { background: #c60f13; border-color: #970b0e; } table.alert:hover td { background: #970b0e !important; } table.radius td { -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } table.round td { -webkit-border-radius: 500px; -moz-border-radius: 500px; border-radius: 500px; } body.outlook p { display: inline !important; } @media only screen and (max-width: 600px) { table[class='body'] img { width: auto !important; height: auto !important; } table[class='body'] center { min-width: 0 !important; } table[class='body'] .container { width: 95% !important; } table[class='body'] .row { width: 100% !important; display: block !important; } table[class='body'] .wrapper { display: block !important; padding-right: 0 !important; } table[class='body'] .columns, table[class='body'] .column { table-layout: fixed !important; float: none !important; width: 100% !important; padding-right: 0 !important; padding-left: 0 !important; display: block !important; } table[class='body'] .wrapper.first .columns, table[class='body'] .wrapper.first .column { display: table !important; } table[class='body'] table.columns td, table[class='body'] table.column td { width: 100% !important; } table[class='body'] .columns td.one, table[class='body'] .column td.one { width: 8.333333% !important; } table[class='body'] .columns td.two, table[class='body'] .column td.two { width: 16.666666% !important; } table[class='body'] .columns td.three, table[class='body'] .column td.three { width: 25% !important; } table[class='body'] .columns td.four, table[class='body'] .column td.four { width: 33.333333% !important; } table[class='body'] .columns td.five, table[class='body'] .column td.five { width: 41.666666% !important; } table[class='body'] .columns td.six, table[class='body'] .column td.six { width: 50% !important; } table[class='body'] .columns td.seven, table[class='body'] .column td.seven { width: 58.333333% !important; } table[class='body'] .columns td.eight, table[class='body'] .column td.eight { width: 66.666666% !important; } table[class='body'] .columns td.nine, table[class='body'] .column td.nine { width: 75% !important; } table[class='body'] .columns td.ten, table[class='body'] .column td.ten { width: 83.333333% !important; } table[class='body'] .columns td.eleven, table[class='body'] .column td.eleven { width: 91.666666% !important; } table[class='body'] .columns td.twelve, table[class='body'] .column td.twelve { width: 100% !important; } table[class='body'] td.offset-by-one, table[class='body'] td.offset-by-two, table[class='body'] td.offset-by-three, table[class='body'] td.offset-by-four, table[class='body'] td.offset-by-five, table[class='body'] td.offset-by-six, table[class='body'] td.offset-by-seven, table[class='body'] td.offset-by-eight, table[class='body'] td.offset-by-nine, table[class='body'] td.offset-by-ten, table[class='body'] td.offset-by-eleven { padding-left: 0 !important; } table[class='body'] table.columns td.expander { width: 1px !important; } table[class='body'] .right-text-pad, table[class='body'] .text-pad-right { padding-left: 10px !important; } table[class='body'] .left-text-pad, table[class='body'] .text-pad-left { padding-right: 10px !important; } table[class='body'] .hide-for-small, table[class='body'] .show-for-desktop { display: none !important; } table[class='body'] .show-for-small, table[class='body'] .hide-for-desktop { display: inherit !important; } } body, table.body, h1, h2, h3, h4, h5, h6, p, td { color: #474e5d; } td.wrapper { padding-top: 0; } div.im { color: inherit !important; } .text-right { text-align: right; } .pull-right { float: right; } table.columns .spacer-inner-vertical-xs, table.column .spacer-inner-vertical-xs { padding-top: 10px; padding-bottom: 10px; } table.columns .spacer-inner-horizontal, table.column .spacer-inner-horizontal { padding-left: 20px; padding-right: 20px; } table.columns .spacer-inner-xs, table.column .spacer-inner-xs { padding: 10px; } table.columns .spacer-inner-left-xs, table.column .spacer-inner-left-xs { padding-left: 10px; } table.columns .spacer-inner-left-lg, table.column .spacer-inner-left-lg { padding-left: 30px; } table.columns .spacer-inner-right-lg, table.column .spacer-inner-right-lg { padding-right: 30px; } table.columns .spacer-inner-top, table.column .spacer-inner-top { padding-top: 20px; } table.columns .spacer-inner-top-xs, table.column .spacer-inner-top-xs { padding-top: 10px; } table.columns .spacer-inner-top-ty, table.column .spacer-inner-top-ty { padding-top: 5px; } table.columns .spacer-inner-bottom, table.column .spacer-inner-bottom { padding-bottom: 20px; } table.columns .spacer-inner-bottom-xs, table.column .spacer-inner-bottom-xs { padding-bottom: 10px; } table.columns .spacer-inner-bottom-ty, table.column .spacer-inner-bottom-ty { padding-bottom: 5px; } .rounded { border-radius: 4px; } .rounded-bottom { border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } .shadow-box-soft { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.09); } .spacer-big { width: 100% !important; } .spacer-big td { height: 26px !important; width: 100% !important; } .vertical-align-middle { vertical-align: middle; } .no-padding { padding: 0 !important; } .no-margin { margin: 0 !important; } h1, .h1 { font-size: 42px; } h2, .h2 { font-size: 37px; } h3, .h3 { font-size: 26px; } h4, .h4 { font-size: 23px; } h5, .h5, h6, .h6 { font-size: 16px; } p { margin: 0; } .text-mini, .text-mini p { font-size: 12px; } .text-small { font-size: 14px; } .text-normal { font-size: 16px; } .bold { font-weight: bold; } .italic { font-style: italic; } .normal { font-weight: normal; } hr.soften { background-image: -webkit-linear-gradient(left, transparent, rgba(0, 0, 0, 0.1), transparent); background-image: -moz-linear-gradient(left, transparent, rgba(0, 0, 0, 0.1), transparent); background-image: -ms-linear-gradient(left, transparent, rgba(0, 0, 0, 0.1), transparent); background-image: -o-linear-gradient(left, transparent, rgba(0, 0, 0, 0.1), transparent); background-image: linear-gradient(left, transparent, rgba(0, 0, 0, 0.1), transparent); border: 0; height: 1px; margin: 25px 0; } .organization-name { color: #fdfdfd !important; color: #fdfdfd; font-size: 16px; } .button-default { background-color: #35CF5C !important; border-radius: 4px; } .button-default a { color: #fdfdfd !important; display: block; font-size: 16px; } .comment-metas { font-size: 11px; } .right { text-align: right; } img.right { float: right; } table.button-default td { border-top: none; border-left: none; border-right: none; border-bottom: 4px solid; border-radius: 4px; } table.button-no-border td { border: none !important; } img.inline { float: none; display: inline; } center > p { text-align: center; } .logo { display: inline; float: none; max-width: 100px; } .avatar { display: inline; float: none; max-width: 59px; } .background-color-dark { background-color: #474e5d; } .background-color-light { background-color: #fdfdfd; } .background-color-grey-light { background-color: #ebebed; } .background-color-light-accent { background-color: #e8e6de; } .background-color-neutral { background-color: #f2f2f2; } .text-color-danger { color: #a94442; } .text-color-dark-beige { color: #9b9992 } .text-color-dark-gray { color: #9b9b9b; } .text-color-light, .text-color-light h1, .text-color-light p { color: #fdfdfd; } .greeting-text { font-size: 16px; line-height: 1.3; } .content-background { background-color: #ffffff; } table.columns .text-pad, table.column .text-pad { padding-left: 20px; padding-right: 20px; } .panel { padding: 20px !important; } table.one .panel center, table.one .text-pad center { min-width: 10px; } table.two .panel center, table.two .text-pad center { min-width: 40px; } table.three .panel center, table.three .text-pad center { min-width: 90px; } table.four .panel center, table.four .text-pad center { min-width: 140px; } table.five .panel center, table.five .text-pad center { min-width: 190px; } table.six .panel center, table.six .text-pad center { min-width: 240px; } table.seven .panel center, table.seven .text-pad center { min-width: 290px; } table.eight .panel center, table.eight .text-pad center { min-width: 340px; } table.nine .panel center, table.nine .text-pad center { min-width: 390px; } table.ten .panel center, table.ten .text-pad center { min-width: 440px; } table.eleven .panel center, table.eleven .text-pad center { min-width: 490px; } table.twelve .panel center, table.twelve .text-pad center { min-width: 540px; } img { padding: 0 !important; margin: 0 !important; } a, a:visited { color: #5ab4c5; } a:hover, a:active { color: #3e9daf !important; color: #3e9daf; } h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited { color: #5ab4c5; } h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active { color: #3e9daf !important; color: #3e9daf; } table.button-default td { background: #5ed97d !important; border-color: #35CF5C !important; background: #5ed97d; border-color: #35CF5C; } table.button-default:hover td { background: #5ed97d !important; background: #5ed97d; } table.button-default td a { color: #ffffff !important; color: #ffffff; } table.button-default { background: #35CF5C !important; background: #35CF5C; } .heading-container { margin-bottom: 25px !important; } .heading-centred-bold h4 { text-align: center; font-weight: bold } .themed-content h5, .themed-content p strong { color: #5ed97d !important; color: #5ed97d; } php-tijsverkoyen-css-to-inline-styles-2.2.2/tests/CssToInlineStylesTest.php000066400000000000000000000156511356274450300271730ustar00rootroot00000000000000cssToInlineStyles = new CssToInlineStyles(); } public function tearDown() { $this->cssToInlineStyles = null; } public function testNoXMLHeaderPresent() { $this->assertNotContains( 'cssToInlineStyles->convert( '

foo

', '' ) ); } public function testApplyNoStylesOnElement() { $document = new \DOMDocument(); $element = $document->createElement('a', 'foo'); $inlineElement = $this->cssToInlineStyles->inlineCssOnElement( $element, array() ); $document->appendChild($inlineElement); $this->assertEquals('foo', trim($document->saveHTML())); } public function testApplyBasicStylesOnElement() { $document = new \DOMDocument(); $element = $document->createElement('a', 'foo'); $inlineElement = $this->cssToInlineStyles->inlineCssOnElement( $element, array( new Property('padding', '5px'), ) ); $document->appendChild($inlineElement); $this->assertEquals('foo', trim($document->saveHTML())); } public function testApplyBasicStylesOnElementWithInlineStyles() { $document = new \DOMDocument(); $element = $document->createElement('a', 'foo'); $element->setAttribute('style', 'color: green; border: 1px;'); $inlineElement = $this->cssToInlineStyles->inlineCssOnElement( $element, array( new Property('border-bottom', '5px'), new Property('border', '2px'), ) ); $document->appendChild($inlineElement); $this->assertEquals( 'foo', trim($document->saveHTML()) ); } public function testBasicRealHTMLExample() { $html = '

foo

'; $css = 'p { color: red; }'; $expected = <<

foo

EOF; $this->assertEquals($expected, $this->cssToInlineStyles->convert($html, $css)); } public function testSimpleElementSelector() { $html = '
'; $css = 'div { display: none; }'; $expected = '
'; $this->assertCorrectConversion($expected, $html, $css); } public function testSimpleCssSelector() { $html = 'nodeContent'; $css = '.test-class { background-color: #aaa; text-decoration: none; }'; $expected = 'nodeContent'; $this->assertCorrectConversion($expected, $html, $css); } public function testSimpleIdSelector() { $html = '
'; $css = '#div1 { border: 1px solid red; }'; $expected = '
'; $this->assertCorrectConversion($expected, $html, $css); } public function testInlineStylesBlock() { $html = << EOF; $expected = ''; $this->assertCorrectConversion($expected, $html); } public function testSpecificity() { $html = << EOF; $css = << EOF; $this->assertCorrectConversion($expected, $html, $css); } public function testEqualSpecificity() { $html = '
'; $css = ' .one { display: inline; } a > strong {} a {} a {} a {} a {} a {} a {}a {} img { display: block; }'; $expected = '
'; $this->assertCorrectConversion($expected, $html, $css); } public function testInvalidSelector() { $html = "

"; $css = ' p&@*$%& { display: inline; }'; $expected = $html; $this->assertCorrectConversion($expected, $html, $css); } public function testHtmlEncoding() { $text = 'Žluťoučký kůň pije pivo nebo jak to je dál'; $expected = $text; $this->assertEquals($expected, trim(strip_tags($this->cssToInlineStyles->convert($text)))); } public function testSpecialCharacters() { $text = '1 < 2'; $expected = $text; $this->assertEquals($expected, trim(strip_tags($this->cssToInlineStyles->convert($text)))); } public function testSpecialCharactersExplicit() { $text = '&lt;script&>'; $expected = $text; $this->assertEquals($expected, trim(strip_tags($this->cssToInlineStyles->convert($text)))); } public function testSelfClosingTags() { $html = '
'; $css = ''; $expected = $html; $this->assertCorrectConversion($expected, $html, $css); } private function assertCorrectConversion($expected, $html, $css = null) { $this->assertEquals( $expected, $this->getBodyContent( $this->cssToInlineStyles->convert($html, $css) ) ); } private function getBodyContent($html) { $matches = array(); preg_match('|(.*)|ims', $html, $matches); if (!isset($matches[1])) { return null; } return trim($matches[1]); } }