Search code examples
htmlspringgrailsgrails-2.0grails-plugin

Compile CSS into HTML as Inline Style in Grails?


I want to generate GSP templates for html emails. To support more mail clients it is recommended to use inline css in html style elements.

Here is a discussion on that topic: "Compile" CSS into HTML as inline styles

Is there a Grails plugin where I can specify certain GSP files for which the CSS should be compiled as inline?

If there is no plugin, how can I specify GSP files for which the css should be complied inline?

Here is an example. I have the following GSP templates for my html mails that I send with the Grails mail plugin.

/mail/signup_mail.gsp
/mail/welcome.gsp
/mail/newsletter.gsp

Each GSP file includes a style.css file. This should be compiled inline.


Solution

  • You can fit the following Java code in your grails application.

        import java.io.IOException;
        import java.util.StringTokenizer;
    
        import org.jsoup.Jsoup;
        import org.jsoup.nodes.Document;
        import org.jsoup.nodes.Element;
        import org.jsoup.select.Elements;
    
        public class AutomaticCssInliner {
    
        public static void main(String[] args) throws IOException {
            final String style = "style";
            final String html = "<html>" + "<body> <style>"
                    + "body{background:#FFC} \n p{background:red}"
                    + "body, p{font-weight:bold} </style>"
                    + "<p>...</p> </body> </html>";
            // Document doc = Jsoup.connect("http://mypage.com/inlineme.php").get();
            Document doc = Jsoup.parse(html);
            Elements els = doc.select(style);// to get all the style elements
            for (Element e : els) {
                String styleRules = e.getAllElements().get(0).data().replaceAll(
                        "\n", "").trim(), delims = "{}";
                StringTokenizer st = new StringTokenizer(styleRules, delims);
                while (st.countTokens() > 1) {
                    String selector = st.nextToken(), properties = st.nextToken();
                    Elements selectedElements = doc.select(selector);
                    for (Element selElem : selectedElements) {
                        String oldProperties = selElem.attr(style);
                        selElem.attr(style,
                                oldProperties.length() > 0 ? concatenateProperties(
                                        oldProperties, properties) : properties);
                    }
                }
                e.remove();
            }
            System.out.println(doc);// now we have the result html without the
            // styles tags, and the inline css in each
            // element
        }
    
    private static String concatenateProperties(String oldProp, String newProp) {
        oldProp = oldProp.trim();
        if (!newProp.endsWith(";"))
           newProp += ";";
        return newProp + oldProp; // The existing (old) properties should take precedence.
    }
    }