(function($) { | |
/** | |
* @class Filter - clean editor content | |
* @param elRTE editor instance | |
* @author Dmitry (dio) Levashov, dio@std42.ru | |
*/ | |
elRTE.prototype.filter = function(rte) { | |
var self = this, | |
n = $('<span/>').addClass('elrtetesturl').appendTo(document.body)[0]; | |
// media replacement image base url | |
this.url = (typeof(n.currentStyle )!= "undefined" ? n.currentStyle['backgroundImage'] : document.defaultView.getComputedStyle(n, null)['backgroundImage']).replace(/^url\((['"]?)([\s\S]+\/)[\s\S]+\1\)$/i, "$2"); | |
$(n).remove(); | |
this.rte = rte; | |
// flag - return xhtml tags? | |
this.xhtml = /xhtml/i.test(rte.options.doctype); | |
// boolean attributes | |
this.boolAttrs = rte.utils.makeObject('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'.split(',')); | |
// tag regexp | |
this.tagRegExp = /<(\/?)([\w:]+)((?:\s+[a-z\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*\/?>/g; | |
// this.tagRegExp = /<(\/?)([\w:]+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*\/?>/g; | |
// opened tag regexp | |
this.openTagRegExp = /<([\w:]+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*\/?>/g; | |
// attributes regexp | |
this.attrRegExp = /(\w+)(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^\s]+))?/g; | |
// script tag regexp | |
this.scriptRegExp = /<script([^>]*)>([\s\S]*?)<\/script>/gi; | |
// style tag regexp | |
this.styleRegExp = /(<style([^>]*)>[\s\S]*?<\/style>)/gi; | |
// link tag regexp | |
this.linkRegExp = /(<link([^>]+)>)/gi; | |
// cdata regexp | |
this.cdataRegExp = /<!\[CDATA\[([\s\S]+)\]\]>/g; | |
// object tag regexp | |
this.objRegExp = /<object([^>]*)>([\s\S]*?)<\/object>/gi; | |
// embed tag regexp | |
this.embRegExp = /<(embed)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*>/gi; | |
// param tag regexp | |
this.paramRegExp = /<(param)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*>/gi; | |
// iframe tag regexp | |
this.iframeRegExp = /<iframe([^>]*)>([\s\S]*?)<\/iframe>/gi; | |
// yandex maps regexp | |
this.yMapsRegExp = /<div\s+([^>]*id\s*=\s*('|")?YMapsID[^>]*)>/gi; | |
// google maps regexp | |
this.gMapsRegExp = /<iframe\s+([^>]*src\s*=\s*"http:\/\/maps\.google\.\w+[^>]*)>([\s\S]*?)<\/iframe>/gi; | |
// video hostings url regexp | |
this.videoHostRegExp = /^(http:\/\/[\w\.]*)?(youtube|vimeo|rutube).*/i; | |
// elrte services classes regexp | |
this.serviceClassRegExp = /<(\w+)([^>]*class\s*=\s*"[^>]*elrte-[^>]*)>\s*(<\/\1>)?/gi; | |
this.pagebreakRegExp = /<(\w+)([^>]*style\s*=\s*"[^>]*page-break[^>]*)>\s*(<\/\1>)?/gi; | |
this.pbRegExp = new RegExp('<!-- pagebreak -->', 'gi'); | |
// allowed tags | |
this.allowTags = rte.options.allowTags.length ? rte.utils.makeObject(rte.options.allowTags) : null; | |
// denied tags | |
this.denyTags = rte.options.denyTags.length ? rte.utils.makeObject(rte.options.denyTags) : null; | |
// deny attributes | |
this.denyAttr = rte.options.denyAttr ? rte.utils.makeObject(rte.options.denyAttr) : null; | |
// deny attributes for pasted html | |
this.pasteDenyAttr = rte.options.pasteDenyAttr ? rte.utils.makeObject(rte.options.pasteDenyAttr) : null; | |
// font sizes to convert size attr into css property | |
this.fontSize = ['medium', 'xx-small', 'small', 'medium','large','x-large','xx-large' ]; | |
// font families regexp to detect family by font name | |
this.fontFamily = { | |
'sans-serif' : /^(arial|tahoma|verdana)$/i, | |
'serif' : /^(times|times new roman)$/i, | |
'monospace' : /^courier$/i | |
} | |
// scripts storage | |
this.scripts = {}; | |
// cached chains of rules | |
this._chains = {}; | |
// cache chains | |
$.each(this.chains, function(n) { | |
self._chains[n] = []; | |
$.each(this, function(i, r) { | |
typeof(self.rules[r]) == 'function' && self._chains[n].push(self.rules[r]); | |
}); | |
}); | |
/** | |
* filtering through required chain | |
* | |
* @param String chain name | |
* @param String html-code | |
* @return String | |
**/ | |
this.proccess = function(chain, html) { | |
// remove whitespace at the begin and end | |
html = $.trim(html).replace(/^\s*( )+/gi, '').replace(/( |<br[^>]*>)+\s*$/gi, ''); | |
// pass html through chain | |
$.each(this._chains[chain]||[], function() { | |
html = this.call(self, html); | |
}); | |
html = html.replace(/\t/g, ' ').replace(/\r/g, '').replace(/\s*\n\s*\n+/g, "\n")+' '; | |
return $.trim(html) ? html : ' '; | |
} | |
/** | |
* wrapper for "wysiwyg" chain filtering | |
* | |
* @param String | |
* @return String | |
**/ | |
this.wysiwyg = function(html) { | |
return this.proccess('wysiwyg', html); | |
} | |
/** | |
* wrapper for "source" chain filtering | |
* | |
* @param String | |
* @return String | |
**/ | |
this.source = function(html) { | |
return this.proccess('source', html); | |
} | |
/** | |
* wrapper for "source2source" chain filtering | |
* | |
* @param String | |
* @return String | |
**/ | |
this.source2source = function(html) { | |
return this.proccess('source2source', html); | |
} | |
/** | |
* wrapper for "wysiwyg2wysiwyg" chain filtering | |
* | |
* @param String | |
* @return String | |
**/ | |
this.wysiwyg2wysiwyg = function(html) { | |
return this.proccess('wysiwyg2wysiwyg', html); | |
} | |
/** | |
* Parse attributes from string into object | |
* | |
* @param String string of attributes | |
* @return Object | |
**/ | |
this.parseAttrs = function(s) { | |
var a = {}, | |
b = this.boolAttrs, | |
m = s.match(this.attrRegExp), | |
t, n, v; | |
// this.rte.log(s) | |
// this.rte.log(m) | |
m && $.each(m, function(i, s) { | |
t = s.split('='); | |
n = $.trim(t[0]).toLowerCase(); | |
if (t.length>2) { | |
t.shift(); | |
v = t.join('='); | |
} else { | |
v = b[n] ||t[1]||''; | |
} | |
a[n] = $.trim(v).replace(/^('|")(.*)(\1)$/, "$2"); | |
}); | |
a.style = this.rte.utils.parseStyle(a.style); | |
// rte.log(a.style) | |
a['class'] = this.rte.utils.parseClass(a['class']||'') | |
return a; | |
} | |
/** | |
* Restore attributes string from hash | |
* | |
* @param Object attributes hash | |
* @return String | |
**/ | |
this.serializeAttrs = function(a, c) { | |
var s = [], self = this; | |
$.each(a, function(n, v) { | |
if (n=='style') { | |
v = self.rte.utils.serializeStyle(v, c); | |
} else if (n=='class') { | |
// self.rte.log(v) | |
// self.rte.log(self.rte.utils.serializeClass(v)) | |
v = self.rte.utils.serializeClass(v); | |
} | |
v && s.push(n+'="'+v+'"'); | |
}); | |
return s.join(' '); | |
} | |
/** | |
* Remove/replace denied attributes/style properties | |
* | |
* @param Object attributes hash | |
* @param String tag name to wich attrs belongs | |
* @return Object | |
**/ | |
this.cleanAttrs = function(a, t) { | |
var self = this, ra = this.replaceAttrs; | |
// remove safari and mso classes | |
$.each(a['class'], function(n) { | |
/^(Apple-style-span|mso\w+)$/i.test(n) && delete a['class'][n]; | |
}); | |
function value(v) { | |
return v+(/\d$/.test(v) ? 'px' : ''); | |
} | |
$.each(a, function(n, v) { | |
// replace required attrs with css | |
ra[n] && ra[n].call(self, a, t); | |
// remove/fix mso styles | |
if (n == 'style') { | |
$.each(v, function(sn, sv) { | |
switch (sn) { | |
case "mso-padding-alt": | |
case "mso-padding-top-alt": | |
case "mso-padding-right-alt": | |
case "mso-padding-bottom-alt": | |
case "mso-padding-left-alt": | |
case "mso-margin-alt": | |
case "mso-margin-top-alt": | |
case "mso-margin-right-alt": | |
case "mso-margin-bottom-alt": | |
case "mso-margin-left-alt": | |
case "mso-table-layout-alt": | |
case "mso-height": | |
case "mso-width": | |
case "mso-vertical-align-alt": | |
a.style[sn.replace(/^mso-|-alt$/g, '')] = value(sv); | |
delete a.style[sn]; | |
break; | |
case "horiz-align": | |
a.style['text-align'] = sv; | |
delete a.style[sn]; | |
break; | |
case "vert-align": | |
a.style['vertical-align'] = sv; | |
delete a.style[sn]; | |
break; | |
case "font-color": | |
case "mso-foreground": | |
a.style.color = sv; | |
delete a.style[sn]; | |
break; | |
case "mso-background": | |
case "mso-highlight": | |
a.style.background = sv; | |
delete a.style[sn]; | |
break; | |
case "mso-default-height": | |
a.style['min-height'] = value(sv); | |
delete a.style[sn]; | |
break; | |
case "mso-default-width": | |
a.style['min-width'] = value(sv); | |
delete a.style[sn]; | |
break; | |
case "mso-padding-between-alt": | |
a.style['border-collapse'] = 'separate'; | |
a.style['border-spacing'] = value(sv); | |
delete a.style[sn]; | |
break; | |
case "text-line-through": | |
if (sv.match(/(single|double)/i)) { | |
a.style['text-decoration'] = 'line-through'; | |
} | |
delete a.style[sn]; | |
break; | |
case "mso-zero-height": | |
if (sv == 'yes') { | |
a.style.display = 'none'; | |
} | |
delete a.style[sn]; | |
break; | |
case 'font-weight': | |
if (sv == 700) { | |
a.style['font-weight'] = 'bold'; | |
} | |
break; | |
default: | |
if (sn.match(/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/)) { | |
delete a.style[sn] | |
} | |
} | |
}); | |
} | |
}); | |
return a; | |
} | |
} | |
// rules to replace tags | |
elRTE.prototype.filter.prototype.replaceTags = { | |
b : { tag : 'strong' }, | |
big : { tag : 'span', style : {'font-size' : 'large'} }, | |
center : { tag : 'div', style : {'text-align' : 'center'} }, | |
i : { tag : 'em' }, | |
font : { tag : 'span' }, | |
nobr : { tag : 'span', style : {'white-space' : 'nowrap'} }, | |
menu : { tag : 'ul' }, | |
plaintext : { tag : 'pre' }, | |
s : { tag : 'strike' }, | |
small : { tag : 'span', style : {'font-size' : 'small'}}, | |
u : { tag : 'span', style : {'text-decoration' : 'underline'} }, | |
xmp : { tag : 'pre' } | |
} | |
// rules to replace attributes | |
elRTE.prototype.filter.prototype.replaceAttrs = { | |
align : function(a, n) { | |
switch (n) { | |
case 'img': | |
a.style[a.align.match(/(left|right)/) ? 'float' : 'vertical-align'] = a.align; | |
break; | |
case 'table': | |
if (a.align == 'center') { | |
a.style['margin-left'] = a.style['margin-right'] = 'auto'; | |
} else { | |
a.style['float'] = a.align; | |
} | |
break; | |
default: | |
a.style['text-align'] = a.align; | |
} | |
delete a.align; | |
}, | |
border : function(a) { | |
!a.style['border-width'] && (a.style['border-width'] = (parseInt(a.border)||1)+'px'); | |
!a.style['border-style'] && (a.style['border-style'] = 'solid'); | |
delete a.border; | |
}, | |
bordercolor : function(a) { | |
!a.style['border-color'] && (a.style['border-color'] = a.bordercolor); | |
delete a.bordercolor; | |
}, | |
background : function(a) { | |
!a.style['background-image'] && (a.style['background-image'] = 'url('+a.background+')'); | |
delete a.background; | |
}, | |
bgcolor : function(a) { | |
!a.style['background-color'] && (a.style['background-color'] = a.bgcolor); | |
delete a.bgcolor; | |
}, | |
clear : function(a) { | |
a.style.clear = a.clear == 'all' ? 'both' : a.clear; | |
delete a.clear; | |
}, | |
color : function(a) { | |
!a.style.color && (a.style.color = a.color); | |
delete a.color; | |
}, | |
face : function(a) { | |
var f = a.face.toLowerCase(); | |
$.each(this.fontFamily, function(n, r) { | |
if (f.match(r)) { | |
a.style['font-family'] = f+','+n; | |
} | |
}); | |
delete a.face; | |
}, | |
hspace : function(a, n) { | |
if (n == 'img') { | |
var v = parseInt(a.hspace)||0; | |
!a.style['margin-left'] && (a.style['margin-left'] = v+'px'); | |
!a.style['margin-right'] && (a.style['margin-right'] = v+'px') | |
delete a.hspace; | |
} | |
}, | |
size : function(a, n) { | |
if (n != 'input') { | |
a.style['font-size'] = this.fontSize[parseInt(a.size)||0]||'medium'; | |
delete a.size; | |
} | |
}, | |
valign : function(a) { | |
if (!a.style['vertical-align']) { | |
a.style['vertical-align'] = a.valign; | |
} | |
delete a.valign; | |
}, | |
vspace : function(a, n) { | |
if (n == 'img') { | |
var v = parseInt(a.vspace)||0; | |
!a.style['margin-top'] && (a.style['margin-top'] = v+'px'); | |
!a.style['margin-bottom'] && (a.style['margin-bottom'] = v+'px') | |
delete a.hspace; | |
} | |
} | |
} | |
// rules collection | |
elRTE.prototype.filter.prototype.rules = { | |
/** | |
* If this.rte.options.allowTags is set - remove all except this ones | |
* | |
* @param String html code | |
* @return String | |
**/ | |
allowedTags : function(html) { | |
var a = this.allowTags; | |
return a ? html.replace(this.tagRegExp, function(t, c, n) { return a[n.toLowerCase()] ? t : ''; }) : html; | |
}, | |
/** | |
* If this.rte.options.denyTags is set - remove all deny tags | |
* | |
* @param String html code | |
* @return String | |
**/ | |
deniedTags : function(html) { | |
var d = this.denyTags; | |
return d ? html.replace(this.tagRegExp, function(t, c, n) { return d[n.toLowerCase()] ? '' : t }) : html; | |
}, | |
/** | |
* Replace not allowed tags/attributes | |
* | |
* @param String html code | |
* @return String | |
**/ | |
clean : function(html) { | |
var self = this, | |
rt = this.replaceTags, | |
ra = this.replaceAttrs, | |
da = this.denyAttr, | |
n; | |
html = html.replace(/<!DOCTYPE([\s\S]*)>/gi, '') | |
.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>") | |
.replace(/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s ]*)<\/span>/gi, "$1") | |
.replace(/(<p[^>]*>\s*<\/p>|<p[^>]*\/>)/gi, '<br>') | |
.replace(/(<\/p>)(?:\s*<br\s*\/?>\s*|\s* \s*)+\s*(<p[^>]*>)/gi, function(t, b, e) { | |
return b+"\n"+e; | |
}) | |
.replace(this.tagRegExp, function(t, c, n, a) { | |
n = n.toLowerCase(); | |
if (c) { | |
return '</'+(rt[n] ? rt[n].tag : n)+'>'; | |
} | |
// self.rte.log(t) | |
// create attributes hash and clean it | |
a = self.cleanAttrs(self.parseAttrs(a||''), n); | |
// self.rte.log(a) | |
if (rt[n]) { | |
rt[n].style && $.extend(a.style, rt[n].style); | |
n = rt[n].tag; | |
} | |
da && $.each(a, function(na) { | |
if (da[na]) { | |
delete a[na]; | |
} | |
}); | |
a = self.serializeAttrs(a); | |
// self.rte.log(a) | |
return '<'+n+(a?' ':'')+a+'>'; | |
}); | |
n = $('<div>'+html+'</div>'); | |
// remove empty spans and merge nested spans | |
n.find('span:not([id]):not([class])').each(function() { | |
var t = $(this); | |
if (!t.attr('style')) { | |
$.trim(t.html()).length ? self.rte.dom.unwrap(this) : t.remove(); | |
// t.children().length ? self.rte.dom.unwrap(this) : t.remove(); | |
} | |
}).end().find('span span:only-child').each(function() { | |
var t = $(this), | |
p = t.parent().eq(0), | |
tid = t.attr('id'), | |
pid = p.attr('id'), id, s, c; | |
if (self.rte.dom.isOnlyNotEmpty(this) && (!tid || !pid)) { | |
c = $.trim(p.attr('class')+' '+t.attr('class')) | |
c && p.attr('class', c); | |
s = self.rte.utils.serializeStyle($.extend(self.rte.utils.parseStyle($(this).attr('style')||''), self.rte.utils.parseStyle($(p).attr('style')||''))); | |
s && p.attr('style', s); | |
id = tid||pid; | |
id && p.attr('id', id); | |
this.firstChild ? $(this.firstChild).unwrap() : t.remove(); | |
} | |
}) | |
.end().find('a[name]').each(function() { | |
$(this).addClass('elrte-protected elrte-anchor'); | |
}); | |
return n.html() | |
}, | |
/** | |
* Clean pasted html | |
* | |
* @param String html code | |
* @return String | |
**/ | |
cleanPaste : function(html) { | |
var self = this, d = this.pasteDenyAttr; | |
html = html | |
.replace(this.scriptRegExp, '') | |
.replace(this.styleRegExp, '') | |
.replace(this.linkRegExp, '') | |
.replace(this.cdataRegExp, '') | |
.replace(/\<\!--[\s\S]*?--\>/g, ''); | |
if (this.rte.options.pasteOnlyText) { | |
html = html.replace(this.tagRegExp, function(t, c, n) { | |
return /br/i.test(n) || (c && /h[1-6]|p|ol|ul|li|div|blockquote|tr/i) ? '<br>' : ''; | |
}).replace(/( |<br[^>]*>)+\s*$/gi, ''); | |
} else if (d) { | |
html = html.replace(this.openTagRegExp, function(t, n, a) { | |
a = self.parseAttrs(a); | |
$.each(a, function(an) { | |
if (d[an]) { | |
delete a[an]; | |
} | |
}); | |
a = self.serializeAttrs(a, true); | |
return '<'+n+(a?' ':'')+a+'>'; | |
}); | |
} | |
return html; | |
}, | |
/** | |
* Replace script/style/media etc with placeholders | |
* | |
* @param String html code | |
* @return String | |
**/ | |
replace : function(html) { | |
var self = this, r = this.rte.options.replace||[], n; | |
// custom replaces if set | |
if (r.length) { | |
$.each(r, function(i, f) { | |
if (typeof(f) == 'function') { | |
html = f.call(self, html); | |
} | |
}); | |
} | |
/** | |
* Return media replacement - img html code | |
* | |
* @param Object object to store in rel attr | |
* @param String media mime-type | |
* @return String | |
**/ | |
function img(o, t) { | |
var s = src(), | |
c = s && self.videoHostRegExp.test(s) ? s.replace(self.videoHostRegExp, "$2") : t.replace(/^\w+\/(.+)/, "$1"), | |
w = parseInt((o.obj ? o.obj.width || o.obj.style.width : 0)||(o.embed ? o.embed.width || o.embed.style.width : 0))||150, | |
h = parseInt((o.obj ? o.obj.height || o.obj.style.height : 0)||(o.embed ? o.embed.height || o.embed.style.height : 0))||100, | |
id = 'media'+Math.random().toString().substring(2), | |
style ='', | |
l; | |
// find media src | |
function src() { | |
if (o.embed && o.embed.src) { | |
return o.embed.src; | |
} | |
if (o.params && o.params.length) { | |
l = o.params.length; | |
while (l--) { | |
if (o.params[l].name == 'src' || o.params[l].name == 'movie') { | |
return o.params[l].value; | |
} | |
} | |
} | |
} | |
if (o.obj && o.obj.style && o.obj.style['float']) { | |
style = ' style="float:'+o.obj.style['float']+'"'; | |
} | |
self.scripts[id] = o; | |
return '<img src="'+self.url+'pixel.gif" class="elrte-media elrte-media-'+c+' elrte-protected" title="'+(s ? self.rte.utils.encode(s) : '')+'" rel="'+id+'" width="'+w+'" height="'+h+'"'+style+'>'; | |
} | |
html = html | |
.replace(this.styleRegExp, "<!-- ELRTE_COMMENT$1 -->") | |
.replace(this.linkRegExp, "<!-- ELRTE_COMMENT$1-->") | |
.replace(this.cdataRegExp, "<!--[CDATA[$1]]-->") | |
.replace(this.scriptRegExp, function(t, a, s) { | |
var id; | |
if (self.denyTags.script) { | |
return ''; | |
} | |
id = 'script'+Math.random().toString().substring(2); | |
a = self.parseAttrs(a); | |
!a.type && (a.type = 'text/javascript'); | |
self.scripts[id] = '<script '+self.serializeAttrs(a)+">"+s+"</script>"; | |
return '<!-- ELRTE_SCRIPT:'+(id)+' -->'; | |
}) | |
.replace(this.yMapsRegExp, function(t, a) { | |
a = self.parseAttrs(a); | |
a['class']['elrte-yandex-maps'] = 'elrte-yandex-maps'; | |
a['class']['elrte-protected'] = 'elrte-protected'; | |
return '<div '+self.serializeAttrs(a)+'>'; | |
}) | |
.replace(this.gMapsRegExp, function(t, a) { | |
var id = 'gmaps'+Math.random().toString().substring(2), w, h; | |
a = self.parseAttrs(a); | |
w = parseInt(a.width||a.style.width||100); | |
h = parseInt(a.height||a.style.height||100); | |
self.scripts[id] = t; | |
return '<img src="'+self.url+'pixel.gif" class="elrte-google-maps elrte-protected" id="'+id+'" style="width:'+w+'px;height:'+h+'px">'; | |
}) | |
.replace(this.objRegExp, function(t, a, c) { | |
var m = c.match(self.embRegExp), | |
o = { obj : self.parseAttrs(a), embed : m && m.length ? self.parseAttrs(m[0].substring(7)) : null, params : [] }, | |
i = self.rte.utils.mediaInfo(o.embed ? o.embed.type||'' : '', o.obj.classid||''); | |
if (i) { | |
if ((m = c.match(self.paramRegExp))) { | |
$.each(m, function(i, p) { | |
o.params.push(self.parseAttrs(p.substring(6))); | |
}); | |
} | |
!o.obj.classid && (o.obj.classid = i.classid[0]); | |
!o.obj.codebase && (o.obj.codebase = i.codebase); | |
o.embed && !o.embed.type && (o.embed.type = i.type); | |
// ie bug with empty attrs | |
o.obj.width == '1' && delete o.obj.width; | |
o.obj.height == '1' && delete o.obj.height; | |
if (o.embed) { | |
o.embed.width == '1' && delete o.embed.width; | |
o.embed.height == '1' && delete o.embed.height; | |
} | |
return img(o, i.type); | |
} | |
return t; | |
}) | |
.replace(this.embRegExp, function(t, n, a) { | |
var a = self.parseAttrs(a), | |
i = self.rte.utils.mediaInfo(a.type||''); | |
// ie bug with empty attrs | |
a.width == '1' && delete a.width; | |
a.height == '1' && delete a.height; | |
return i ? img({ embed : a }, i.type) : t; | |
}) | |
.replace(this.iframeRegExp, function(t, a) { | |
var a = self.parseAttrs(a); | |
var w = a.style.width || (parseInt(a.width) > 1 ? parseInt(a.width)+'px' : '100px'); | |
var h = a.style.height || (parseInt(a.height) > 1 ? parseInt(a.height)+'px' : '100px'); | |
var id = 'iframe'+Math.random().toString().substring(2); | |
self.scripts[id] = t; | |
var img = '<img id="'+id+'" src="'+self.url+'pixel.gif" class="elrte-protected elrte-iframe" style="width:'+w+'; height:'+h+'">'; | |
return img; | |
}) | |
.replace(this.vimeoRegExp, function(t, n, a) { | |
a = self.parseAttrs(a); | |
delete a.frameborder; | |
a.width == '1' && delete a.width; | |
a.height == '1' && delete a.height; | |
a.type = 'application/x-shockwave-flash'; | |
return img({ embed : a }, 'application/x-shockwave-flash'); | |
}) | |
.replace(/<\/(embed|param)>/gi, '') | |
.replace(this.pbRegExp, function() { | |
return '<img src="'+self.url+'pixel.gif" class="elrte-protected elrte-pagebreak">'; | |
}); | |
n = $('<div>'+html+'</div>'); | |
// remove empty spans and merge nested spans | |
// n.find('span:not([id]):not([class])').each(function() { | |
// var t = $(this); | |
// | |
// if (!t.attr('style')) { | |
// $.trim(t.html()).length ? self.rte.dom.unwrap(this) : t.remove(); | |
// // t.children().length ? self.rte.dom.unwrap(this) : t.remove(); | |
// } | |
// }).end().find('span span:only-child').each(function() { | |
// var t = $(this), | |
// p = t.parent().eq(0), | |
// tid = t.attr('id'), | |
// pid = p.attr('id'), id, s, c; | |
// | |
// if (self.rte.dom.is(this, 'onlyChild') && (!tid || !pid)) { | |
// c = $.trim(p.attr('class')+' '+t.attr('class')) | |
// c && p.attr('class', c); | |
// s = self.rte.utils.serializeStyle($.extend(self.rte.utils.parseStyle($(this).attr('style')||''), self.rte.utils.parseStyle($(p).attr('style')||''))); | |
// s && p.attr('style', s); | |
// id = tid||pid; | |
// id && p.attr('id', id); | |
// this.firstChild ? $(this.firstChild).unwrap() : t.remove(); | |
// } | |
// }) | |
// .end().find('a[name]').each(function() { | |
// $(this).addClass('elrte-anchor'); | |
// }); | |
if (!this.rte.options.allowTextNodes) { | |
// wrap inline nodes with p | |
var dom = this.rte.dom, | |
nodes = [], | |
w = []; | |
if ($.browser.msie) { | |
for (var i = 0; i<n[0].childNodes.length; i++) { | |
nodes.push(n[0].childNodes[i]) | |
} | |
} else { | |
nodes = Array.prototype.slice.call(n[0].childNodes); | |
} | |
function wrap() { | |
if (w.length && dom.filter(w, 'notEmpty').length) { | |
dom.wrap(w, document.createElement('p')); | |
} | |
w = []; | |
} | |
$.each(nodes, function(i, n) { | |
if (dom.is(n, 'block')) { | |
wrap(); | |
} else { | |
if (w.length && n.previousSibling != w[w.length-1]) { | |
wrap(); | |
} | |
w.push(n); | |
} | |
}); | |
wrap(); | |
} | |
return n.html(); | |
}, | |
/** | |
* Restore script/style/media etc from placeholders | |
* | |
* @param String html code | |
* @return String | |
**/ | |
restore : function(html) { | |
var self =this, r = this.rte.options.restore||[]; | |
// custom restore if set | |
if (r.length) { | |
$.each(r, function(i, f) { | |
if (typeof(f) == 'function') { | |
html = f.call(self, html); | |
} | |
}); | |
} | |
html = html | |
.replace(/\<\!--\[CDATA\[([\s\S]*?)\]\]--\>/gi, "<![CDATA[$1]]>") | |
.replace(/\<\!--\s*ELRTE_SCRIPT\:\s*(script\d+)\s*--\>/gi, function(t, n) { | |
if (self.scripts[n]) { | |
t = self.scripts[n]; | |
delete self.scripts[n]; | |
} | |
return t||''; | |
}) | |
.replace(/\<\!-- ELRTE_COMMENT([\s\S]*?) --\>/gi, "$1") | |
.replace(this.serviceClassRegExp, function(t, n, a, e) { | |
var a = self.parseAttrs(a), j, o = ''; | |
// alert(t) | |
if (a['class']['elrte-google-maps']) { | |
var t = ''; | |
if (self.scripts[a.id]) { | |
t = self.scripts[a.id]; | |
delete self.scripts[a.id] | |
} | |
return t; | |
} else if (a['class']['elrte-iframe']) { | |
return self.scripts[a.id] || ''; | |
} else if (a['class']['elrtebm']) { | |
return ''; | |
} else if (a['class']['elrte-media']) { | |
// alert(a.rel) | |
// return '' | |
// j = a.rel ? JSON.parse(self.rte.utils.decode(a.rel)) : {}; | |
j = self.scripts[a.rel]||{}; | |
j.params && $.each(j.params, function(i, p) { | |
o += '<param '+self.serializeAttrs(p)+">\n"; | |
}); | |
j.embed && (o+='<embed '+self.serializeAttrs(j.embed)+">"); | |
j.obj && (o = '<object '+self.serializeAttrs(j.obj)+">\n"+o+"\n</object>\n"); | |
return o||t; | |
} else if (a['class']['elrte-pagebreak']) { | |
return '<!-- pagebreak -->'; | |
} | |
$.each(a['class'], function(n) { | |
if (/^elrte-\w+/i.test(n)) { | |
delete(a['class'][n]); | |
} | |
// /^elrte\w+/i.test(n) && delete(a['class'][n]); | |
}); | |
return '<'+n+' '+self.serializeAttrs(a)+'>'+(e||''); | |
}); | |
return html; | |
}, | |
/** | |
* compact styles and move tags and attributes names in lower case(for ie&opera) | |
* | |
* @param String html code | |
* return String | |
**/ | |
compactStyles : function(html) { | |
var self = this; | |
return html.replace(this.tagRegExp, function(t, c, n, a) { | |
a = !c && a ? self.serializeAttrs(self.parseAttrs(a), true) : ''; | |
return '<'+c+n.toLowerCase()+(a?' ':'')+a+'>'; | |
}); | |
}, | |
/** | |
* return xhtml tags | |
* | |
* @param String html code | |
* return String | |
**/ | |
xhtmlTags : function(html) { | |
return this.xhtml ? html.replace(/<(img|hr|br|embed|param|link|area)([^>]*\/*)>/gi, "<$1$2 />") : html; | |
} | |
} | |
/** | |
* Chains configuration | |
* Default chains | |
* wysiwyg - proccess html from source for wysiwyg editor mode | |
* source - proccess html from wysiwyg for source editor mode | |
* paste - clean pasted html | |
* wysiwyg2wysiwyg - ciclyc rule to clean html from wysiwyg for wysiwyg paste | |
* source2source - ciclyc rule to clean html from source for source paste | |
* deniedTags is in the end of chain to protect google maps iframe from removed | |
**/ | |
elRTE.prototype.filter.prototype.chains = { | |
wysiwyg : ['replace', 'clean', 'allowedTags', 'deniedTags', 'compactStyles'], | |
source : ['clean', 'allowedTags', 'restore', 'compactStyles', 'xhtmlTags'], | |
paste : ['clean', 'allowedTags', 'cleanPaste', 'replace', 'deniedTags', 'compactStyles'], | |
wysiwyg2wysiwyg : ['clean', 'allowedTags', 'restore', 'replace', 'deniedTags', 'compactStyles'], | |
source2source : ['clean', 'allowedTags', 'replace', 'deniedTags', 'restore', 'compactStyles', 'xhtmlTags'] | |
} | |
})(jQuery); |