Changeset 62827 in spip-zone for _plugins_/facteur


Ignore:
Timestamp:
Jun 21, 2012, 3:06:50 PM (7 years ago)
Author:
cedric@…
Message:

Le reglage configurable "Transformer les styles contenus entre <head> </head> en des styles en ligne" n'a pas de sens en tant que filtre systematique applique a tous les mails :

  • il casse les mails faits mains sur mesure (comme le wrapper html des emails texte du plugin) car incapable de gerer les @media
  • il peut etre utile sur certains mails html simples
  • il est a utiliser au cas par cas, et c'est le webmestre qui code son mail html qui peut le savoir, pas l'admin qui configure le site et utilise simplement

En consequence, le reglage disparait de la configuration et n'est plus pris en compte
Par compatibilite la methode ConvertirStylesEnligne? de la classe Facteur reste disponible, mais tout son code est deporte dans le filtre facteur_convertir_styles_inline
que l'on appellera au cas par cas dans les squelettes HTML par un appel #FILTRE{facteur_convertir_styles_inline}

Ainsi on preserve son usage quand necessaire, sans plus risque de casser les emails HTML bien fichus
On incremente la version en 2.2.0 pour marquer la difference fonctionnelle

Location:
_plugins_/facteur/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/facteur/trunk/classes/facteur.php

    r60364 r62827  
    9595                        $this->Body = $message_html;
    9696                        $this->IsHTML(true);
    97                         if ($GLOBALS['meta']['facteur_filtre_css'])
    98                                 $this->ConvertirStylesEnligne();
    9997                        if ($GLOBALS['meta']['facteur_filtre_images'])
    10098                                $this->JoindreImagesHTML();
     
    277275
    278276
     277        /**
     278         * Compat ascendante, obsolete
     279         */
    279280        function ConvertirStylesEnligne() {
    280                 /*
    281 
    282                 Written by Eric Dols - edols@auditavenue.com
    283 
    284                 You may freely use or modify this, provided
    285                 you leave credits to the original coder.
    286                 Feedback about (un)successfull uses, bugs and improvements done
    287                 are much appreciated, but don't expect actual support.
    288 
    289                 PURPOSE OF THIS FUNCTION
    290                         It is designed to process html emails relying
    291                         on a css stylesheet placed in the <head> for layout in
    292                         order to enhance compatibility with email clients,
    293                         including webmail services.
    294                         Provided you use minimal css, you can keep styling separate
    295                         from the content in your email template, and let this function
    296                         "inject" those styles inline in your email html tags on-the-fly,
    297                         just before sending.
    298                         Technically, it grabs the style declarations found in the
    299                         <head> section and inserts each declaration inline,
    300                         inside the corresponding html tags in the email message.
    301 
    302                         Supports both HTML and XHTML markup seamlessly. Thus
    303                         tolerant to email message writers using non-xhtml tag,
    304                         even when template is xhtml compliant (e.g. they would
    305                         add <img ...> instead of a xhtml compliant <img ... />).
    306 
    307                 NEW 10 dec. 2003:
    308                         - code revised, including a few regexp bugs fixed.
    309                         - multiple class for a tag are now allowed <p class="firstclass secondclass">
    310                         - all unsupported css styles are now moved to the body section (not just a:hover etc...)
    311 
    312                 USE
    313                         Add this function to a function library include, like "inline.inc"
    314                         and include it near the beginning of your php page:
    315                         require ("inline.inc");
    316 
    317                         load the html source of message into a variable
    318                         like $html_source and process it using:
    319                         $html_source = sheet2inline($html_source)
    320 
    321 
    322                 STYLE DEFINITIONS SUPPORTED
    323                         TAG { ... }
    324                         TAG1, TAG2, ... { ... }
    325                         TAG.class { ... }
    326                         .class { ...)
    327                         TAG:pseudo { ... }
    328 
    329 
    330                         CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
    331                         they are converted to oneliners before inserting them inline in the html tags.
    332 
    333                         .class definitions are processed AFTER tag definitions,
    334                         thus appended inline after any existing tag styling to
    335                         preserve the normal css priority behavior.
    336 
    337                         Existing style="..." attributes in tags are NOT stripped. However they MUST
    338                         be with double quotes. If not, an addtional style="..." attribute will be added
    339 
    340 
    341                 KNOWN LIMITATIONS
    342                         - style info should be placed in <head> section. I believe
    343                                 it shouldnt be too hard to modify to point to an external
    344                                 stylesheet instead.
    345                         - no support (yet?):
    346                                 * chains like P UL LI { .... } or P UL LI.class { .... }
    347                                 * #divname p { ... } and <tag id="...">
    348                                 * a:hover, a:visited {...} multiple class:pseudo
    349                                 They require a significantly more complicated processing likely
    350                                 based on stylesheet and document trees parsing.
    351                                 Many email clients don't handle more than what is supported
    352                                 by this script anyway.
    353                         - pseudo-classes like a:hover {...} can't be inserted inline
    354                                 in the html tags: they are moved to a <style> declaration in
    355                                 the <body> instead. This is a limitation from html, not this script.
    356                         - It is still up to you to check if target email clients render
    357                                 your css styled templates correctly, especially webmail services
    358                                 like Hotmail, in which the email becomes a sub-part of an html page,
    359                                 with styles already in place.
    360                 */
    361 
    362                 // variables to be accessed in the callback sub-function too
    363                 global $styledefinition, $styletag, $styleclass;
    364 
    365                 // Let's first load the stylesheet information in a $styles array using a regexp
    366                 preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $this->Body , $styles);
    367                 /*
    368                         $styles[1] = . or ''  => .class or tag (empty)
    369                         $styles[2] = name of class or tag(s)
    370                         $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
    371                         $styles[4] = name of pseudo-element after a tag, if any
    372                         $styles[5] = the style definition itself, i.e. what's between the { }
    373                 */
    374 
    375                 // Now loop through the styles found and act accordingly;
    376 
    377                 // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
    378                 foreach ($styles[1] as $i => $type) {
    379                         if ($type=="" && $styles[3][$i]=="") {
    380                                 $styledefinition = trim($styles[5][$i]);
    381                                 $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
    382                                 $styleclass = "";
    383                                 // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
    384                                 if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
    385                                         $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
    386                                         $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
    387                                         $styles[6][$i]=1; // mark as injected inline
    388                                 }
    389                         }
    390                 }
    391 
    392                 // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
    393                 // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
    394                 foreach ($styles[1] as $i => $type) {
    395                         if ($type!="." && $styles[3][$i]=="." ) {       // class definition for a specific tag
    396                                 $styledefinition = trim($styles[5][$i]);
    397                                 $styletag = trim($styles[2][$i]);
    398                                 $styleclass = trim($styles[4][$i]);
    399                                 $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
    400                                 $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
    401                                 $styles[6][$i]=1; // mark as injected inline
    402 
    403                         }
    404                         elseif ($type=="." && $styles[3][$i]=="" ) {    // general class definition for any tag
    405                                 $styledefinition = trim($styles[5][$i]);
    406                                 $styletag = "";
    407                                 $styleclass = trim($styles[2][$i]);
    408                                 $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
    409                                 $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
    410                                 $styles[6][$i]=1; // mark as injected inline
    411                         }
    412                 }
    413 
    414 
    415                 /* move all style declarations that weren't injected from <head> to a <body> <style> section,
    416                          including but not limited to:
    417                          - pseudo-classes like a:hover {...} as they can't be set inline
    418                          - declaration chains like UL LI {...}
    419                          - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
    420                 foreach ($styles[1] as $i => $type) {
    421                         if ($styles[6][$i]=="") {
    422                                 // add a <style type="text/css"> section after <body> if there's isn't one yet
    423                                 if (preg_match ("!<body[^>]*>\s*<style!mi", $this->Body)==0) {
    424                                         $this->Body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $this->Body);
    425                                 }
    426                                 // append a copy of the pseudo-element declaration to that body style section
    427                                 $styledefinition = trim($styles[5][$i]);
    428                                 $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
    429                                 $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
    430                                 $this->Body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $this->Body);
    431                                 $styles[6][$i]= 2; // mark as moved to <style> section in <body>
    432                         }
    433                 }
    434 
    435                 // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
    436                 //$this->Body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $this->Body);
    437 
    438                 // check what styles have been injected
    439 #                       print_r($styles);
    440 
     281                $this->Body = facteur_convertir_styles_inline($this->Body);
    441282        }
    442283
  • _plugins_/facteur/trunk/facteur_fonctions.php

    r62768 r62827  
    88
    99if (!defined("_ECRIRE_INC_VERSION")) return;
     10
     11        /*
     12
     13        Written by Eric Dols - edols@auditavenue.com
     14
     15        You may freely use or modify this, provided
     16        you leave credits to the original coder.
     17        Feedback about (un)successfull uses, bugs and improvements done
     18        are much appreciated, but don't expect actual support.
     19
     20        PURPOSE OF THIS FUNCTION
     21                It is designed to process html emails relying
     22                on a css stylesheet placed in the <head> for layout in
     23                order to enhance compatibility with email clients,
     24                including webmail services.
     25                Provided you use minimal css, you can keep styling separate
     26                from the content in your email template, and let this function
     27                "inject" those styles inline in your email html tags on-the-fly,
     28                just before sending.
     29                Technically, it grabs the style declarations found in the
     30                <head> section and inserts each declaration inline,
     31                inside the corresponding html tags in the email message.
     32
     33                Supports both HTML and XHTML markup seamlessly. Thus
     34                tolerant to email message writers using non-xhtml tag,
     35                even when template is xhtml compliant (e.g. they would
     36                add <img ...> instead of a xhtml compliant <img ... />).
     37
     38        NEW 10 dec. 2003:
     39                - code revised, including a few regexp bugs fixed.
     40                - multiple class for a tag are now allowed <p class="firstclass secondclass">
     41                - all unsupported css styles are now moved to the body section (not just a:hover etc...)
     42
     43        USE
     44                Add this function to a function library include, like "inline.inc"
     45                and include it near the beginning of your php page:
     46                require ("inline.inc");
     47
     48                load the html source of message into a variable
     49                like $html_source and process it using:
     50                $html_source = sheet2inline($html_source)
     51
     52
     53        STYLE DEFINITIONS SUPPORTED
     54                TAG { ... }
     55                TAG1, TAG2, ... { ... }
     56                TAG.class { ... }
     57                .class { ...)
     58                TAG:pseudo { ... }
     59
     60
     61                CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
     62                they are converted to oneliners before inserting them inline in the html tags.
     63
     64                .class definitions are processed AFTER tag definitions,
     65                thus appended inline after any existing tag styling to
     66                preserve the normal css priority behavior.
     67
     68                Existing style="..." attributes in tags are NOT stripped. However they MUST
     69                be with double quotes. If not, an addtional style="..." attribute will be added
     70
     71
     72        KNOWN LIMITATIONS
     73                - style info should be placed in <head> section. I believe
     74                        it shouldnt be too hard to modify to point to an external
     75                        stylesheet instead.
     76                - no support (yet?):
     77                        * chains like P UL LI { .... } or P UL LI.class { .... }
     78                        * #divname p { ... } and <tag id="...">
     79                        * a:hover, a:visited {...} multiple class:pseudo
     80                        They require a significantly more complicated processing likely
     81                        based on stylesheet and document trees parsing.
     82                        Many email clients don't handle more than what is supported
     83                        by this script anyway.
     84                - pseudo-classes like a:hover {...} can't be inserted inline
     85                        in the html tags: they are moved to a <style> declaration in
     86                        the <body> instead. This is a limitation from html, not this script.
     87                - It is still up to you to check if target email clients render
     88                        your css styled templates correctly, especially webmail services
     89                        like Hotmail, in which the email becomes a sub-part of an html page,
     90                        with styles already in place.
     91        */
     92function facteur_convertir_styles_inline($body){
     93        // variables to be accessed in the callback sub-function too
     94        global $styledefinition, $styletag, $styleclass;
     95
     96        // Let's first load the stylesheet information in a $styles array using a regexp
     97        preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $body , $styles);
     98        /*
     99                $styles[1] = . or ''  => .class or tag (empty)
     100                $styles[2] = name of class or tag(s)
     101                $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
     102                $styles[4] = name of pseudo-element after a tag, if any
     103                $styles[5] = the style definition itself, i.e. what's between the { }
     104        */
     105
     106        // Now loop through the styles found and act accordingly;
     107
     108        // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
     109        foreach ($styles[1] as $i => $type) {
     110                if ($type=="" && $styles[3][$i]=="") {
     111                        $styledefinition = trim($styles[5][$i]);
     112                        $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
     113                        $styleclass = "";
     114                        // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
     115                        if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
     116                                $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
     117                                $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
     118                                $styles[6][$i]=1; // mark as injected inline
     119                        }
     120                }
     121        }
     122
     123        // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
     124        // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
     125        foreach ($styles[1] as $i => $type) {
     126                if ($type!="." && $styles[3][$i]=="." ) {       // class definition for a specific tag
     127                        $styledefinition = trim($styles[5][$i]);
     128                        $styletag = trim($styles[2][$i]);
     129                        $styleclass = trim($styles[4][$i]);
     130                        $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
     131                        $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
     132                        $styles[6][$i]=1; // mark as injected inline
     133
     134                }
     135                elseif ($type=="." && $styles[3][$i]=="" ) {    // general class definition for any tag
     136                        $styledefinition = trim($styles[5][$i]);
     137                        $styletag = "";
     138                        $styleclass = trim($styles[2][$i]);
     139                        $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
     140                        $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
     141                        $styles[6][$i]=1; // mark as injected inline
     142                }
     143        }
     144
     145
     146        /* move all style declarations that weren't injected from <head> to a <body> <style> section,
     147                 including but not limited to:
     148                 - pseudo-classes like a:hover {...} as they can't be set inline
     149                 - declaration chains like UL LI {...}
     150                 - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
     151        foreach ($styles[1] as $i => $type) {
     152                if ($styles[6][$i]=="") {
     153                        // add a <style type="text/css"> section after <body> if there's isn't one yet
     154                        if (preg_match ("!<body[^>]*>\s*<style!mi", $body)==0) {
     155                                $body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $body);
     156                        }
     157                        // append a copy of the pseudo-element declaration to that body style section
     158                        $styledefinition = trim($styles[5][$i]);
     159                        $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
     160                        $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
     161                        $body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $body);
     162                        $styles[6][$i]= 2; // mark as moved to <style> section in <body>
     163                }
     164        }
     165
     166        // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
     167        //$body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $body);
     168
     169        // check what styles have been injected
     170#                       print_r($styles);
     171
     172        return $body;
     173}
    10174
    11175/**
  • _plugins_/facteur/trunk/formulaires/configurer_facteur.html

    r54249 r62827  
    119119                                        <ul>
    120120                                                <li class="editer_facteur_filtres[ (#ENV**{erreurs}|table_valeur{facteur_filtres}|oui)erreur]">
    121                                                         <label><:facteur:facteur_smtp_secure:></label>
    122121                                                        [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_secure})</span>]
    123122                                                        <p class="explication"><:facteur:facteur_filtres_descriptif:></p>
     
    125124                                                                <input type="checkbox" name="facteur_filtre_images" class="checkbox" value="1" id="facteur_filtre_images"[(#ENV{facteur_filtre_images,''}|=={1}|oui)checked="checked"]/>
    126125                                                                <label for="facteur_filtre_images"><:facteur:facteur_filtre_images:></label>
    127                                                         </div>
    128                                                         <div class="choix">
    129                                                                 <input type="checkbox" name="facteur_filtre_css" class="checkbox" value="1" id="facteur_filtre_css"[(#ENV{facteur_filtre_css,''}|=={1}|oui)checked="checked"]/>
    130                                                                 <label for="facteur_filtre_css"><:facteur:facteur_filtre_css:></label>
    131126                                                        </div>
    132127                                                        <div class="choix">
  • _plugins_/facteur/trunk/formulaires/configurer_facteur.php

    r60043 r62827  
    2323                'facteur_smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],
    2424                'facteur_filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],
    25                 'facteur_filtre_css' => $GLOBALS['meta']['facteur_filtre_css'],
    2625                'facteur_filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],
    2726                '_enable_smtp_secure' => (intval(phpversion()) == 5)?' ':'',
     
    126125
    127126        ecrire_meta('facteur_filtre_images', intval(_request('facteur_filtre_images')));
    128         ecrire_meta('facteur_filtre_css', intval(_request('facteur_filtre_css')));
    129127        ecrire_meta('facteur_filtre_iso_8859', intval(_request('facteur_filtre_iso_8859')));
    130128
  • _plugins_/facteur/trunk/paquet.xml

    r62768 r62827  
    22        prefix="facteur"
    33        categorie="communication"
    4         version="2.1.10"
     4        version="2.2.0"
    55        etat="stable"
    66        compatibilite="[3.0.0;3.0.*]"
Note: See TracChangeset for help on using the changeset viewer.