e9fa2a21a6744ab32b55d489751ab50e77384f51
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / DefaultClean / default-clean.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2008-2009 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 * TYPO3 SVN ID: $Id$
30 */
31 DefaultClean = HTMLArea.Plugin.extend({
32
33 constructor : function(editor, pluginName) {
34 this.base(editor, pluginName);
35 },
36
37 /*
38 * This function gets called by the class constructor
39 */
40 configurePlugin : function(editor) {
41
42 this.pageTSConfiguration = this.editorConfiguration.buttons.cleanword;
43
44 /*
45 * Registering plugin "About" information
46 */
47 var pluginInformation = {
48 version : "1.2",
49 developer : "Stanislas Rolland",
50 developerUrl : "http://www.sjbr.ca/",
51 copyrightOwner : "Stanislas Rolland",
52 sponsor : "SJBR",
53 sponsorUrl : "http://www.sjbr.ca/",
54 license : "GPL"
55 };
56 this.registerPluginInformation(pluginInformation);
57
58 /*
59 * Registering the (hidden) button
60 */
61 var buttonId = "CleanWord";
62 var buttonConfiguration = {
63 id : buttonId,
64 tooltip : this.localize(buttonId + "-Tooltip"),
65 action : "onButtonPress",
66 hide : true
67 };
68 this.registerButton(buttonConfiguration);
69 },
70
71 /*
72 * This function gets called when the button was pressed.
73 *
74 * @param object editor: the editor instance
75 * @param string id: the button id or the key
76 *
77 * @return boolean false if action is completed
78 */
79 onButtonPress : function (editor, id, target) {
80 // Could be a button or its hotkey
81 var buttonId = this.translateHotKey(id);
82 buttonId = buttonId ? buttonId : id;
83
84 this.clean();
85 return false;
86 },
87
88 onGenerate : function () {
89 var doc = this.editor._doc;
90 // Function reference used on paste with older versions of Mozilla/Firefox in which onPaste is not fired
91 this.cleanLaterFunctRef = this.makeFunctionReference("clean");
92 HTMLArea._addEvents((HTMLArea.is_ie ? doc.body : doc), ["paste","dragdrop","drop"], DefaultClean.wordCleanHandler, true);
93 },
94
95 clean : function () {
96 function clearClass(node) {
97 var newc = node.className.replace(/(^|\s)mso.*?(\s|$)/ig,' ');
98 if(newc != node.className) {
99 node.className = newc;
100 if(!/\S/.test(node.className)) node.removeAttribute("className");
101 }
102 }
103 function clearStyle(node) {
104 if (HTMLArea.is_ie) var style = node.style.cssText;
105 else var style = node.getAttribute("style");
106 if (style) {
107 var declarations = style.split(/\s*;\s*/);
108 for (var i = declarations.length; --i >= 0;) {
109 if(/^mso|^tab-stops/i.test(declarations[i]) || /^margin\s*:\s*0..\s+0..\s+0../i.test(declarations[i])) declarations.splice(i,1);
110 }
111 node.setAttribute("style", declarations.join("; "));
112 }
113 }
114 function stripTag(el) {
115 if(HTMLArea.is_ie) {
116 el.outerHTML = HTMLArea.htmlEncode(el.innerText);
117 } else {
118 var txt = document.createTextNode(HTMLArea.getInnerText(el));
119 el.parentNode.insertBefore(txt,el);
120 el.parentNode.removeChild(el);
121 }
122 }
123 function checkEmpty(el) {
124 if(/^(span|b|strong|i|em|font)$/i.test(el.nodeName) && !el.firstChild) el.parentNode.removeChild(el);
125 }
126 function parseTree(root) {
127 var tag = root.nodeName.toLowerCase(), next;
128 switch (root.nodeType) {
129 case 1:
130 if (/^(meta|style|title|link)$/.test(tag)) {
131 root.parentNode.removeChild(root);
132 return false;
133 break;
134 }
135 case 3:
136 case 9:
137 case 11:
138 if ((HTMLArea.is_ie && root.scopeName != 'HTML') || (!HTMLArea.is_ie && /:/.test(tag)) || /o:p/.test(tag)) {
139 stripTag(root);
140 return false;
141 } else {
142 clearClass(root);
143 clearStyle(root);
144 for (var i=root.firstChild;i;i=next) {
145 next = i.nextSibling;
146 if (i.nodeType != 3 && parseTree(i)) { checkEmpty(i); }
147 }
148 }
149 return true;
150 break;
151 default:
152 root.parentNode.removeChild(root);
153 return false;
154 break;
155 }
156 }
157 parseTree(this.editor._doc.body);
158 }
159 });
160
161 /*
162 * Closure avoidance for IE
163 */
164 DefaultClean.cleanLater = function (editorNumber) {
165 var editor = RTEarea[editorNumber].editor;
166 editor.getPluginInstance("Default").clean();
167 };
168
169 /*
170 * Handler for paste, dragdrop and drop events
171 */
172 DefaultClean.wordCleanHandler = function (ev) {
173 if (!ev) var ev = window.event;
174 var target = ev.target ? ev.target : ev.srcElement;
175 var owner = target.ownerDocument ? target.ownerDocument : target;
176 if (HTMLArea.is_ie) { // IE5.5 does not report any ownerDocument
177 while (owner.parentElement) { owner = owner.parentElement; }
178 }
179 var editor = RTEarea[owner._editorNo].editor;
180
181 // If we dropped an image dragged from the TYPO3 Image plugin, let's close the dialog window
182 if (typeof(HTMLArea.Dialog) != "undefined" && HTMLArea.Dialog.TYPO3Image) {
183 HTMLArea.Dialog.TYPO3Image.close();
184 } else {
185 window.setTimeout("DefaultClean.cleanLater(\'" + editor._editorNumber + "\');", 250);
186 }
187 };
188