Compile CSS into HTML as Inline Style in Grails?
Asked Answered
S

2

7

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.

Steadfast answered 15/10, 2013 at 13:7 Comment(0)
B
-3

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.
}
}
Blastema answered 18/10, 2013 at 5:45 Comment(2)
@Blastema please give mote details how it is used?Elmore
I'm just wonder about your question, seems you are not familiar with Java/Groovy good enough. The integration depends on your application, you can use this snippet wherever you want in your own app, getting html code from corresponding gsp file and passing it to parse function as param. Also there are comments in the code and I described that core part of this snippet is jsoup lib. Seems you want me to write code specific to your application. :) I think this code with description good enough for junior developer for integration.Blastema
M
1

We do this with a free method on the Mailchimp API. You can also use Premailer.

http://apidocs.mailchimp.com/api/1.2/inlinecss.func.php

http://premailer.dialect.ca/

Micronucleus answered 17/10, 2013 at 20:5 Comment(11)
How can I include this in Grails?Steadfast
Both are external web services which you can call from grails: grails.org/Calling+External+WebServices We do this in .NET, but the approach is the same. We call the .aspx page with the email template on the localhost loopback address to get it's html -- you would call your .gsp page. Then we submit that html to the css inliner web service.Micronucleus
Here it is done in grails: github.com/happyinc/grails-mailchimp/blob/master/grails-app/…Micronucleus
how do I have to use your Service?Steadfast
Don't I need a api key?Steadfast
Mailchimp requires an API key. It's free to sign up.Micronucleus
how do I have to use your Service? Can you please post some code?Steadfast
A grails wrapper for the api method you need is on line 461 at github.com/happyinc/grails-mailchimp/blob/master/grails-app/…Micronucleus
Can you please post an example of how I have to use this code? Where do I have to enter the key? How can I inline a specific file let s say /basePath/grails/views/mail/testmail.gsp ?Steadfast
The APIs inline css in html -- not Groovy Server Pages. So first you need to get the html that your .gsp generates. Something like: def myHtml = new URL('http://localhost/testmail.gsp').getText(). Then pass the myHtml variable to the css inliner of your choice. If you use the plugin I mentioned above, you put the api key in config.Groovy. There are instructions at the same site at github.com/happyinc/grails-mailchimp/blob/master/README.mdMicronucleus
@Micronucleus Can you please give a coding example how it is applied?Elmore
B
-3

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.
}
}
Blastema answered 18/10, 2013 at 5:45 Comment(2)
@Blastema please give mote details how it is used?Elmore
I'm just wonder about your question, seems you are not familiar with Java/Groovy good enough. The integration depends on your application, you can use this snippet wherever you want in your own app, getting html code from corresponding gsp file and passing it to parse function as param. Also there are comments in the code and I described that core part of this snippet is jsoup lib. Seems you want me to write code specific to your application. :) I think this code with description good enough for junior developer for integration.Blastema

© 2022 - 2024 — McMap. All rights reserved.