1b1e9fe9311d27cce4d6264509011bed22eea4f0
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / DefaultClean / default-clean.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2008-2011 Stanislas Rolland <typo3(arobas)sjbr.ca>
5 * All rights reserved
6 *
7 * This script is part of the TYPO3 project. The TYPO3 project is
8 * free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The GNU General Public License can be found at
14 * http://www.gnu.org/copyleft/gpl.html.
15 * A copy is found in the textfile GPL.txt and important notices to the license
16 * from the author is found in LICENSE.txt distributed with these scripts.
17 *
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26 /**
27 * Default Clean Plugin for TYPO3 htmlArea RTE
28 */
29 HTMLArea.DefaultClean = Ext.extend(HTMLArea.Plugin, {
30 /*
31 * This function gets called by the class constructor
32 */
33 configurePlugin: function(editor) {
34 this.pageTSConfiguration = this.editorConfiguration.buttons.cleanword;
35 /*
36 * Registering plugin "About" information
37 */
38 var pluginInformation = {
39 version : '2.2',
40 developer : 'Stanislas Rolland',
41 developerUrl : 'http://www.sjbr.ca/',
42 copyrightOwner : 'Stanislas Rolland',
43 sponsor : 'SJBR',
44 sponsorUrl : 'http://www.sjbr.ca/',
45 license : 'GPL'
46 };
47 this.registerPluginInformation(pluginInformation);
48 /*
49 * Registering the (hidden) button
50 */
51 var buttonId = 'CleanWord';
52 var buttonConfiguration = {
53 id : buttonId,
54 tooltip : this.localize(buttonId + '-Tooltip'),
55 action : 'onButtonPress',
56 hide : true,
57 hideInContextMenu: true
58 };
59 this.registerButton(buttonConfiguration);
60 },
61 /*
62 * This function gets called when the button was pressed.
63 *
64 * @param object editor: the editor instance
65 * @param string id: the button id or the key
66 *
67 * @return boolean false if action is completed
68 */
69 onButtonPress: function (editor, id, target) {
70 // Could be a button or its hotkey
71 var buttonId = this.translateHotKey(id);
72 buttonId = buttonId ? buttonId : id;
73 this.clean();
74 return false;
75 },
76 /*
77 * This function gets called when the editor is generated
78 */
79 onGenerate: function () {
80 this.editor.iframe.mon(Ext.get(Ext.isIE ? this.editor.document.body : this.editor.document.documentElement), 'paste', this.wordCleanHandler, this);
81 },
82 /*
83 * This function cleans all nodes in the node tree below the input node
84 *
85 * @param object node: the root of the node tree to clean
86 *
87 * @return void
88 */
89 clean: function () {
90 function clearClass(node) {
91 var newc = node.className.replace(/(^|\s)mso.*?(\s|$)/ig,' ');
92 if (newc != node.className) {
93 node.className = newc;
94 if (!/\S/.test(node.className)) {
95 if (!Ext.isOpera) {
96 node.removeAttribute('class');
97 if (Ext.isIE) {
98 node.removeAttribute('className');
99 }
100 } else {
101 node.className = '';
102 }
103 }
104 }
105 }
106 function clearStyle(node) {
107 var style = Ext.isIE ? node.style.cssText : node.getAttribute('style');
108 if (style) {
109 var declarations = style.split(/\s*;\s*/);
110 for (var i = declarations.length; --i >= 0;) {
111 if (/^mso|^tab-stops/i.test(declarations[i]) || /^margin\s*:\s*0..\s+0..\s+0../i.test(declarations[i])) {
112 declarations.splice(i, 1);
113 }
114 }
115 node.setAttribute('style', declarations.join('; '));
116 }
117 }
118 function stripTag(el) {
119 if (Ext.isIE) {
120 el.outerHTML = HTMLArea.util.htmlEncode(el.innerText);
121 } else {
122 var txt = document.createTextNode(HTMLArea.DOM.getInnerText(el));
123 el.parentNode.insertBefore(txt,el);
124 el.parentNode.removeChild(el);
125 }
126 }
127 function checkEmpty(el) {
128 if (/^(span|b|strong|i|em|font)$/i.test(el.nodeName) && !el.firstChild) {
129 el.parentNode.removeChild(el);
130 }
131 }
132 function parseTree(root) {
133 var tag = root.nodeName.toLowerCase(), next;
134 switch (root.nodeType) {
135 case HTMLArea.DOM.ELEMENT_NODE:
136 if (/^(meta|style|title|link)$/.test(tag)) {
137 root.parentNode.removeChild(root);
138 return false;
139 break;
140 }
141 case HTMLArea.DOM.TEXT_NODE:
142 case HTMLArea.DOM.DOCUMENT_NODE:
143 case HTMLArea.DOM.DOCUMENT_FRAGMENT_NODE:
144 if ((Ext.isIE && root.scopeName != 'HTML') || (!Ext.isIE && /:/.test(tag)) || /o:p/.test(tag)) {
145 stripTag(root);
146 return false;
147 } else {
148 clearClass(root);
149 clearStyle(root);
150 for (var i = root.firstChild; i; i = next) {
151 next = i.nextSibling;
152 if (i.nodeType !== HTMLArea.DOM.TEXT_NODE && parseTree(i)) {
153 checkEmpty(i);
154 }
155 }
156 }
157 return true;
158 break;
159 default:
160 root.parentNode.removeChild(root);
161 return false;
162 break;
163 }
164 }
165 parseTree(this.editor.document.body);
166 if (Ext.isWebKit) {
167 this.editor.getDomNode().cleanAppleStyleSpans(this.editor.document.body);
168 }
169 },
170 /*
171 * Handler for paste, dragdrop and drop events
172 */
173 wordCleanHandler: function (event) {
174 this.clean.defer(250, this);
175 }
176 });