* The function used to validate email addresses
* @param {String} value The email address
*/
- 'email' : function(v){
+ email : function(v){
return email.test(v);
},
/**
* The error text to display when the email validation function returns false
* @type String
*/
- 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
+ emailText : 'This field should be an e-mail address in the format "user@domain.com"',
/**
* The keystroke filter mask to be applied on email input
* @type RegExp
*/
- 'emailMask' : /[a-z0-9_\.\-@]/i,
+ emailMask : /[a-z0-9_\.\-@]/i,
/**
* The function used to validate URLs
* @param {String} value The URL
*/
- 'url' : function(v){
+ url : function(v){
return url.test(v);
},
/**
* The error text to display when the url validation function returns false
* @type String
*/
- 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
+ urlText : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
/**
* The function used to validate alpha values
* @param {String} value The value
*/
- 'alpha' : function(v){
+ alpha : function(v){
return alpha.test(v);
},
/**
* The error text to display when the alpha validation function returns false
* @type String
*/
- 'alphaText' : 'This field should only contain letters and _',
+ alphaText : 'This field should only contain letters and _',
/**
* The keystroke filter mask to be applied on alpha input
* @type RegExp
*/
- 'alphaMask' : /[a-z_]/i,
+ alphaMask : /[a-z_]/i,
/**
* The function used to validate alphanumeric values
* @param {String} value The value
*/
- 'alphanum' : function(v){
+ alphanum : function(v){
return alphanum.test(v);
},
/**
* The error text to display when the alphanumeric validation function returns false
* @type String
*/
- 'alphanumText' : 'This field should only contain letters, numbers and _',
+ alphanumText : 'This field should only contain letters, numbers and _',
/**
* The keystroke filter mask to be applied on alphanumeric input
* @type RegExp
*/
- 'alphanumMask' : /[a-z0-9_]/i
+ alphanumMask : /[a-z0-9_]/i
};
}();/*
* - LGPL
}, this);
+ },
+
+
+ removeNodeKeepChildren : function( node)
+ {
+
+ ar = Array.from(node.childNodes);
+ for (var i = 0; i < ar.length; i++) {
+
+ node.removeChild(ar[i]);
+ // what if we need to walk these???
+ node.parentNode.insertBefore(ar[i], node);
+
+ }
+ node.parentNode.removeChild(node);
}
};
if (this.tag === false) {
return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
}
+ // hacky?
+ if ((typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1)) {
+ this.cleanNamespace = true;
+ }
+
this.walk(cfg.node);
}
Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
{
-
+ cleanNamespace : false, // should really be an option, rather than using ':' inside of this tag.
replaceTag : function(node)
{
// walk children...
- //Roo.log(node);
+ //Roo.log(node.tagName);
var ar = Array.from(node.childNodes);
//remove first..
+
for (var i = 0; i < ar.length; i++) {
- if (ar[i].nodeType == 1) {
+ var e = ar[i];
+ if (e.nodeType == 1) {
if (
- (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
+ (typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1)
|| // array and it matches
- (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
+ (typeof(this.tag) == 'string' && this.tag == e.tagName)
+ ||
+ (e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1)
+ ||
+ (e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'string' && this.tag == ":")
) {
this.replaceTag(ar[i]); // child is blacklisted as well...
continue;
}
}
+ //Roo.log("REMOVE:" + node.tagName);
node.parentNode.removeChild(node);
return false; // don't walk children
// no need to apply config.
this.replaceDocBullets(cfg.node);
+ this.replaceAname(cfg.node);
// this is disabled as the removal is done by other filters;
// this.walk(cfg.node);
},
+ replaceAname : function (doc)
+ {
+ // replace all the a/name without..
+ var aa = Array.from(doc.getElementsByTagName('a'));
+ for (var i = 0; i < aa.length; i++) {
+ var a = aa[i];
+ if (a.hasAttribute("name")) {
+ a.removeAttribute("name");
+ }
+ if (a.hasAttribute("href")) {
+ continue;
+ }
+ // reparent children.
+ this.removeNodeKeepChildren(a);
+
+ }
+
+
+
+ },
+
+
+
replaceDocBullets : function(doc)
{
// this is a bit odd - but it appears some indents use ql-indent-1
//Roo.log(doc.innerHTML);
- var listpara = doc.getElementsByClassName('MsoListParagraphCxSpFirst');
+ var listpara = Array.from(doc.getElementsByClassName('MsoListParagraphCxSpFirst'));
+ for( var i = 0; i < listpara.length; i ++) {
+ listpara[i].className = "MsoListParagraph";
+ }
+
+ listpara = Array.from(doc.getElementsByClassName('MsoListParagraphCxSpMiddle'));
+ for( var i = 0; i < listpara.length; i ++) {
+ listpara[i].className = "MsoListParagraph";
+ }
+ listpara = Array.from(doc.getElementsByClassName('MsoListParagraphCxSpLast'));
+ for( var i = 0; i < listpara.length; i ++) {
+ listpara[i].className = "MsoListParagraph";
+ }
+ listpara = Array.from(doc.getElementsByClassName('ql-indent-1'));
for( var i = 0; i < listpara.length; i ++) {
- listpara.item(i).className = "MsoListParagraph";
+ listpara[i].className = "MsoListParagraph";
}
+
// this is a bit hacky - we had one word document where h2 had a miso-list attribute.
- var htwo = doc.getElementsByTagName('h2');
+ var htwo = Array.from(doc.getElementsByTagName('h2'));
for( var i = 0; i < htwo.length; i ++) {
- if (htwo.item(i).getAttribute('style').match(/mso-list:/)) {
- htwo.item(i).className = "MsoListParagraph";
+ if (htwo[i].hasAttribute('style') && htwo[i].getAttribute('style').match(/mso-list:/)) {
+ htwo[i].className = "MsoListParagraph";
}
}
-
- listpara = doc.getElementsByClassName('ql-indent-1');
- while(listpara.length) {
- this.replaceDocBullet(listpara.item(0));
+ listpara = Array.from(doc.getElementsByClassName('MsoNormal'));
+ for( var i = 0; i < listpara.length; i ++) {
+ if (listpara[i].hasAttribute('style') && listpara[i].getAttribute('style').match(/mso-list:/)) {
+ listpara[i].className = "MsoListParagraph";
+ } else {
+ listpara[i].className = "MsoNormalx";
+ }
}
+
listpara = doc.getElementsByClassName('MsoListParagraph');
+ // Roo.log(doc.innerHTML);
+
+
+
while(listpara.length) {
this.replaceDocBullet(listpara.item(0));
doc = parent.ownerDocument,
items = [];
-
+ var listtype = 'ul';
while (ns) {
if (ns.nodeType != 1) {
ns = ns.nextSibling;
break;
}
var spans = ns.getElementsByTagName('span');
+ if (ns.hasAttribute('style') && ns.getAttribute('style').match(/mso-list/)) {
+ items.push(ns);
+ ns = ns.nextSibling;
+ has_list = true;
+ if (spans.length && spans[0].hasAttribute('style')) {
+ var style = this.styleToObject(spans[0]);
+ if (typeof(style['font-family']) != 'undefined' && !style['font-family'].match(/Symbol/)) {
+ listtype = 'ol';
+ }
+ }
+
+ continue;
+ }
+ var spans = ns.getElementsByTagName('span');
if (!spans.length) {
break;
}
var has_list = false;
for(var i = 0; i < spans.length; i++) {
- if (spans[i].getAttribute('style').match(/mso-list/)) {
+ if (spans[i].hasAttribute('style') && spans[i].getAttribute('style').match(/mso-list/)) {
has_list = true;
break;
}
if (!has_list) {
break;
}
-
-
items.push(ns);
ns = ns.nextSibling;
+
+
}
if (!items.length) {
ns.className = "";
return;
}
- var ul = parent.ownerDocument.createElement('ul'); // what about number lists...
+ var ul = parent.ownerDocument.createElement(listtype); // what about number lists...
parent.insertBefore(ul, p);
var lvl = 0;
var stack = [ ul ];
var last_li = false;
-
+ var margin_to_depth = {};
+ max_margins = -1;
+
items.forEach(function(n, ipos) {
//Roo.log("got innertHMLT=" + n.innerHTML);
}
-
+ var num = 1;
var style = {};
for(var i = 0; i < spans.length; i++) {
if (typeof(style['mso-list']) == 'undefined') {
continue;
}
-
+ if (listtype == 'ol') {
+ num = spans[i].innerText.replace(/[^0-9]+]/g,'') * 1;
+ }
spans[i].parentNode.removeChild(spans[i]); // remove the fake bullet.
break;
}
style = this.styleToObject(n); // mo-list is from the parent node.
if (typeof(style['mso-list']) == 'undefined') {
//Roo.log("parent is missing level");
-
-
+
parent.removeChild(n);
return;
}
- var nlvl = (style['mso-list'].split(' ')[1].replace(/level/,'') *1) - 1 ;
-
+ var margin = style['margin-left'];
+ if (typeof(margin_to_depth[margin]) == 'undefined') {
+ max_margins++;
+ margin_to_depth[margin] = max_margins;
+ }
+ nlvl = margin_to_depth[margin] ;
if (nlvl > lvl) {
//new indent
- var nul = doc.createElement('ul'); // what about number lists...
+ var nul = doc.createElement(listtype); // what about number lists...
if (!last_li) {
last_li = doc.createElement('li');
stack[lvl].appendChild(last_li);
}
lvl = nlvl;
+ // not starting at 1..
+ if (!stack[nlvl].hasAttribute("start") && listtype == "ol") {
+ stack[nlvl].setAttribute("start", num);
+ }
+
var nli = stack[nlvl].appendChild(doc.createElement('li'));
last_li = nli;
nli.innerHTML = n.innerHTML;
*/
toObject : function()
{
-
var ret = {
tag : 'td',
contenteditable : 'true', // this stops cell selection from picking the table.
this.colspan = Math.max(1,1*node.getAttribute('colspan'));
this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
this.html = node.innerHTML;
+ if (node.style.textAlign != '') {
+ this.textAlign = node.style.textAlign;
+ }
},
c.col = cn;
}
- if (typeof(this.colWidths[cn]) == 'undefined') {
+ if (typeof(this.colWidths[cn]) == 'undefined' && c.colspan < 2) {
this.colWidths[cn] = ce.style.width;
if (this.colWidths[cn] != '') {
all_auto = false;
this.colspan += rc.colspan;
this.node.setAttribute('colspan', this.colspan);
+ var table = this.toTableArray();
+ this.normalizeWidths(table);
+ this.updateWidths(table);
},
if (r == cd.row && c == cd.col) {
this.node.removeAttribute('rowspan');
this.node.removeAttribute('colspan');
- continue;
}
var ntd = this.node.cloneNode(); // which col/row should be 0..
- ntd.removeAttribute('id'); //
- //ntd.style.width = '';
+ ntd.removeAttribute('id');
+ ntd.style.width = this.colWidths[c];
ntd.innerHTML = '';
table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1 };
}
}
this.redrawAllCells(table);
-
-
},
el.width = Math.floor(this.colWidths[c]) +'%';
el.updateElement(el.node);
}
+ if (this.colWidths[0] != false && table[r][c].colspan > 1) {
+ var el = Roo.htmleditor.Block.factory(table[r][c].cell);
+ var width = 0;
+ for(var i = 0; i < table[r][c].colspan; i ++) {
+ width += Math.floor(this.colWidths[c + i]);
+ }
+ el.width = width +'%';
+ el.updateElement(el.node);
+ }
table[r][c].cell = false; // done
}
}
},
normalizeWidths : function(table)
{
-
if (this.colWidths[0] === false) {
var nw = 100.0 / this.colWidths.length;
this.colWidths.forEach(function(w,i) {
if (this.enableBlocks) {
new Roo.htmleditor.FilterBlock({ node : div });
}
+
+ var html = div.innerHTML;
+
//?? tidy?
- var tidy = new Roo.htmleditor.TidySerializer({
- inner: true
- });
- var html = tidy.serialize(div);
+ if (this.autoClean) {
+
+ new Roo.htmleditor.FilterAttributes({
+ node : div,
+ attrib_white : [
+ 'href',
+ 'src',
+ 'name',
+ 'align',
+ 'colspan',
+ 'rowspan',
+ 'data-display',
+ 'data-width',
+ 'start' ,
+ 'style',
+ // youtube embed.
+ 'class',
+ 'allowfullscreen',
+ 'frameborder',
+ 'width',
+ 'height',
+ 'alt'
+ ],
+ attrib_clean : ['href', 'src' ]
+ });
+
+ var tidy = new Roo.htmleditor.TidySerializer({
+ inner: true
+ });
+ html = tidy.serialize(div);
+
+ }
if(Roo.isSafari){
.map(function(g) { return g.toDataURL(); })
.filter(function(g) { return g != 'about:blank'; });
-
+ //Roo.log(html);
html = this.cleanWordChars(html);
var d = (new DOMParser().parseFromString(html, 'text/html')).body;
return false;
}
+
+
if (images.length > 0) {
+ // replace all v:imagedata - with img.
+ var ar = Array.from(d.getElementsByTagName('v:imagedata'));
+ Roo.each(ar, function(node) {
+ node.parentNode.insertBefore(d.ownerDocument.createElement('img'), node );
+ node.parentNode.removeChild(node);
+ });
+
+
Roo.each(d.getElementsByTagName('img'), function(img, i) {
img.setAttribute('src', images[i]);
});
new Roo.htmleditor.FilterStyleToTag({ node : d });
new Roo.htmleditor.FilterAttributes({
node : d,
- attrib_white : ['href', 'src', 'name', 'align', 'colspan', 'rowspan', 'data-display', 'data-width'],
+ attrib_white : ['href', 'src', 'name', 'align', 'colspan', 'rowspan', 'data-display', 'data-width', 'start'],
attrib_clean : ['href', 'src' ]
});
new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});