Roo/htmleditor/FilterWord.js
[roojs1] / Roo / htmleditor / FilterWord.js
1 /**
2  * @class Roo.htmleditor.FilterWord
3  * try and clean up all the mess that Word generates.
4  * 
5  * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
6  
7  * @constructor
8  * Run a new Span Filter
9  * @param {Object} config Configuration options
10  */
11
12 Roo.htmleditor.FilterWord = function(cfg)
13 {
14     // no need to apply config.
15     this.replaceDocBullets(cfg.node);
16     
17     this.walk(cfg.node);
18     
19     
20 }
21
22 Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
23 {
24     tag: true,
25      
26     
27     /**
28      * Clean up MS wordisms...
29      */
30     replaceTag : function(node)
31     {
32          
33         // no idea what this does - span with text, replaceds with just text.
34         if(
35                 node.nodeName == 'SPAN' &&
36                 !node.hasAttributes() &&
37                 node.childNodes.length == 1 &&
38                 node.firstChild.nodeName == "#text"  
39         ) {
40             var textNode = node.firstChild;
41             node.removeChild(textNode);
42             if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
43                 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44             }
45             node.parentNode.insertBefore(textNode, node);
46             if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
47                 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
48             }
49             
50             node.parentNode.removeChild(node);
51             return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
52         }
53         
54    
55         
56         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
57             node.parentNode.removeChild(node);
58             return false; // dont do chidlren
59         }
60         //Roo.log(node.tagName);
61         // remove - but keep children..
62         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
63             //Roo.log('-- removed');
64             while (node.childNodes.length) {
65                 var cn = node.childNodes[0];
66                 node.removeChild(cn);
67                 node.parentNode.insertBefore(cn, node);
68                 // move node to parent - and clean it..
69                 this.replaceTag(cn);
70             }
71             node.parentNode.removeChild(node);
72             /// no need to iterate chidlren = it's got none..
73             //this.iterateChildren(node, this.cleanWord);
74             return false; // no need to iterate children.
75         }
76         // clean styles
77         if (node.className.length) {
78             
79             var cn = node.className.split(/\W+/);
80             var cna = [];
81             Roo.each(cn, function(cls) {
82                 if (cls.match(/Mso[a-zA-Z]+/)) {
83                     return;
84                 }
85                 cna.push(cls);
86             });
87             node.className = cna.length ? cna.join(' ') : '';
88             if (!cna.length) {
89                 node.removeAttribute("class");
90             }
91         }
92         
93         if (node.hasAttribute("lang")) {
94             node.removeAttribute("lang");
95         }
96         
97         if (node.hasAttribute("style")) {
98             
99             var styles = node.getAttribute("style").split(";");
100             var nstyle = [];
101             Roo.each(styles, function(s) {
102                 if (!s.match(/:/)) {
103                     return;
104                 }
105                 var kv = s.split(":");
106                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
107                     return;
108                 }
109                 // what ever is left... we allow.
110                 nstyle.push(s);
111             });
112             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
113             if (!nstyle.length) {
114                 node.removeAttribute('style');
115             }
116         }
117         return true; // do children
118         
119         
120         
121     },
122     
123     styleToObject: function(node)
124     {
125         var styles = node.getAttribute("style").split(";");
126         var ret = {};
127         Roo.each(styles, function(s) {
128             if (!s.match(/:/)) {
129                 return;
130             }
131             var kv = s.split(":");
132              
133             // what ever is left... we allow.
134             ret[kv[0]] = kv[1];
135         });
136         return ret;
137     },
138     
139     
140     replaceDocBullets : function(doc)
141     {
142         var listpara = doc.getElementsByClassName('MsoListParagraph');
143         while(listpara.length) {
144             this.replaceDocBullet(listpara.item(0));
145             //code
146         }
147     },
148     
149     replaceDocBullet : function(p)
150     {
151         // gather all the siblings.
152         var ns = p,
153             parent = p.parentNode,
154             doc = parent.ownerDocument,
155             items = []; 
156         while (ns) {
157             if (!ns.className.match(/MsoListParagraph/)) {
158                 break;
159             }
160             items.push(ns);
161             ns = ns.nextSibling;
162             
163         }
164         var ul = parent.ownerDocument.createElement('ul'); // what about number lists...
165         parent.insertBefore(ul, p);
166         var lvl = 0;
167         var stack = [ ul ];
168         var last_li = false;
169         items.forEach(function(n) {
170             parent.removeChild(n);
171             var spans = n.getElementsByTagName('span');
172             n.removeChild(spans.item(0)); // remove the fake bullet.
173             var style = this.styleToObject(n);
174             var nlvl = (style['mso-list'].split(' ')[1].replace(/level/,'') *1) - 1;
175             if (nlvl > lvl) {
176                 new indent
177                 var nul = doc.createElement('ul'); // what about number lists...
178                 last_li.appendChild(nul);
179                 stack[nlvl] = nul;
180             }
181             
182             var nli = stack[nlvl].appendChild('li');
183             last_li = nli;
184             // copy children of p into nli
185             while(p.firstChild) {
186                 var fc = p.firstChild;
187                 p.removeChild(fc);
188                 nli.appendChild(fc);
189             }
190              
191             
192         },this);
193         
194         
195         
196         
197     }
198     
199     
200     
201 });