var defaultTextStyles = {}
defaultTextStyles['font-family'] = 'AceFont1';
defaultTextStyles['font-size'] = '13';
defaultTextStyles['font-weight'] = 'normal';
defaultTextStyles['font-style'] = 'normal';
var base_padding = 24;
var extra_padding = 36;
function addZero(n, reslen) {
var reslen = reslen || 2;
var res = n + '';
while (res.length < reslen) res = '0' + res;
return res;
}
function rgbToHex(str) {
var m
if( (m = str.match(/(rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+)\s*)?\))/ )) ) {
var color = '#'
+ addZero(parseInt(m[2]).toString(16))
+ addZero(parseInt(m[3]).toString(16))
+ addZero(parseInt(m[4]).toString(16))
str = str.replace(m[1], color)
}
return str;
}
function rgbToHexAll(str) {
return str.replace(/(?:rgb\s*\(\s*(?:\d+)\s*,\s*(?:\d+)\s*,\s*(?:\d+)\s*(?:,\s*(\d+)\s*)?\))/ig , function(a,b,c) {
var hex = rgbToHex(a);
return hex;
}).replace(/rgba\(\s*0\s*,\s*0\s*,\s*0\s*,\s*0\s*\)/ig , 'transparent')
}
function convert(content, options) {
defaultTextStyles['font-size'] = options['font-size'];
var unique_id = 1;
var div = $('
').appendTo('body');
div[0].innerHTML = content.replace(/(\&)(?:[\w\d]{2,10}\;)/g , function(a){//hide unicode &xxx; chars
return a.replace(/&/g , '###amp;')
});
var res_div = $('').appendTo('body');
traverse(div[0]);
res_div.find('[data-uid]').removeAttr('data-uid');
res_div.find('table').each(function() {
var $this = $(this);
if( !$this.attr('cellspacing') ) $this.attr('cellspacing', '0');
if( !$this.attr('cellpadding') ) $this.attr('cellpadding', '0');
if( !$this.attr('border') ) $this.attr('border', '0');
if( !this.style.tableLayout && ($(this).closest('.table-space').length == 0) ) this.style.tableLayout = 'fixed';
});
res_div.find('td').each(function() {
var $this = $(this);
if( !$this.attr('valign') ) $this.attr('valign', 'top');
if( !$this.attr('align') ) $this.attr('align', options['rtl'] ? 'right' : 'left');
});
res_div.find('img').each(function() {
var $this = $(this);
if( !$this.attr('hspace') ) $this.attr('hspace', '0');
if( !$this.attr('vspace') ) $this.attr('vspace', '0');
if( !$this.attr('border') ) $this.attr('border', '0');
if( !this.style.display && $this.siblings('img').length == 0 ) this.style.display = 'block';//for older outlooks?
if( !this.style.paddingBottom && $this.closest('.table-col-td').length != 0 && !$this.next().is('br') ) this.style.paddingBottom = '9px';
});
res_div.find(' > div').children().unwrap();
var output =
res_div.html()
.replace(/###amp;/g, '&')
//.replace(/AceFont1/ig, options['font-family']).replace(/AceFont2/ig, options['font-family']);
output = rgbToHexAll(output);
output = output.replace(/line-height\:\s*(\d+\.\d+)px/ig, function(a, b, c) {
return a.replace(b, parseInt(Math.round(b)));
});
//wrap contents inside a slightly bigger td
var wrap_size = parseInt(options['wrap-size'])
if(wrap_size > 0) {
var wrap_width = parseInt(options['base-width']) + wrap_size;
if( div.find('.navbar').length == 0 )
output = '';
}
div.remove();
res_div.remove();
return output;
function traverse(input_parent) {
var child = input_parent.firstChild;
while(child != null) {
//if child is text append to parent! continue;//
if( child.nodeType == 1 && child.getAttribute('data-uid') == null ) {
var $elem = $(child);
var $class = $elem.attr('class');
unique_id++;
$elem.attr('data-uid', unique_id);
if( $elem.hasClass('row') ) {
var uid = $elem.parent().attr('data-uid');
var parent_td = res_div.find('[data-uid='+uid+']');
var table = $('')
.appendTo(parent_td);
table.attr('width', options['base-width']);
var td = table.find('td');
td.attr('data-uid', unique_id);
if( $elem.closest('.navbar').length == 0 ) {
var bg = $elem[0].style.backgroundColor || options['content-background'];
table.attr('bgcolor', bg).css('background-color', bg);
}
}
else if( $elem.is('[class*=col]') && $elem.parent().hasClass('row') ) {
var uid = $elem.parent().attr('data-uid');
var parent_td = res_div.find('[data-uid='+uid+']');
var class_name = $elem.parent().hasClass('sm-border') ? 'table-col-border': 'table-col';
var new_table =
$('')
.appendTo(parent_td);
new_table.attr('align', options['rtl'] ? 'right' : 'left');
var siblings = $elem.siblings('[class*=col]').length;
var col_count = siblings + 1;
//calculat .row padding and column margins
var pclass = $elem.parent().attr('class');
var match_padding = null;
if( pclass && (match_padding = pclass.match(/padding\-(\d+)/i)) ) {
match_padding = parseInt(match_padding[1]);
}
var row_padding = typeof match_padding === 'number' ? match_padding : extra_padding;
if( typeof match_padding === 'number' ) {
parent_td.closest('table').attr('class', 'table-row-fixed');
parent_td.closest('.table-row-td').attr('class', 'table-row-fixed-td');
}
var margins = {'1': 0, '2': 18, '3': 16, '4': 16, '6': 9}
var match_margin = null;
if( pclass && (match_margin = pclass.match(/margin\-(\d+)/i)) ) {
match_margin = parseInt(match_margin[1]);
}
var margin = typeof match_margin === 'number' ? match_margin : margins[col_count];
//
var grid_size = ((options['base-width'] - (2 * row_padding)) - (siblings * margin)) / 12;
var is_last_child = ($elem.nextAll('[class*=col]').length == 0)
var col_margin = is_last_child ? 0 : margin;
var width = 0;
var clen = $elem.attr('class').match(/col-(?:xs|sm|md|lg)-(\d+)/i);
if(clen && clen[1]) {
var clen = parseInt(clen[1]);
width = parseInt(grid_size * clen)
new_table.attr('width', width + col_margin);
if(col_margin > 0) new_table.css('padding-' + (options['rtl'] ? 'left' : 'right'), col_margin)
//columns with extra padding
new_table.closest('td[class*="table-row-"]').css({'padding-left': row_padding, 'padding-right': row_padding});
} else {
//single .col only
row_padding = typeof match_padding === 'number' ? match_padding : base_padding;
width = (options['base-width'] - (row_padding * 2));
new_table.attr('width', width);
new_table.closest('td[class*="table-row-"]').css({'padding-left': row_padding, 'padding-right': row_padding});
}
var td = new_table.find('td');
td.attr('data-uid', unique_id);
td.attr('width', width);
td.addClass('table-col-td');
}
else if( $elem.hasClass('clearfix') ) {
var uid = $elem.parent().attr('data-uid');
var parent_td = res_div.find('[data-uid='+uid+']');
var new_table = $('').appendTo(parent_td);
if( $elem.closest('.navbar').length == 0 ) {
var bg = $elem[0].style.backgroundColor || options['content-background'];
new_table.attr('bgcolor', bg).css('background-color', bg);
}
var tmp = $elem;
while( true ) {
var new_tr = $('
').appendTo(new_table);
new_tr.attr('data-uid', unique_id);
tmp = tmp.next();
if( tmp.hasClass('clearfix') ) {
unique_id++;
tmp.attr('data-uid', unique_id);
}
else break;
}
var pclass = $elem.attr('class');
var match_padding = null;
if( pclass && (match_padding = pclass.match(/padding\-(\d+)/i)) ) {
match_padding = parseInt(match_padding[1]);
}
var padding = typeof match_padding === 'number' ? match_padding : base_padding;
if( typeof match_padding === 'number' ) parent_td.closest('table').attr('class', 'table-row-fixed');
new_table.css('padding-right', padding);
new_table.css('padding-left', padding);
var parent_width = new_table.closest('[width]').attr('width') || options['base-width'];
new_table.attr('width', parent_width).css('width', parent_width);
}
else if( $elem.is('[class*=pull-]') && $elem.parent().hasClass('clearfix') ) {
var parent = $elem.parent();
var uid = parent.attr('data-uid');
var parent_tr = res_div.find('[data-uid='+uid+']');
//append now
var new_td = $(' | ').appendTo(parent_tr);
if(parent[0].style.height) new_td.css('height', parent[0].style.height);
new_td.attr('data-uid', unique_id);
if( new_td.closest('table').hasClass('table-row-fixed') ) new_td.attr('class', 'table-row-fixed-td');
//add padding between tds
if( $elem.nextAll('[class*=pull-]').length > 0 ) {
var padding = parseInt($elem.css('padding-'+(options['rtl'] ? 'left' : 'right'))) || 16;
new_td.css('padding-'+(options['rtl'] ? 'left' : 'right'), padding);
}
if( $elem.parent().next().hasClass('clearfix') ) {
var padding_bottom = parseInt($elem.css('padding-bottom')) || 12;
new_td.css('padding-bottom', padding_bottom);
}
//var line_height = parseInt($elem.css('line-height')) || 18;
//new_td.css('line-height', line_height+'px');
}
else if( $elem.attr('class') && $elem.attr('class').match(/(?:space|hr|break)-(\d+)/i) ) {
var clen = $elem.attr('class').match(/(?:space|hr|break)-(\d+)/i);
var h = 16;
if(clen && clen[1]) {
h = parseInt(clen[1]);// * 2;
}
var uid = $elem.parent().attr('data-uid');
var parent = res_div.find('[data-uid='+uid+']');
var table = $('').appendTo(parent);
var w = table.closest('[width]').attr('width') || options['base-width'];
w = parseInt(w);
var padding = parseInt(base_padding * (w / options['base-width']));
table.attr('width', w).css({'font-size': 0, 'line-height': 0, 'width':w})
.find('td').attr('width', w).css('width', w);
if($elem.is('[class*=space]')) {
var bg = $elem[0].style.backgroundColor || options['content-background'];
if($elem.hasClass('transparent') || $elem.closest('.well,.alert,.navbar').length > 0) bg = 'transparent';
table.attr('bgcolor', bg).css('background-color', bg)
.find('td').attr('bgcolor', bg).css('background-color', bg)
}
else if($elem.is('[class*=break]')) {
var bg = $elem[0].style.backgroundColor || options['body-background'];
table.attr('bgcolor', bg).css('background-color', bg)
.find('td').attr('bgcolor', bg).css('background-color', bg)
}
else if($elem.is('[class*=hr]')) {
var bg = $elem[0].style.backgroundColor || options['content-background'];
if($elem.hasClass('transparent') || $elem.closest('.well,.alert,.navbar').length > 0) bg = 'transparent';
table.attr('bgcolor', bg).css('background-color', bg)
.find('td')
.attr({'bgcolor': bg, 'align': 'center'})
.css('background-color', bg)
var hr_padding = null;
if($elem.hasClass('compact')) hr_padding = padding;
else if( (hr_padding = $elem.attr('class').match(/padding\-(\d+)/i)) ) {
hr_padding = parseInt(hr_padding[1]);
}
var parent_padding = typeof hr_padding === 'number' ? hr_padding : parseInt(extra_padding / 2);
bg = $elem[0].style.color || options['hr-background'];
var parent_td = table.find('td');
var td = $('')
.appendTo(parent_td);
parent_td.css({'padding-left': parent_padding, 'padding-right': parent_padding})
}
}
else if( $elem.hasClass('navbar') ) {
var uid = $elem.parent().attr('data-uid');
var parent = res_div.find('[data-uid='+uid+']');
var table = $('').appendTo(parent);
table.attr('width', '100%').css('width', '100%').find('td').attr({'width' : '100%', 'align': 'center'}).css('width', '100%');
var bg = $elem.css('background-color');
table.attr('bgcolor', bg).css('background-color', bg).find('td').attr('bgcolor', bg).css('background-color', bg);
$elem.attr('data-skipstyle', true);
var navbar_h = $elem[0].style.height || 50;
table = $('').appendTo(table.find('td'))
table.find('td').attr('data-uid', unique_id);
}
else if( $elem.is('h1,h2,h3,h4,h5,h6') ) {
var uid = $elem.parent().attr('data-uid');
var parent = res_div.find('[data-uid='+uid+']');
var table = $('').appendTo(parent);
table.find('td').attr('data-uid', unique_id);
var w = table.closest('[width]').attr('width') || options['base-width'];
table.attr('width', w).find('td').attr('width', w);
}
else {
var uid = $elem.parent().attr('data-uid');
var parent = res_div.find('[data-uid='+uid+']');
var $tag = $elem[0].tagName.toLowerCase();
if( ($tag == 'div' || $tag == 'p') &&
(parseInt($elem.css('padding-left')) > 0 || parseInt($elem.css('padding-right')) > 0
|| parseInt($elem.css('padding-top')) > 0 || parseInt($elem.css('padding-bottom')) > 0) )
{
//because outlook doesn't allow padding on DIV
//we convert it to TD
var element = $('').appendTo(parent);
element.find('td').attr('data-uid', unique_id);
}
else {
var element = $('<'+$tag+' />').appendTo(parent);
element.attr('data-uid', unique_id);
if( $tag == 'hr' ) {
$elem.attr('data-skipstyle', true);
element.css({'background-color': $elem[0].style.backgroundColor || options['hr-background'], 'border-width': 0, 'height': '1px'})
}
}
}
}
else if(child.nodeType == 3) {
var puid = $(child).parent().attr('data-uid');
var parent = res_div.find('[data-uid='+puid+']');
parent.append(child.textContent.replace(/\"/g, '"').replace(/\/g, '>'));
}
/**
else if(child.nodeType == 8) {
}
*/
if(child.nodeType == 1) {
var mirror = res_div.find('[data-uid='+child.getAttribute('data-uid')+']')
if(mirror.length == 1) {
var attributes = child.attributes;
for (var i = 0; i < attributes.length; i++){
var attr = attributes.item(i);
var attr_name = attr.nodeName.toLowerCase();
if( attr_name == 'style' || attr_name.indexOf('on') == 0 ) continue;//ignore onclick, etc
if( attr_name == 'class' && child.tagName.toLowerCase() != 'img') continue;//allow class on image only
if( !mirror.attr(attr.nodeName) ) mirror.attr(attr.nodeName, attr.nodeValue);
}
var applied_styles = {}
var elem = child;
var $elem = $(elem);
var rules = $elem.attr('data-skipstyle') ? null : window.getMatchedCSSRules(elem);
if( (rules && rules.length > 0) || (elem.style.length > 0) ) {
if(rules) for(var i = 0; i < rules.length; i++) {
var styles = rules[i]['style'];
for(var k = 0 ; k < styles.length; k++) {
applied_styles[styles[k]] = true;
}
}
for(var k = 0 ; k < elem.style.length; k++) {
applied_styles[elem.style[k]] = true;
}
var styles = {}
var computedStyle = window.getComputedStyle(elem, null);
for(var k in applied_styles) {
k = $.trim(k.toLowerCase());
var m
//exclude margin for now, not supported by outlook
if((m = k.match(/^(margin|padding)(?:-(left|right|top|bottom))?/))) {
if( $elem.hasClass('row') || $elem.is('[class*=col]') || $elem.hasClass('clearfix') ) continue;
var name = m[1];
if( !(name in styles) ) styles[name] = {}
if( typeof m[2] !== 'undefined' ) styles[name][m[2]] = computedStyle[name+'-'+m[2]];
else {
var val = computedStyle[name];
var part = val.split(/\s+/);
styles[name]['top'] = part[0];
styles[name]['right'] = part[1] || part[0];
styles[name]['bottom'] = part[2] || part[0];
styles[name]['left'] = part[3] || part[1] || part[0];
}
}
else if(k.match(/border/)) {//only supports border/border-top/border-bottom/border-left/border-right
if( (m = k.match(/^(border)(?:-(left|right|top|bottom))?(?:-(width|color|style))?$/)) ) {
if( typeof m[2] !== 'undefined' && typeof m[3] !== 'undefined' ) {
if( !('border' in styles) ) styles['border'] = {}
styles['border'][m[2]] = rgbToHex(computedStyle['border-'+m[2]]);
}
}
}
else if( k.match(/^(?:background-)?color$/) ) {
var color = rgbToHex(computedStyle[k]);
styles[k] = color;
if( k.match(/^background-color$/) && (mirror.is('td') || mirror.is('table')) ) mirror.attr('bgcolor', color);
}
else if( k.match(/^(?:width|height)$/) ) {
var attr = mirror.attr(k);
if( !attr && ('style' in mirror[0] || !mirror[0].style[k]) ) {
styles[k] = computedStyle[k];
var val = parseInt(computedStyle[k]);
if( !isNaN(val) && (mirror.is('td') || mirror.is('table') || mirror.is('tr') || mirror.is('img')) ) {
mirror.attr(k, styles[k]);
}
}
if( attr && !mirror[0].style[k] ) styles[k] = attr;
}
else if(k.match(/text-align/)) {
if( mirror.is('td') ){
var v = computedStyle[k];
mirror.attr('align', v);
}
styles[k] = computedStyle[k];
}
else if(k.match(/vertical-align/)) {
if( mirror.is('td') ){
var v = computedStyle[k];
if(v == 'top' || v == 'bottom' || v == 'middle') {
mirror.attr('valign', v);
} else mirror.attr('valign', 'top');
}
styles[k] = computedStyle[k];
}
else if(k.match(/^(font-family|font-style|font-size|font-weight)$/)) {
if( computedStyle[k] != defaultTextStyles[k] || mirror.is('td') ) styles[k] = computedStyle[k];
var tag = elem.tagName.toUpperCase();
if( k.match(/^(font-weight)$/) && (tag == 'B' || tag == 'STRONG') ) delete styles[k];
else if( k.match(/^(font-style)$/) && (tag == 'I' || tag == 'EM') ) delete styles[k];
}
else if(k.match(/^(direction|letter-spacing|line-height|text-decoration|list-style-type|font-variant)$/)) {
//valid styles only, just copy them over
styles[k] = computedStyle[k];
}
}
for(var name in styles) {
var val = styles[name];
if( name.match(/padding|margin|border/i) ) {
if(val.left === val.right && val.left === val.top && val.top === val.bottom) {
if( name.match(/margin/i) && parseInt(val.left) !== 0 ) continue;//don't allow non-zero margin on any element (outlook doesn't support it)
mirror.css(name, val.left);
}
else {
for(var dir in val) if(val.hasOwnProperty(dir)) {
if( name.match(/margin/i) && parseInt(val[dir]) !== 0 ) continue;//don't allow non-zero margin on any element (outlook doesn't support it)
mirror.css(name+'-'+dir , val[dir]);
}
}
}
else {
mirror.css(name , val);
}
}
}
}
}
if(child.nodeType == 1) traverse(child);
child = child.nextSibling;
}//while
}//traverse
}//convert
function get_output(input_str, options) {
options['base-width'] = parseInt(options['base-width']);
var wrap_width = options['base-width'] + parseInt(options['wrap-size']);
var str = convert(input_str, options);
str = '\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
';
var title = options['title'] || '';
return str.replace(/\\<\/title\>/i, ''+title+'');
}