Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created February 19, 2021 12:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bennadel/cca97237fcefd5f8910745170bc30095 to your computer and use it in GitHub Desktop.
Save bennadel/cca97237fcefd5f8910745170bc30095 to your computer and use it in GitHub Desktop.
Using ColdFusion Custom Tags To Create An HTML Email DSL In Lucee CFML 5.3.7.47, Part IX
<h1>
Hello world
</h1>
<p>
This is an inlined code sample file.
</p>
<p>
This is a really long line that will have to have some sort of wrapping in order to not break the layout. And, the following line is a really long line that has no whitespace.
</p>
<p>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</p>
<!--- Import custom tag libraries. --->
<cfimport prefix="core" taglib="./core/" />
<cfimport prefix="html" taglib="./core/html/" />
<!--- // ------------------------------------------------------------------------- // --->
<!--- // ------------------------------------------------------------------------- // --->
<core:Email
subject="Code blocks"
teaser="Talking nerdy to me!">
<core:Body>
<cfoutput>
<html:h1>
Sharing code blocks in email
</html:h1>
<html:p>
Let's look at some <html:code>inline code</html:code> samples. Code
blocks tend to use a monospace font and have a light background color.
If we're going to include HTML tags in our code, we have to be sure
to encode the brackets:
<html:code>#encodeForHtml( "<strong>Cool Beans</strong>" )#</html:code>.
</html:p>
<html:p>
We can also use pre-formatted blocks of code - these are a bit more
complex, because they use both
<html:code>#encodeForHtml( "<html:pre>" )#</html:code> and
<html:code>#encodeForHtml( "<html:code>" )#</html:code> tags and have
significantly more formatting.
</html:p>
<html:pre><html:code>#htmlEditFormat( fileRead( "./ex10/code-sample.txt" ) )#</html:code></html:pre>
<html:p>
Easy peasy, lemon squeezey!
</html:p>
</cfoutput>
</core:Body>
</core:Email>
<!--- Import custom tag libraries. --->
<cfimport prefix="core" taglib="../" />
<!--- Define custom tag attributes. --->
<cfparam name="attributes.class" type="string" default="" />
<cfparam name="attributes.margins" type="string" default="small xlarge" />
<cfparam name="attributes.style" type="string" default="" />
<cfparam name="attributes.tabSize" type="string" default="4" />
<!--- // ------------------------------------------------------------------------- // --->
<!--- // ------------------------------------------------------------------------- // --->
<cfswitch expression="#thistag.executionMode#">
<cfcase value="start">
<cfoutput>
<!---
Since the "code" entity has some base styles, we need to unset some of
them for use in the "pre" tag.
--->
<core:HtmlEntityTheme entity="code">
background-color: transparent ;
border-radius: 0px ;
display: block ;
padding: 0px ;
white-space: pre-wrap ;
word-break: break-all ;
</core:HtmlEntityTheme>
</cfoutput>
</cfcase>
<cfcase value="end">
<cfoutput>
<!---
When the email content is being rendered, all unnecessary whitespace is
removed. However, we don't want this to happen in the PRE tag since the
PRE tag is intended to maintain whitespace. As such, instead of rendering
the content directly, we're going to store it. Then, we're going to
replace it back into the body after the email has been minified.
--->
<cfset email = getBaseTagData( "cf_email" ) />
<cfset email.preContentBlocks.append( thistag.generatedContent ) />
<cfset preContentBlockToken = "__PRE:#email.preContentBlocks.len()#__" />
<core:Styles
variable="tdStyle"
entityName="pre"
entityClass="#attributes.class#"
entityStyle="#attributes.style#">
tab-size: #attributes.tabSize# ;
</core:Styles>
<core:Styles variable="nativePreStyle">
Margin: 0 ; <!--- For Outlook. --->
margin: 0px ;
padding: 0px ;
white-space: pre-wrap ;
word-break: break-all ;
</core:Styles>
<core:BlockMargins margins="#attributes.margins#">
<!---
CAUTION: We are using raw HTML elements here instead of the "html"
custom tags module so that we don't accidentally apply Theme styles
to this markup.
--->
<table role="presentation" width="100%" border="0" cellpadding="10" cellspacing="0">
<tr>
<td class="#trim( 'html-entity-pre #attributes.class#' )#" style="#tdStyle#">
<pre style="#nativePreStyle#">#preContentBlockToken#</pre>
</td>
</tr>
</table>
</core:BlockMargins>
<!--- Reset the generated content since we're overriding the output. --->
<cfset thistag.generatedContent = "" />
</cfoutput>
</cfcase>
</cfswitch>
<cfscript>
// .... truncated code ....
/**
* I strip out as much white-space in the given content as possible.
*
* @content I am the email body content being minified.
*/
public string function minifyEmailContent( required string content ) {
var newline = chr( 10 );
var minifiedContent = trim( arguments.content );
// Normalizing line-breaks and spaces.
minifiedContent = reReplaceAll( minifiedContent, "(?m)^[ \t]+", "" );
minifiedContent = reReplaceAll( minifiedContent, "[\r\n]+", newline );
// Wrap each STYLE attribute onto its own line in order to help prevent mid-
// style text-wrapping applied by the more stringent email clients.
minifiedContent = reReplaceAll( minifiedContent, "(\bstyle="")", "#newline#$1" );
// Now that we've removed all the superfluous whitespace, as the last step in our
// minification, let's apply any PRE tag content (which is intended to contain
// meaningful whitespace).
preContentBlocks.each(
( preContent, i ) => {
minifiedContent = reReplaceAll( minifiedContent, "__PRE:#i#__", preContent );
}
);
return( minifiedContent );
}
// .... truncated code ....
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment