grunt-email-builder
Advanced tools
Comparing version
{ | ||
"name": "grunt-email-builder", | ||
"description": "Combine Html and Css into an email", | ||
"version": "2.0.8", | ||
"version": "2.0.10", | ||
"homepage": "https://github.com/yargalot/Email-Builder", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -12,14 +12,13 @@ /* jshint -W030,-W117 */ | ||
// Required modules | ||
var path = require('path'), | ||
os = require('os'); | ||
cheerio = require('cheerio'), | ||
mailer = require('nodemailer'), | ||
encode = require('./entityEncode'), | ||
Litmus = require('./litmus'), | ||
Promise = require('bluebird'), | ||
juice = Promise.promisifyAll(require('juice2')); | ||
var path = require('path'); | ||
var os = require('os'); | ||
var cheerio = require('cheerio'); | ||
var mailer = require('nodemailer'); | ||
var encode = require('./entityEncode'); | ||
var Litmus = require('./litmus'); | ||
var Promise = require('bluebird'); | ||
var juice = Promise.promisifyAll(require('juice2')); | ||
function EmailBuilder(task) { | ||
this.task = task; | ||
@@ -33,6 +32,40 @@ this.options = task.options(EmailBuilder.Defaults); | ||
EmailBuilder.taskDescription = 'Compile Files'; | ||
EmailBuilder.Defaults = {}; | ||
EmailBuilder.Defaults = { | ||
removeStyleTags: true, | ||
removeLinkTags: true | ||
}; | ||
/** | ||
* Remove all style and link tags by default | ||
* | ||
* @param {String} html | ||
* | ||
* @returns {String} html that has style and link tags removed | ||
*/ | ||
EmailBuilder.prototype.removeStyles = function(html) { | ||
var $ = cheerio.load(html); | ||
var linkTags = $('link'); | ||
var styleTags = $('style'); | ||
var stylesExist = (styleTags.length || linkTags.length); | ||
// Remove links and style tags after they've been inlined | ||
if(stylesExist){ | ||
if(this.options.removeStyleTags) { | ||
html = html.replace(/<\bstyle\b[\s\S]+<\/\bstyle\b>/g, ''); | ||
} | ||
if(this.options.removeLinkTags){ | ||
html = html.replace(/<link.*stylesheet[^>]+>/g,''); | ||
} | ||
} | ||
return html; | ||
}; | ||
/** | ||
* Pull all styles from link/style tags within conditional comments and put them | ||
@@ -46,31 +79,24 @@ * in a style tag | ||
EmailBuilder.prototype.handleConditionals = function(html){ | ||
EmailBuilder.prototype.addStylesToConditionals = function(html){ | ||
var reConditional = /(<!--\[\s*if[^>]+>(?:<![^>]+>)?)([\s\S]+?)(<![^>]+>)/gi; | ||
var _self = this; | ||
var $, linkTags, styleTags, stylesExist, styles; | ||
html = html.replace(reConditional, function(match, p1, p2, p3, offset, string){ | ||
var $ = cheerio.load(p2), | ||
linkTags = $('link'), | ||
styleTags = $('style'), | ||
stylesExist = (styleTags.length || linkTags.length), | ||
styles = stylesExist ? '\n<style type="text/css">\n' : ''; | ||
$ = cheerio.load(p2); | ||
linkTags = $('link'); | ||
styleTags = $('style'); | ||
stylesExist = (styleTags.length || linkTags.length); | ||
styles = stylesExist ? '\n<style type="text/css">\n' : ''; | ||
styleTags.each(function(){ | ||
var $this = $(this); | ||
styles += $this.text() + '\n'; | ||
$this.remove(); | ||
}); | ||
styles += _self.getStyleTagContent(p2).conditionalStyles; | ||
styles += _self.getLinkTagContent(p2).conditionalStyles; | ||
p2 = _self.removeStyles(p2); | ||
linkTags.each(function(){ | ||
var $this = $(this); | ||
var href = $this.attr('href'); | ||
styles += _self.grunt.file.read(href) + '\n'; | ||
$this.remove(); | ||
}); | ||
styles += stylesExist ? '\n</style>\n' : ''; | ||
return p1 + styles + $.html() + p3; | ||
return p1 + styles + p2 + p3; | ||
@@ -84,49 +110,142 @@ }); | ||
/** | ||
* Prepare html to be inlined by extracting and removing any data-ignore styles | ||
* Get styles from style tag | ||
* | ||
* @param {String} file - src file to read | ||
* @param {String} html | ||
* | ||
* @returns {Object} ignoreStyles - styles from style tags/links that have data-ignore attribute | ||
* @returns {Object} html - the new html with any style tags/links | ||
* @returns {String} an object whose properties contain styles from data-ignore being set | ||
* or styles within conditional comments | ||
*/ | ||
EmailBuilder.prototype.prepareHtml = function(file) { | ||
EmailBuilder.prototype.getStyleTagContent = function(html) { | ||
var $ = cheerio.load(html); | ||
var styleTags = $('style'); | ||
var ignoreStyles = ''; | ||
var conditionalStyles = ''; | ||
var $this; | ||
var html = this.grunt.file.read(file), | ||
$ = cheerio.load(html), | ||
styleTags = $('style'), | ||
linkTags = $('link'), | ||
ignoreStyles = '', | ||
conditionals = '', | ||
_self = this; | ||
// Grab styles from style tags with data-ignore attr | ||
styleTags.each(function(){ | ||
var $this = $(this); | ||
$this = $(this); | ||
if($this.attr('data-ignore')){ | ||
ignoreStyles += $this.text(); | ||
$this.remove(); | ||
} else { | ||
conditionalStyles += $this.text(); | ||
} | ||
}); | ||
}); | ||
// Reset base to file path | ||
this.grunt.file.setBase(path.dirname(file)); | ||
return { | ||
ignoreStyles: ignoreStyles, | ||
conditionalStyles: conditionalStyles | ||
}; | ||
}; | ||
/** | ||
* Get styles from link tag path | ||
* | ||
* @param {String} html | ||
* | ||
* @returns {String} an object whose properties contain styles from data-ignore being set | ||
* or styles within conditional comments | ||
*/ | ||
EmailBuilder.prototype.getLinkTagContent = function(html) { | ||
var $ = cheerio.load(html); | ||
var linkTags = $('link'); | ||
var _self = this; | ||
var ignoreStyles = ''; | ||
var conditionalStyles = ''; | ||
var $this, href, pathExists; | ||
// Grab styles from links with data-ignore attr | ||
linkTags.each(function(){ | ||
var $this = $(this); | ||
$this = $(this); | ||
href = $this.attr('href'); | ||
pathExists = _self.grunt.file.exists(path.resolve(process.cwd(), href)); | ||
if(pathExists){ | ||
if($this.attr('data-ignore')){ | ||
ignoreStyles += _self.grunt.file.read(href); | ||
} else { | ||
conditionalStyles += _self.grunt.file.read(href); | ||
} | ||
} | ||
if($this.attr('data-ignore')){ | ||
var href = $this.attr('href'); | ||
ignoreStyles += _self.grunt.file.read(href); | ||
$this.remove(); | ||
} | ||
}); | ||
return { | ||
ignoreStyles: ignoreStyles, | ||
conditionalStyles: conditionalStyles | ||
}; | ||
}; | ||
/** | ||
* Remove any link tags whose href path does not exist | ||
* | ||
* @param {String} html | ||
* | ||
* @returns {String} new html | ||
*/ | ||
EmailBuilder.prototype.removeNonLinks = function(html) { | ||
var $ = cheerio.load(html); | ||
var linkTags = $('link'); | ||
var _self = this; | ||
var linkTag; | ||
linkTags.each(function(){ | ||
$this = $(this); | ||
href = $this.attr('href'); | ||
pathExists = _self.grunt.file.exists(path.resolve(process.cwd(), href)); | ||
if(!pathExists){ | ||
linkTag = new RegExp('<link.*'+ href +'[^>]+>', 'g'); | ||
html = html.replace(linkTag, ''); | ||
} | ||
}); | ||
html = this.handleConditionals($.html()); | ||
return html; | ||
}; | ||
/** | ||
* Transform html to be inlined by extracting and removing any data-ignore styles | ||
* | ||
* @param {String} file - src file to read | ||
* | ||
* @returns {Object} ignoreStyles - styles from style tags/links that have data-ignore attribute | ||
* @returns {Object} html - the new html with any style tags/links | ||
*/ | ||
EmailBuilder.prototype.transformHtml = function(file) { | ||
var html = this.grunt.file.read(file); | ||
var $ = cheerio.load(html); | ||
var ignoreStyles = ''; | ||
var _self = this; | ||
// Reset base to file path | ||
this.grunt.file.setBase(path.dirname(file)); | ||
ignoreStyles += this.getStyleTagContent(html).ignoreStyles; | ||
ignoreStyles += this.getLinkTagContent(html).ignoreStyles; | ||
html = this.addStylesToConditionals($.html()); | ||
// If we don't remove links whose paths do not exist then the css | ||
// will not get inlined due to a bug in juice | ||
html = this.removeNonLinks(html); | ||
// Reset base to default | ||
this.grunt.file.setBase(this.basepath); | ||
return { | ||
@@ -155,13 +274,14 @@ ignoreStyles: ignoreStyles, | ||
var slashes = os.platform() === 'win32' ? '\\\\' : '//', | ||
url = "file:" + slashes + path.join(this.basepath, src), | ||
prepHtml = this.prepareHtml(src); | ||
var slashes = os.platform() === 'win32' ? '\\\\' : '//'; | ||
var url = "file:" + slashes + path.join(this.basepath, src); | ||
var transformHtml = this.transformHtml(src); | ||
this.options.url = url; | ||
return juice.juiceContentAsync(prepHtml.html, this.options) | ||
return juice.juiceContentAsync(transformHtml.html, this.options) | ||
.bind(this) | ||
.then(function(html){ | ||
html = html.replace(/(<\/head>)/gi, '<style type="text/css">' + prepHtml.ignoreStyles + '</style>$1'); | ||
html = html.replace(/(<\/head>)/gi, '<style type="text/css">' + transformHtml.ignoreStyles + '</style>$1'); | ||
if(this.options.encodeSpecialChars) { html = encode.htmlEncode(html); } | ||
@@ -178,2 +298,3 @@ | ||
/** | ||
@@ -200,2 +321,3 @@ * Write final html output to file | ||
/** | ||
@@ -213,9 +335,9 @@ * Send tests to Litmus App | ||
if(this.options.litmus){ | ||
var litmus = new Litmus(this.options.litmus), | ||
date = this.task.grunt.template.today('yyyy-mm-dd'), | ||
subject = this.options.litmus.subject, | ||
$ = cheerio.load(html), | ||
$title = $('title').text().trim(), | ||
files = this.task.filesSrc, | ||
titleDups = {}; | ||
var litmus = new Litmus(this.options.litmus); | ||
var date = this.task.grunt.template.today('yyyy-mm-dd'); | ||
var subject = this.options.litmus.subject; | ||
var $ = cheerio.load(html); | ||
var $title = $('title').text().trim(); | ||
var files = this.task.filesSrc; | ||
var titleDups = {}; | ||
@@ -269,7 +391,6 @@ if( (subject === undefined) || (subject.trim().length === 0) ){ | ||
var emailTest = this.options.emailTest, | ||
transportType = emailTest.transport ? emailTest.transport.type : false, | ||
transportOpts = emailTest.transport ? emailTest.transport.options : false, | ||
transport = mailer.createTransport(transportType, transportOpts); | ||
var emailTest = this.options.emailTest; | ||
var transportType = emailTest.transport ? emailTest.transport.type : false; | ||
var transportOpts = emailTest.transport ? emailTest.transport.options : false; | ||
var transport = mailer.createTransport(transportType, transportOpts); | ||
var mailOptions = { | ||
@@ -352,11 +473,10 @@ from: emailTest.email, | ||
grunt.registerMultiTask(EmailBuilder.taskName, EmailBuilder.taskDescription, function() { | ||
this.grunt = grunt; | ||
var done = this.async(); | ||
var task = new EmailBuilder(this); | ||
var done = this.async(); | ||
var task = new EmailBuilder(this); | ||
task.run() | ||
.done(done); | ||
}); | ||
@@ -363,0 +483,0 @@ }; |
@@ -206,13 +206,10 @@ var mailer = require('nodemailer'), | ||
Litmus.prototype.getBuiltXml = function(html, title) { | ||
var xmlApplications = builder.create('applications').att('type', 'array'); | ||
var xml = builder.create('test_set').ele('applications').att('type', 'array'); | ||
_.each(this.options.applications, function(app) { | ||
var item = xmlApplications.ele('application'); | ||
item.ele('code', app); | ||
xml = xml.ele('application').ele('code', app).up().up(); | ||
}); | ||
//Build Xml to send off, Join with Application XMl | ||
var xml = builder.create('test_set') | ||
.importXMLBuilder(xmlApplications) | ||
xml = xml.up() | ||
.ele('save_defaults', 'false').up() | ||
@@ -219,0 +216,0 @@ .ele('use_defaults', 'false').up() |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
58227
6.64%858
11%