All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hulsom.nexus-monitor.1.0.source-code.CssInliner.groovy Maven / Gradle / Ivy

The newest version!
import groovy.transform.CompileStatic
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.StringTokenizer;

/**
 * 

Inlines CSS to avoid the dreaded GMail Grimace.

* *

The magic keyword is data-inline="true".

* *
    *
  • * When used in conjunction with the style tag, it inlines the stylesheet defined there into all * html elements matching the rules. *
  • *
  • * When used with the img tag, it base64 encodes the image it found to make it visible in the * email. *
  • *
* * @author Rahul Somasunderam */ @CompileStatic public class CssInliner { public static final String CSS_STYLE = "cssstyle"; public static final String STYLE_ATTR = "style"; public static final String STYLE_TAG = "style"; public static final String IMG_TAG = "img"; public static final String IMG_SRC_ATTR = "src"; private static String concatenateProperties(String oldProp, String newProp) { if (!oldProp.endsWith(";")) oldProp += ";"; return oldProp.trim() + " " + newProp.trim() + ";"; } /** * Generates a stylesheet from an html document * * @param doc the html document * @return a string representing the stylesheet. */ private String fetchStyles(Document doc) { Elements els = doc.select(STYLE_TAG); StringBuilder styles = new StringBuilder(); for (Element e : els) { if (e.attr("data-inline").equals("true")) { styles.append(e.data()); e.remove(); } } return styles.toString(); } /** * Takes an input string representing an html document and processes it with the Css Inliner. * @param input the html document * @return the processed html document */ public String process(String input) { Document doc = Jsoup.parse(input); extractStyles(doc); applyStyles(doc); inlineImages(doc); String output = doc.toString(); return output; } /** * Inlines images marked with data-inline="true" * * @param doc the html document */ private void inlineImages(Document doc) { Elements allImages = doc.getElementsByTag(IMG_TAG); for (Element img : allImages) { if (img.attr("data-inline").equals("true")) { String src = img.attr(IMG_SRC_ATTR); try { URL url = new URL(src); URLConnection urlConnection = url.openConnection(); urlConnection.connect(); String contentType = urlConnection.getContentType(); urlConnection.getContent(); byte[] srcContent = IOUtils.toByteArray(url.openStream()); String base64 = new Base64().encodeToString(srcContent); img.attr(IMG_SRC_ATTR, MessageFormat.format("data:{0};base64,{1}", contentType, base64)); } catch (Exception e) { e.printStackTrace(); } } } } /** * Transfers styles from the cssstyle attribute to the style attribute. * * @param doc the html document */ private void applyStyles(Document doc) { Elements allStyledElements = doc.getElementsByAttribute(CSS_STYLE); for (Element e : allStyledElements) { String newStyle = e.attr(CSS_STYLE); String oldStyle = e.attr(STYLE_ATTR); e.attr(STYLE_ATTR, (newStyle + "; " + oldStyle).replace(";;", ";")); e.removeAttr(CSS_STYLE); } } /** * Extracts styles from the stylesheet and applies them to a cssstyle attribute. This is because the * styles need to be applied sequentially, but before the style defined for the element inline. * * @param doc the html document */ private void extractStyles(Document doc) { String stylesheet = fetchStyles(doc); String trimmedStylesheet = stylesheet.replaceAll("\n", "").replaceAll("/\\*.*?\\*/", "").replaceAll(" +", " "); String styleRules = trimmedStylesheet.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(CSS_STYLE); selElem.attr(CSS_STYLE, oldProperties.length() > 0 ? concatenateProperties( oldProperties, properties) : properties); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy