webcit_before_automake is now the trunk
[citadel.git] / webcit / tiny_mce / tiny_mce_src.js
1 /**\r
2  * $RCSfile: tiny_mce_src.js,v $\r
3  * $Revision: 1.281 $\r
4  * $Date: 2005/12/02 08:12:07 $\r
5  *\r
6  * @author Moxiecode\r
7  * @copyright Copyright © 2004, Moxiecode Systems AB, All rights reserved.\r
8  */\r
9 \r
10 function TinyMCE() {\r
11         this.majorVersion = "2";\r
12         this.minorVersion = "0";\r
13         this.releaseDate = "2005-12-01";\r
14 \r
15         this.instances = new Array();\r
16         this.stickyClassesLookup = new Array();\r
17         this.windowArgs = new Array();\r
18         this.loadedFiles = new Array();\r
19         this.configs = new Array();\r
20         this.currentConfig = 0;\r
21         this.eventHandlers = new Array();\r
22 \r
23         // Browser check\r
24         var ua = navigator.userAgent;\r
25         this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");\r
26         this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);\r
27         this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);\r
28         this.isGecko = ua.indexOf('Gecko') != -1;\r
29         this.isSafari = ua.indexOf('Safari') != -1;\r
30         this.isOpera = ua.indexOf('Opera') != -1;\r
31         this.isMac = ua.indexOf('Mac') != -1;\r
32         this.isNS7 = ua.indexOf('Netscape/7') != -1;\r
33         this.isNS71 = ua.indexOf('Netscape/7.1') != -1;\r
34         this.dialogCounter = 0;\r
35 \r
36         // Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those\r
37         if (this.isOpera) {\r
38                 this.isMSIE = true;\r
39                 this.isGecko = false;\r
40                 this.isSafari =  false;\r
41         }\r
42 \r
43         // TinyMCE editor id instance counter\r
44         this.idCounter = 0;\r
45 };\r
46 \r
47 TinyMCE.prototype.defParam = function(key, def_val) {\r
48         this.settings[key] = tinyMCE.getParam(key, def_val);\r
49 };\r
50 \r
51 TinyMCE.prototype.init = function(settings) {\r
52         var theme;\r
53 \r
54         this.settings = settings;\r
55 \r
56         // Check if valid browser has execcommand support\r
57         if (typeof(document.execCommand) == 'undefined')\r
58                 return;\r
59 \r
60         // Get script base path\r
61         if (!tinyMCE.baseURL) {\r
62                 var elements = document.getElementsByTagName('script');\r
63 \r
64                 for (var i=0; i<elements.length; i++) {\r
65                         if (elements[i].src && (elements[i].src.indexOf("tiny_mce.js") != -1 || elements[i].src.indexOf("tiny_mce_src.js") != -1 || elements[i].src.indexOf("tiny_mce_gzip") != -1)) {\r
66                                 var src = elements[i].src;\r
67 \r
68                                 tinyMCE.srcMode = (src.indexOf('_src') != -1) ? '_src' : '';\r
69                                 src = src.substring(0, src.lastIndexOf('/'));\r
70 \r
71                                 tinyMCE.baseURL = src;\r
72                                 break;\r
73                         }\r
74                 }\r
75         }\r
76 \r
77         // Get document base path\r
78         this.documentBasePath = document.location.href;\r
79         if (this.documentBasePath.indexOf('?') != -1)\r
80                 this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));\r
81         this.documentURL = this.documentBasePath;\r
82         this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));\r
83 \r
84         // If not HTTP absolute\r
85         if (tinyMCE.baseURL.indexOf('://') == -1 && tinyMCE.baseURL.charAt(0) != '/') {\r
86                 // If site absolute\r
87                 tinyMCE.baseURL = this.documentBasePath + "/" + tinyMCE.baseURL;\r
88         }\r
89 \r
90         // Set default values on settings\r
91         this.defParam("mode", "none");\r
92         this.defParam("theme", "advanced");\r
93         this.defParam("plugins", "", true);\r
94         this.defParam("language", "en");\r
95         this.defParam("docs_language", this.settings['language']);\r
96         this.defParam("elements", "");\r
97         this.defParam("textarea_trigger", "mce_editable");\r
98         this.defParam("editor_selector", "");\r
99         this.defParam("editor_deselector", "mceNoEditor");\r
100         this.defParam("valid_elements", "+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/b[class|style],-em/i[class|style],-strike[class|style],-u[class|style],+p[style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border=0|alt|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],-td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[style|dir|class|align],-h2[style|dir|class|align],-h3[style|dir|class|align],-h4[style|dir|class|align],-h5[style|dir|class|align],-h6[style|dir|class|align],hr[class|style],font[face|size|style|id|class|dir|color]");\r
101         this.defParam("extended_valid_elements", "");\r
102         this.defParam("invalid_elements", "");\r
103         this.defParam("encoding", "");\r
104         this.defParam("urlconverter_callback", tinyMCE.getParam("urlconvertor_callback", "TinyMCE.prototype.convertURL"));\r
105         this.defParam("save_callback", "");\r
106         this.defParam("debug", false);\r
107         this.defParam("force_br_newlines", false);\r
108         this.defParam("force_p_newlines", true);\r
109         this.defParam("add_form_submit_trigger", true);\r
110         this.defParam("relative_urls", true);\r
111         this.defParam("remove_script_host", true);\r
112         this.defParam("focus_alert", true);\r
113         this.defParam("document_base_url", this.documentURL);\r
114         this.defParam("visual", true);\r
115         this.defParam("visual_table_class", "mceVisualAid");\r
116         this.defParam("setupcontent_callback", "");\r
117         this.defParam("fix_content_duplication", true);\r
118         this.defParam("custom_undo_redo", true);\r
119         this.defParam("custom_undo_redo_levels", -1);\r
120         this.defParam("custom_undo_redo_keyboard_shortcuts", true);\r
121         this.defParam("verify_css_classes", false);\r
122         this.defParam("verify_html", true);\r
123         this.defParam("apply_source_formatting", false);\r
124         this.defParam("directionality", "ltr");\r
125         this.defParam("cleanup_on_startup", false);\r
126         this.defParam("inline_styles", false);\r
127         this.defParam("convert_newlines_to_brs", false);\r
128         this.defParam("auto_reset_designmode", true);\r
129         this.defParam("entities", "160,nbsp,38,amp,34,quot,162,cent,8364,euro,163,pound,165,yen,169,copy,174,reg,8482,trade,8240,permil,181,micro,183,middot,8226,bull,8230,hellip,8242,prime,8243,Prime,167,sect,182,para,223,szlig,8249,lsaquo,8250,rsaquo,171,laquo,187,raquo,8216,lsquo,8217,rsquo,8220,ldquo,8221,rdquo,8218,sbquo,8222,bdquo,60,lt,62,gt,8804,le,8805,ge,8211,ndash,8212,mdash,175,macr,8254,oline,164,curren,166,brvbar,168,uml,161,iexcl,191,iquest,710,circ,732,tilde,176,deg,8722,minus,177,plusmn,247,divide,8260,frasl,215,times,185,sup1,178,sup2,179,sup3,188,frac14,189,frac12,190,frac34,402,fnof,8747,int,8721,sum,8734,infin,8730,radic,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8712,isin,8713,notin,8715,ni,8719,prod,8743,and,8744,or,172,not,8745,cap,8746,cup,8706,part,8704,forall,8707,exist,8709,empty,8711,nabla,8727,lowast,8733,prop,8736,ang,180,acute,184,cedil,170,ordf,186,ordm,8224,dagger,8225,Dagger,192,Agrave,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,202,Ecirc,203,Euml,204,Igrave,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,212,Ocirc,213,Otilde,214,Ouml,216,Oslash,338,OElig,217,Ugrave,219,Ucirc,220,Uuml,376,Yuml,222,THORN,224,agrave,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,234,ecirc,235,euml,236,igrave,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,244,ocirc,245,otilde,246,ouml,248,oslash,339,oelig,249,ugrave,251,ucirc,252,uuml,254,thorn,255,yuml,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,8501,alefsym,982,piv,8476,real,977,thetasym,978,upsih,8472,weierp,8465,image,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8756,there4,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,173,shy,233,eacute,237,iacute,243,oacute,250,uacute,193,Aacute,225,aacute,201,Eacute,205,Iacute,211,Oacute,218,Uacute,221,Yacute,253,yacute");\r
130         this.defParam("entity_encoding", "named");\r
131         this.defParam("cleanup_callback", "");\r
132         this.defParam("add_unload_trigger", true);\r
133         this.defParam("ask", false);\r
134         this.defParam("nowrap", false);\r
135         this.defParam("auto_resize", false);\r
136         this.defParam("auto_focus", false);\r
137         this.defParam("cleanup", true);\r
138         this.defParam("remove_linebreaks", true);\r
139         this.defParam("button_tile_map", false);\r
140         this.defParam("submit_patch", true);\r
141         this.defParam("browsers", "msie,safari,gecko,opera");\r
142         this.defParam("dialog_type", "window");\r
143         this.defParam("accessibility_warnings", true);\r
144         this.defParam("merge_styles_invalid_parents", "");\r
145         this.defParam("force_hex_style_colors", true);\r
146         this.defParam("trim_span_elements", true);\r
147         this.defParam("convert_fonts_to_spans", false);\r
148         this.defParam("doctype", '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');\r
149         this.defParam("font_size_classes", '');\r
150         this.defParam("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large');\r
151         this.defParam("event_elements", 'a,img');\r
152         this.defParam("convert_urls", true);\r
153         this.defParam("table_inline_editing", false);\r
154         this.defParam("object_resizing", true);\r
155 \r
156         // Browser check IE\r
157         if (this.isMSIE && this.settings['browsers'].indexOf('msie') == -1)\r
158                 return;\r
159 \r
160         // Browser check Gecko\r
161         if (this.isGecko && this.settings['browsers'].indexOf('gecko') == -1)\r
162                 return;\r
163 \r
164         // Browser check Safari\r
165         if (this.isSafari && this.settings['browsers'].indexOf('safari') == -1)\r
166                 return;\r
167 \r
168         // Browser check Opera\r
169         if (this.isOpera && this.settings['browsers'].indexOf('opera') == -1)\r
170                 return;\r
171 \r
172         // If not super absolute make it so\r
173         var baseHREF = tinyMCE.settings['document_base_url'];\r
174         var h = document.location.href;\r
175         var p = h.indexOf('://');\r
176         if (p > 0 && document.location.protocol != "file:") {\r
177                 p = h.indexOf('/', p + 3);\r
178                 h = h.substring(0, p);\r
179 \r
180                 if (baseHREF.indexOf('://') == -1)\r
181                         baseHREF = h + baseHREF;\r
182 \r
183                 tinyMCE.settings['document_base_url'] = baseHREF;\r
184                 tinyMCE.settings['document_base_prefix'] = h;\r
185         }\r
186 \r
187         // Trim away query part\r
188         if (baseHREF.indexOf('?') != -1)\r
189                 baseHREF = baseHREF.substring(0, baseHREF.indexOf('?'));\r
190 \r
191         this.settings['base_href'] = baseHREF.substring(0, baseHREF.lastIndexOf('/')) + "/";\r
192 \r
193         theme = this.settings['theme'];\r
194         this.blockRegExp = new RegExp("^(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|blockquote|center|dl|dir|fieldset|form|noscript|noframes|menu|isindex)$", "i");\r
195         this.posKeyCodes = new Array(13,45,36,35,33,34,37,38,39,40);\r
196         this.uniqueURL = 'http://tinymce.moxiecode.cp/mce_temp_url'; // Make unique URL non real URL\r
197         this.uniqueTag = '<div id="mceTMPElement" style="display: none">TMP</div>';\r
198 \r
199         // Theme url\r
200         this.settings['theme_href'] = tinyMCE.baseURL + "/themes/" + theme;\r
201 \r
202         if (!tinyMCE.isMSIE)\r
203                 this.settings['force_br_newlines'] = false;\r
204 \r
205         if (tinyMCE.getParam("content_css", false)) {\r
206                 var cssPath = tinyMCE.getParam("content_css", "");\r
207 \r
208                 // Is relative\r
209                 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')\r
210                         this.settings['content_css'] = this.documentBasePath + "/" + cssPath;\r
211                 else\r
212                         this.settings['content_css'] = cssPath;\r
213         } else\r
214                 this.settings['content_css'] = '';\r
215 \r
216         if (tinyMCE.getParam("popups_css", false)) {\r
217                 var cssPath = tinyMCE.getParam("popups_css", "");\r
218 \r
219                 // Is relative\r
220                 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')\r
221                         this.settings['popups_css'] = this.documentBasePath + "/" + cssPath;\r
222                 else\r
223                         this.settings['popups_css'] = cssPath;\r
224         } else\r
225                 this.settings['popups_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css";\r
226 \r
227         if (tinyMCE.getParam("editor_css", false)) {\r
228                 var cssPath = tinyMCE.getParam("editor_css", "");\r
229 \r
230                 // Is relative\r
231                 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')\r
232                         this.settings['editor_css'] = this.documentBasePath + "/" + cssPath;\r
233                 else\r
234                         this.settings['editor_css'] = cssPath;\r
235         } else\r
236                 this.settings['editor_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css";\r
237 \r
238         if (tinyMCE.settings['debug']) {\r
239                 var msg = "Debug: \n";\r
240 \r
241                 msg += "baseURL: " + this.baseURL + "\n";\r
242                 msg += "documentBasePath: " + this.documentBasePath + "\n";\r
243                 msg += "content_css: " + this.settings['content_css'] + "\n";\r
244                 msg += "popups_css: " + this.settings['popups_css'] + "\n";\r
245                 msg += "editor_css: " + this.settings['editor_css'] + "\n";\r
246 \r
247                 alert(msg);\r
248         }\r
249 \r
250         // Init HTML cleanup\r
251         this._initCleanup();\r
252 \r
253         // Only do this once\r
254         if (this.configs.length == 0) {\r
255                 // Is Safari enabled\r
256                 if (this.isSafari && this.getParam('safari_warning', true))\r
257                         alert("Safari support is very limited and should be considered experimental.\nSo there is no need to even submit bugreports on this early version.\nYou can disable this message by setting: safari_warning option to false");\r
258 \r
259                 tinyMCE.addEvent(window, "load", TinyMCE.prototype.onLoad);\r
260 \r
261                 if (tinyMCE.isMSIE) {\r
262                         if (tinyMCE.settings['add_unload_trigger']) {\r
263                                 tinyMCE.addEvent(window, "unload", TinyMCE.prototype.unloadHandler);\r
264                                 tinyMCE.addEvent(window.document, "beforeunload", TinyMCE.prototype.unloadHandler);\r
265                         }\r
266                 } else {\r
267                         if (tinyMCE.settings['add_unload_trigger'])\r
268                                 tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);});\r
269                 }\r
270         }\r
271 \r
272         this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings['theme'] + '/editor_template' + tinyMCE.srcMode + '.js');\r
273         this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings['language'] +  '.js');\r
274         this.loadCSS(this.settings['editor_css']);\r
275 \r
276         // Add plugins\r
277         var themePlugins = tinyMCE.getParam('plugins', '', true, ',');\r
278         if (this.settings['plugins'] != '') {\r
279                 for (var i=0; i<themePlugins.length; i++)\r
280                         this.loadScript(tinyMCE.baseURL + '/plugins/' + themePlugins[i] + '/editor_plugin' + tinyMCE.srcMode + '.js');\r
281         }\r
282 \r
283         // Setup entities\r
284         settings['cleanup_entities'] = new Array();\r
285         var entities = tinyMCE.getParam('entities', '', true, ',');\r
286         for (var i=0; i<entities.length; i+=2)\r
287                 settings['cleanup_entities']['c' + entities[i]] = entities[i+1];\r
288 \r
289         // Save away this config\r
290         settings['index'] = this.configs.length;\r
291         this.configs[this.configs.length] = settings;\r
292 };\r
293 \r
294 TinyMCE.prototype.loadScript = function(url) {\r
295         for (var i=0; i<this.loadedFiles.length; i++) {\r
296                 if (this.loadedFiles[i] == url)\r
297                         return;\r
298         }\r
299 \r
300         document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></script>');\r
301 \r
302         this.loadedFiles[this.loadedFiles.length] = url;\r
303 };\r
304 \r
305 TinyMCE.prototype.loadCSS = function(url) {\r
306         for (var i=0; i<this.loadedFiles.length; i++) {\r
307                 if (this.loadedFiles[i] == url)\r
308                         return;\r
309         }\r
310 \r
311         document.write('<link href="' + url + '" rel="stylesheet" type="text/css" />');\r
312 \r
313         this.loadedFiles[this.loadedFiles.length] = url;\r
314 };\r
315 \r
316 TinyMCE.prototype.importCSS = function(doc, css_file) {\r
317         if (css_file == '')\r
318                 return;\r
319 \r
320         if (typeof(doc.createStyleSheet) == "undefined") {\r
321                 var elm = doc.createElement("link");\r
322 \r
323                 elm.rel = "stylesheet";\r
324                 elm.href = css_file;\r
325 \r
326                 if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0)\r
327                         headArr[0].appendChild(elm);\r
328         } else\r
329                 var styleSheet = doc.createStyleSheet(css_file);\r
330 };\r
331 \r
332 TinyMCE.prototype.confirmAdd = function(e, settings) {\r
333         var elm = tinyMCE.isMSIE ? event.srcElement : e.target;\r
334         var elementId = elm.name ? elm.name : elm.id;\r
335 \r
336         tinyMCE.settings = settings;\r
337 \r
338         if (!elm.getAttribute('mce_noask') && confirm(tinyMCELang['lang_edit_confirm']))\r
339                 tinyMCE.addMCEControl(elm, elementId);\r
340 \r
341         elm.setAttribute('mce_noask', 'true');\r
342 };\r
343 \r
344 TinyMCE.prototype.updateContent = function(form_element_name) {\r
345         // Find MCE instance linked to given form element and copy it's value\r
346         var formElement = document.getElementById(form_element_name);\r
347         for (var n in tinyMCE.instances) {\r
348                 var inst = tinyMCE.instances[n];\r
349                 if (!tinyMCE.isInstance(inst))\r
350                         continue;\r
351 \r
352                 inst.switchSettings();\r
353 \r
354                 if (inst.formElement == formElement) {\r
355                         var doc = inst.getDoc();\r
356         \r
357                         tinyMCE._setHTML(doc, inst.formElement.value);\r
358 \r
359                         if (!tinyMCE.isMSIE)\r
360                                 doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);\r
361                 }\r
362         }\r
363 };\r
364 \r
365 TinyMCE.prototype.addMCEControl = function(replace_element, form_element_name, target_document) {\r
366         var id = "mce_editor_" + tinyMCE.idCounter++;\r
367         var inst = new TinyMCEControl(tinyMCE.settings);\r
368 \r
369         inst.editorId = id;\r
370         this.instances[id] = inst;\r
371 \r
372         inst.onAdd(replace_element, form_element_name, target_document);\r
373 };\r
374 \r
375 TinyMCE.prototype.triggerSave = function(skip_cleanup, skip_callback) {\r
376         // Cleanup and set all form fields\r
377         for (var n in tinyMCE.instances) {\r
378                 var inst = tinyMCE.instances[n];\r
379                 if (!tinyMCE.isInstance(inst))\r
380                         continue;\r
381 \r
382                 inst.switchSettings();\r
383 \r
384                 tinyMCE.settings['preformatted'] = false;\r
385 \r
386                 // Default to false\r
387                 if (typeof(skip_cleanup) == "undefined")\r
388                         skip_cleanup = false;\r
389 \r
390                 // Default to false\r
391                 if (typeof(skip_callback) == "undefined")\r
392                         skip_callback = false;\r
393 \r
394                 tinyMCE._setHTML(inst.getDoc(), inst.getBody().innerHTML);\r
395 \r
396                 // Remove visual aids when cleanup is disabled\r
397                 if (inst.settings['cleanup'] == false) {\r
398                         tinyMCE.handleVisualAid(inst.getBody(), true, false, inst);\r
399                         tinyMCE._setEventsEnabled(inst.getBody(), true);\r
400                 }\r
401 \r
402                 tinyMCE._customCleanup(inst, "submit_content_dom", inst.contentWindow.document.body);\r
403                 var htm = skip_cleanup ? inst.getBody().innerHTML : tinyMCE._cleanupHTML(inst, inst.getDoc(), this.settings, inst.getBody(), this.visualAid, true);\r
404                 htm = tinyMCE._customCleanup(inst, "submit_content", htm);\r
405 \r
406                 if (tinyMCE.settings["encoding"] == "xml" || tinyMCE.settings["encoding"] == "html")\r
407                         htm = tinyMCE.convertStringToXML(htm);\r
408 \r
409                 if (!skip_callback && tinyMCE.settings['save_callback'] != "")\r
410                         var content = eval(tinyMCE.settings['save_callback'] + "(inst.formTargetElementId,htm,inst.getBody());");\r
411 \r
412                 // Use callback content if available\r
413                 if ((typeof(content) != "undefined") && content != null)\r
414                         htm = content;\r
415 \r
416                 // Replace some weird entities (Bug: #1056343)\r
417                 htm = tinyMCE.regexpReplace(htm, "&#40;", "(", "gi");\r
418                 htm = tinyMCE.regexpReplace(htm, "&#41;", ")", "gi");\r
419                 htm = tinyMCE.regexpReplace(htm, "&#59;", ";", "gi");\r
420                 htm = tinyMCE.regexpReplace(htm, "&#34;", "&quot;", "gi");\r
421                 htm = tinyMCE.regexpReplace(htm, "&#94;", "^", "gi");\r
422 \r
423                 if (inst.formElement)\r
424                         inst.formElement.value = htm;\r
425         }\r
426 };\r
427 \r
428 TinyMCE.prototype._setEventsEnabled = function(node, state) {\r
429         var events = new Array('onfocus','onblur','onclick','ondblclick',\r
430                                 'onmousedown','onmouseup','onmouseover','onmousemove',\r
431                                 'onmouseout','onkeypress','onkeydown','onkeydown','onkeyup');\r
432 \r
433         var evs = tinyMCE.settings['event_elements'].split(',');\r
434     for (var y=0; y<evs.length; y++){\r
435                 var elms = node.getElementsByTagName(evs[y]);\r
436                 for (var i=0; i<elms.length; i++) {\r
437                         var event = "";\r
438 \r
439                         for (var x=0; x<events.length; x++) {\r
440                                 if ((event = tinyMCE.getAttrib(elms[i], events[x])) != '') {\r
441                                         event = tinyMCE.cleanupEventStr("" + event);\r
442 \r
443                                         if (!state)\r
444                                                 event = "return true;" + event;\r
445                                         else\r
446                                                 event = event.replace(/^return true;/gi, '');\r
447 \r
448                                         elms[i].removeAttribute(events[x]);\r
449                                         elms[i].setAttribute(events[x], event);\r
450                                 }\r
451                         }\r
452                 }\r
453         }\r
454 };\r
455 \r
456 TinyMCE.prototype.resetForm = function(form_index) {\r
457         var formObj = document.forms[form_index];\r
458 \r
459         for (var n in tinyMCE.instances) {\r
460                 var inst = tinyMCE.instances[n];\r
461                 if (!tinyMCE.isInstance(inst))\r
462                         continue;\r
463 \r
464                 inst.switchSettings();\r
465 \r
466                 for (var i=0; i<formObj.elements.length; i++) {\r
467                         if (inst.formTargetElementId == formObj.elements[i].name)\r
468                                 inst.getBody().innerHTML = inst.startContent;\r
469                 }\r
470         }\r
471 };\r
472 \r
473 TinyMCE.prototype.execInstanceCommand = function(editor_id, command, user_interface, value, focus) {\r
474         var inst = tinyMCE.getInstanceById(editor_id);\r
475         if (inst) {\r
476                 if (typeof(focus) == "undefined")\r
477                         focus = true;\r
478 \r
479                 if (focus)\r
480                         inst.contentWindow.focus();\r
481 \r
482                 // Reset design mode if lost\r
483                 inst.autoResetDesignMode();\r
484 \r
485                 this.selectedElement = inst.getFocusElement();\r
486                 this.selectedInstance = inst;\r
487                 tinyMCE.execCommand(command, user_interface, value);\r
488 \r
489                 // Cancel event so it doesn't call onbeforeonunlaod\r
490                 if (tinyMCE.isMSIE && window.event != null)\r
491                         tinyMCE.cancelEvent(window.event);\r
492         }\r
493 };\r
494 \r
495 TinyMCE.prototype.execCommand = function(command, user_interface, value) {\r
496         // Default input\r
497         user_interface = user_interface ? user_interface : false;\r
498         value = value ? value : null;\r
499 \r
500         if (tinyMCE.selectedInstance)\r
501                 tinyMCE.selectedInstance.switchSettings();\r
502 \r
503         switch (command) {\r
504                 case 'mceHelp':\r
505                         var template = new Array();\r
506 \r
507                         template['file']   = 'about.htm';\r
508                         template['width']  = 480;\r
509                         template['height'] = 380;\r
510 \r
511                         tinyMCE.openWindow(template, {\r
512                                 tinymce_version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion,\r
513                                 tinymce_releasedate : tinyMCE.releaseDate,\r
514                                 inline : "yes"\r
515                         });\r
516                 return;\r
517 \r
518                 case 'mceFocus':\r
519                         var inst = tinyMCE.getInstanceById(value);\r
520                         if (inst)\r
521                                 inst.contentWindow.focus();\r
522                 return;\r
523 \r
524                 case "mceAddControl":\r
525                 case "mceAddEditor":\r
526                         tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);\r
527                         return;\r
528 \r
529                 case "mceAddFrameControl":\r
530                         tinyMCE.addMCEControl(tinyMCE._getElementById(value), value['element'], value['document']);\r
531                         return;\r
532 \r
533                 case "mceRemoveControl":\r
534                 case "mceRemoveEditor":\r
535                         tinyMCE.removeMCEControl(value);\r
536                         return;\r
537 \r
538                 case "mceResetDesignMode":\r
539                         // Resets the designmode state of the editors in Gecko\r
540                         if (!tinyMCE.isMSIE) {\r
541                                 for (var n in tinyMCE.instances) {\r
542                                         if (!tinyMCE.isInstance(tinyMCE.instances[n]))\r
543                                                 continue;\r
544 \r
545                                         try {\r
546                                                 tinyMCE.instances[n].getDoc().designMode = "on";\r
547                                         } catch (e) {\r
548                                                 // Ignore any errors\r
549                                         }\r
550                                 }\r
551                         }\r
552 \r
553                         return;\r
554         }\r
555 \r
556         if (this.selectedInstance) {\r
557                 this.selectedInstance.execCommand(command, user_interface, value);\r
558         } else if (tinyMCE.settings['focus_alert'])\r
559                 alert(tinyMCELang['lang_focus_alert']);\r
560 };\r
561 \r
562 TinyMCE.prototype.eventPatch = function(editor_id) {\r
563         // Remove odd, error\r
564         if (typeof(tinyMCE) == "undefined")\r
565                 return true;\r
566 \r
567         for (var i=0; i<document.frames.length; i++) {\r
568                 try {\r
569                         if (document.frames[i].event) {\r
570                                 var event = document.frames[i].event;\r
571 \r
572                                 if (!event.target)\r
573                                         event.target = event.srcElement;\r
574 \r
575                                 TinyMCE.prototype.handleEvent(event);\r
576                                 return;\r
577                         }\r
578                 } catch (ex) {\r
579                         // Ignore error if iframe is pointing to external URL\r
580                 }\r
581         }\r
582 };\r
583 \r
584 TinyMCE.prototype.unloadHandler = function() {\r
585         tinyMCE.triggerSave(true, true);\r
586 };\r
587 \r
588 TinyMCE.prototype.addEventHandlers = function(editor_id) {\r
589         if (tinyMCE.isMSIE) {\r
590                 var doc = document.frames[editor_id].document;\r
591 \r
592                 // Event patch\r
593                 tinyMCE.addEvent(doc, "keypress", TinyMCE.prototype.eventPatch);\r
594                 tinyMCE.addEvent(doc, "keyup", TinyMCE.prototype.eventPatch);\r
595                 tinyMCE.addEvent(doc, "keydown", TinyMCE.prototype.eventPatch);\r
596                 tinyMCE.addEvent(doc, "mouseup", TinyMCE.prototype.eventPatch);\r
597                 tinyMCE.addEvent(doc, "click", TinyMCE.prototype.eventPatch);\r
598         } else {\r
599                 var inst = tinyMCE.instances[editor_id];\r
600                 var doc = inst.getDoc();\r
601 \r
602                 inst.switchSettings();\r
603 \r
604                 tinyMCE.addEvent(doc, "keypress", tinyMCE.handleEvent);\r
605                 tinyMCE.addEvent(doc, "keydown", tinyMCE.handleEvent);\r
606                 tinyMCE.addEvent(doc, "keyup", tinyMCE.handleEvent);\r
607                 tinyMCE.addEvent(doc, "click", tinyMCE.handleEvent);\r
608                 tinyMCE.addEvent(doc, "mouseup", tinyMCE.handleEvent);\r
609                 tinyMCE.addEvent(doc, "mousedown", tinyMCE.handleEvent);\r
610                 tinyMCE.addEvent(doc, "focus", tinyMCE.handleEvent);\r
611                 tinyMCE.addEvent(doc, "blur", tinyMCE.handleEvent);\r
612 \r
613                 eval('try { doc.designMode = "On"; } catch(e) {}');\r
614         }\r
615 };\r
616 \r
617 TinyMCE.prototype._createIFrame = function(replace_element) {\r
618         var iframe = document.createElement("iframe");\r
619         var id = replace_element.getAttribute("id");\r
620         var aw, ah;\r
621 \r
622         aw = "" + tinyMCE.settings['area_width'];\r
623         ah = "" + tinyMCE.settings['area_height'];\r
624 \r
625         if (aw.indexOf('%') == -1) {\r
626                 aw = parseInt(aw);\r
627                 aw = aw < 0 ? 300 : aw;\r
628                 aw = aw + "px";\r
629         }\r
630 \r
631         if (ah.indexOf('%') == -1) {\r
632                 ah = parseInt(ah);\r
633                 ah = ah < 0 ? 240 : ah;\r
634                 ah = ah + "px";\r
635         }\r
636 \r
637         iframe.setAttribute("id", id);\r
638         //iframe.setAttribute("className", "mceEditorArea");\r
639         iframe.setAttribute("border", "0");\r
640         iframe.setAttribute("frameBorder", "0");\r
641         iframe.setAttribute("marginWidth", "0");\r
642         iframe.setAttribute("marginHeight", "0");\r
643         iframe.setAttribute("leftMargin", "0");\r
644         iframe.setAttribute("topMargin", "0");\r
645         iframe.setAttribute("width", aw);\r
646         iframe.setAttribute("height", ah);\r
647         iframe.setAttribute("allowtransparency", "true");\r
648 \r
649         if (tinyMCE.settings["auto_resize"])\r
650                 iframe.setAttribute("scrolling", "no");\r
651 \r
652         // Must have a src element in MSIE HTTPs breaks aswell as absoute URLs\r
653         if (tinyMCE.isMSIE && !tinyMCE.isOpera)\r
654                 iframe.setAttribute("src", this.settings['default_document']);\r
655 \r
656         iframe.style.width = aw;\r
657         iframe.style.height = ah;\r
658 \r
659         // MSIE 5.0 issue\r
660         if (tinyMCE.isMSIE && !tinyMCE.isOpera)\r
661                 replace_element.outerHTML = iframe.outerHTML;\r
662         else\r
663                 replace_element.parentNode.replaceChild(iframe, replace_element);\r
664 \r
665         if (tinyMCE.isMSIE)\r
666                 return window.frames[id];\r
667         else\r
668                 return iframe;\r
669 };\r
670 \r
671 TinyMCE.prototype.setupContent = function(editor_id) {\r
672         var inst = tinyMCE.instances[editor_id];\r
673         var doc = inst.getDoc();\r
674         var head = doc.getElementsByTagName('head').item(0);\r
675         var content = inst.startContent;\r
676 \r
677         tinyMCE.operaOpacityCounter = 100 * tinyMCE.idCounter;\r
678 \r
679         inst.switchSettings();\r
680 \r
681         // Not loaded correctly hit it again, Mozilla bug #997860\r
682         if (!tinyMCE.isMSIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") {\r
683                 // This part will remove the designMode status\r
684                 // Failes first time in Firefox 1.5b2 on Mac\r
685                 try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {}\r
686                 window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000);\r
687                 return;\r
688         }\r
689 \r
690         if (!head) {\r
691                 window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10);\r
692                 return;\r
693         }\r
694 \r
695         // Import theme specific content CSS the user specific\r
696         tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings['theme'] + "/css/editor_content.css");\r
697         tinyMCE.importCSS(inst.getDoc(), inst.settings['content_css']);\r
698         tinyMCE.executeCallback('init_instance_callback', '_initInstance', 0, inst);\r
699 \r
700         // Setup span styles\r
701         if (tinyMCE.getParam("convert_fonts_to_spans"))\r
702                 inst.getDoc().body.setAttribute('id', 'mceSpanFonts');\r
703 \r
704         if (tinyMCE.settings['nowrap'])\r
705                 doc.body.style.whiteSpace = "nowrap";\r
706 \r
707         doc.body.dir = this.settings['directionality'];\r
708         doc.editorId = editor_id;\r
709 \r
710         // Add on document element in Mozilla\r
711         if (!tinyMCE.isMSIE)\r
712                 doc.documentElement.editorId = editor_id;\r
713 \r
714         // Setup base element\r
715         var base = doc.createElement("base");\r
716         base.setAttribute('href', tinyMCE.settings['base_href']);\r
717         head.appendChild(base);\r
718 \r
719         // Replace new line characters to BRs\r
720         if (tinyMCE.settings['convert_newlines_to_brs']) {\r
721                 content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi");\r
722                 content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi");\r
723                 content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi");\r
724         }\r
725 \r
726         // Open closed anchors\r
727 //      content = content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');\r
728 \r
729         // Call custom cleanup code\r
730         content = tinyMCE.storeAwayURLs(content);\r
731         content = tinyMCE._customCleanup(inst, "insert_to_editor", content);\r
732 \r
733         if (tinyMCE.isMSIE) {\r
734                 // Ugly!!!\r
735                 window.setInterval('try{tinyMCE.getCSSClasses(document.frames["' + editor_id + '"].document, "' + editor_id + '");}catch(e){}', 500);\r
736 \r
737                 if (tinyMCE.settings["force_br_newlines"])\r
738                         document.frames[editor_id].document.styleSheets[0].addRule("p", "margin: 0px;");\r
739 \r
740                 var body = document.frames[editor_id].document.body;\r
741 \r
742                 tinyMCE.addEvent(body, "beforepaste", TinyMCE.prototype.eventPatch);\r
743                 tinyMCE.addEvent(body, "beforecut", TinyMCE.prototype.eventPatch);\r
744 \r
745                 body.editorId = editor_id;\r
746         }\r
747 \r
748         content = tinyMCE.cleanupHTMLCode(content);\r
749 \r
750         // Fix for bug #958637\r
751         if (!tinyMCE.isMSIE) {\r
752                 var contentElement = inst.getDoc().createElement("body");\r
753                 var doc = inst.getDoc();\r
754 \r
755                 contentElement.innerHTML = content;\r
756 \r
757                 // Remove weridness!\r
758                 if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt'])\r
759                         content = content.replace(new RegExp('&lt;&gt;', 'g'), "");\r
760 \r
761                 if (tinyMCE.settings['cleanup_on_startup'])\r
762                         tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement));\r
763                 else {\r
764                         // Convert all strong/em to b/i\r
765                         content = tinyMCE.regexpReplace(content, "<strong", "<b", "gi");\r
766                         content = tinyMCE.regexpReplace(content, "<em(/?)>", "<i$1>", "gi");\r
767                         content = tinyMCE.regexpReplace(content, "<em ", "<i ", "gi");\r
768                         content = tinyMCE.regexpReplace(content, "</strong>", "</b>", "gi");\r
769                         content = tinyMCE.regexpReplace(content, "</em>", "</i>", "gi");\r
770                         tinyMCE.setInnerHTML(inst.getBody(), content);\r
771                 }\r
772 \r
773                 inst.convertAllRelativeURLs();\r
774         } else {\r
775                 if (tinyMCE.settings['cleanup_on_startup']) {\r
776                         tinyMCE._setHTML(inst.getDoc(), content);\r
777 \r
778                         // Produces permission denied error in MSIE 5.5\r
779                         eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}');\r
780                 } else\r
781                         tinyMCE._setHTML(inst.getDoc(), content);\r
782         }\r
783 \r
784         // Fix for bug #957681\r
785         //inst.getDoc().designMode = inst.getDoc().designMode;\r
786 \r
787         // Setup element references\r
788         var parentElm = document.getElementById(inst.editorId + '_parent');\r
789         if (parentElm.lastChild.nodeName == "INPUT")\r
790                 inst.formElement = tinyMCE.isGecko ? parentElm.firstChild : parentElm.lastChild;\r
791         else\r
792                 inst.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;\r
793 \r
794         tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual'], inst);\r
795         tinyMCE.executeCallback('setupcontent_callback', '_setupContent', 0, editor_id, inst.getBody(), inst.getDoc());\r
796 \r
797         // Re-add design mode on mozilla\r
798         if (!tinyMCE.isMSIE)\r
799                 TinyMCE.prototype.addEventHandlers(editor_id);\r
800 \r
801         // Add blur handler\r
802         if (tinyMCE.isMSIE)\r
803                 tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE.prototype.eventPatch);\r
804 \r
805         // Trigger node change, this call locks buttons for tables and so forth\r
806         tinyMCE.selectedInstance = inst;\r
807         tinyMCE.selectedElement = inst.contentWindow.document.body;\r
808 \r
809         if (!inst.isHidden())\r
810                 tinyMCE.triggerNodeChange(false, true);\r
811 \r
812         // Call custom DOM cleanup\r
813         tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody());\r
814         tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody());\r
815         tinyMCE._setEventsEnabled(inst.getBody(), false);\r
816         tinyMCE.cleanupAnchors(inst.getDoc());\r
817 \r
818         if (tinyMCE.getParam("convert_fonts_to_spans"))\r
819                 tinyMCE.convertSpansToFonts(inst.getDoc());\r
820 \r
821         inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);\r
822         inst.undoLevels[inst.undoLevels.length] = inst.startContent;\r
823 \r
824         tinyMCE.operaOpacityCounter = -1;\r
825 };\r
826 \r
827 TinyMCE.prototype.cleanupHTMLCode = function(s) {\r
828         s = s.replace(/<p \/>/gi, '<p>&nbsp;</p>');\r
829         s = s.replace(/<p>\s*<\/p>/gi, '<p>&nbsp;</p>');\r
830 \r
831         // Open closed tags like <b/> to <b></b>\r
832 //      tinyMCE.debug("f:" + s);\r
833         s = s.replace(/<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\|>]*?)\/>/gi, '<$1$2$3></$1$2>');\r
834 //      tinyMCE.debug("e:" + s);\r
835 \r
836         // Remove trailing space <b > to <b>\r
837         s = s.replace(new RegExp('\\s+></', 'gi'), '></');\r
838 \r
839         // Close tags <img></img> to <img/>\r
840         s = s.replace(/<(img|br|hr)(.*?)><\/(img|br|hr)>/gi, '<$1$2 />');\r
841 \r
842         // Weird MSIE bug, <p><hr /></p> breaks runtime?\r
843         if (tinyMCE.isMSIE)\r
844                 s = s.replace(/<p><hr \/><\/p>/gi, "<hr>");\r
845 \r
846         // Convert relative anchors to absolute URLs ex: #something to file.htm#something\r
847         s = s.replace(new RegExp('(href=\"?)(\\s*?#)', 'gi'), '$1' + tinyMCE.settings['document_base_url'] + "#");\r
848 \r
849         return s;\r
850 };\r
851 \r
852 TinyMCE.prototype.storeAwayURLs = function(s) {\r
853         // Remove all mce_src, mce_href and replace them with new ones\r
854         s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');\r
855         s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');\r
856         s = s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" mce_src="$1"');\r
857         s = s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" mce_href="$1"');\r
858 \r
859         return s;\r
860 };\r
861 \r
862 TinyMCE.prototype.cancelEvent = function(e) {\r
863         if (tinyMCE.isMSIE) {\r
864                 e.returnValue = false;\r
865                 e.cancelBubble = true;\r
866         } else\r
867                 e.preventDefault();\r
868 };\r
869 \r
870 TinyMCE.prototype.removeTinyMCEFormElements = function(form_obj) {\r
871         // Check if form is valid\r
872         if (typeof(form_obj) == "undefined" || form_obj == null)\r
873                 return;\r
874 \r
875         // If not a form, find the form\r
876         if (form_obj.nodeName != "FORM") {\r
877                 if (form_obj.form)\r
878                         form_obj = form_obj.form;\r
879                 else\r
880                         form_obj = tinyMCE.getParentElement(form_obj, "form");\r
881         }\r
882 \r
883         // Still nothing\r
884         if (form_obj == null)\r
885                 return;\r
886 \r
887         // Disable all UI form elements that TinyMCE created\r
888         for (var i=0; i<form_obj.elements.length; i++) {\r
889                 var elementId = form_obj.elements[i].name ? form_obj.elements[i].name : form_obj.elements[i].id;\r
890 \r
891                 if (elementId.indexOf('mce_editor_') == 0)\r
892                         form_obj.elements[i].disabled = true;\r
893         }\r
894 };\r
895 \r
896 TinyMCE.prototype.accessibleEventHandler = function(e) {\r
897         var win = this._win;\r
898         e = tinyMCE.isMSIE ? win.event : e;\r
899         var elm = tinyMCE.isMSIE ? e.srcElement : e.target;\r
900 \r
901         // Piggyback onchange\r
902         if (elm.nodeName == "SELECT" && !elm.oldonchange) {\r
903                 elm.oldonchange = elm.onchange;\r
904                 elm.onchange = null;\r
905         }\r
906 \r
907         // Execute onchange and remove piggyback\r
908         if (e.keyCode == 13 || e.keyCode == 32) {\r
909                 elm.onchange = elm.oldonchange;\r
910                 elm.onchange();\r
911                 elm.oldonchange = null;\r
912                 tinyMCE.cancelEvent(e);\r
913         }\r
914 };\r
915 \r
916 TinyMCE.prototype.addSelectAccessibility = function(e, select, win) {\r
917         // Add event handlers \r
918         if (!select._isAccessible) {\r
919                 select.onkeydown = tinyMCE.accessibleEventHandler;\r
920                 select._isAccessible = true;\r
921                 select._win = win;\r
922         }\r
923 };\r
924 \r
925 TinyMCE.prototype.handleEvent = function(e) {\r
926         // Remove odd, error\r
927         if (typeof(tinyMCE) == "undefined")\r
928                 return true;\r
929 \r
930         //tinyMCE.debug(e.type + " " + e.target.nodeName + " " + (e.relatedTarget ? e.relatedTarget.nodeName : ""));\r
931 \r
932         switch (e.type) {\r
933                 case "blur":\r
934                         if (tinyMCE.selectedInstance)\r
935                                 tinyMCE.selectedInstance.execCommand('mceEndTyping');\r
936 \r
937                         return;\r
938 \r
939                 case "submit":\r
940                         tinyMCE.removeTinyMCEFormElements(tinyMCE.isMSIE ? window.event.srcElement : e.target);\r
941                         tinyMCE.triggerSave();\r
942                         tinyMCE.isNotDirty = true;\r
943                         return;\r
944 \r
945                 case "reset":\r
946                         var formObj = tinyMCE.isMSIE ? window.event.srcElement : e.target;\r
947 \r
948                         for (var i=0; i<document.forms.length; i++) {\r
949                                 if (document.forms[i] == formObj)\r
950                                         window.setTimeout('tinyMCE.resetForm(' + i + ');', 10);\r
951                         }\r
952 \r
953                         return;\r
954 \r
955                 case "keypress":\r
956                         if (e.target.editorId) {\r
957                                 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];\r
958                         } else {\r
959                                 if (e.target.ownerDocument.editorId)\r
960                                         tinyMCE.selectedInstance = tinyMCE.instances[e.target.ownerDocument.editorId];\r
961                         }\r
962 \r
963                         if (tinyMCE.selectedInstance)\r
964                                 tinyMCE.selectedInstance.switchSettings();\r
965 \r
966                         // Insert space instead of &nbsp;\r
967 /*                      if (tinyMCE.isGecko && e.charCode == 32) {\r
968                                 if (tinyMCE.selectedInstance._insertSpace()) {\r
969                                         // Cancel event\r
970                                         e.preventDefault();\r
971                                         return false;\r
972                                 }\r
973                         }*/\r
974 \r
975                         // Insert P element\r
976                         if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) {\r
977                                 // Insert P element instead of BR\r
978                                 if (tinyMCE.selectedInstance._insertPara(e)) {\r
979                                         // Cancel event\r
980                                         tinyMCE.execCommand("mceAddUndoLevel");\r
981                                         tinyMCE.cancelEvent(e);\r
982                                         return false;\r
983                                 }\r
984                         }\r
985 \r
986                         // Handle backspace\r
987                         if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {\r
988                                 // Insert P element instead of BR\r
989                                 if (tinyMCE.selectedInstance._handleBackSpace(e.type)) {\r
990                                         // Cancel event\r
991                                         tinyMCE.execCommand("mceAddUndoLevel");\r
992                                         tinyMCE.cancelEvent(e);\r
993                                         return false;\r
994                                 }\r
995                         }\r
996 \r
997                         // Mozilla custom key handling\r
998                         if (tinyMCE.isGecko && (e.ctrlKey && !e.altKey) && tinyMCE.settings['custom_undo_redo']) {\r
999                                 if (tinyMCE.settings['custom_undo_redo_keyboard_shortcuts']) {\r
1000                                         if (e.charCode == 122) { // Ctrl+Z\r
1001                                                 tinyMCE.selectedInstance.execCommand("Undo");\r
1002                                                 tinyMCE.cancelEvent(e);\r
1003                                                 return false;\r
1004                                         }\r
1005 \r
1006                                         if (e.charCode == 121) { // Ctrl+Y\r
1007                                                 tinyMCE.selectedInstance.execCommand("Redo");\r
1008                                                 tinyMCE.cancelEvent(e);\r
1009                                                 return false;\r
1010                                         }\r
1011                                 }\r
1012 \r
1013                                 if (e.charCode == 98) { // Ctrl+B\r
1014                                         tinyMCE.selectedInstance.execCommand("Bold");\r
1015                                         tinyMCE.cancelEvent(e);\r
1016                                         return false;\r
1017                                 }\r
1018 \r
1019                                 if (e.charCode == 105) { // Ctrl+I\r
1020                                         tinyMCE.selectedInstance.execCommand("Italic");\r
1021                                         tinyMCE.cancelEvent(e);\r
1022                                         return false;\r
1023                                 }\r
1024 \r
1025                                 if (e.charCode == 117) { // Ctrl+U\r
1026                                         tinyMCE.selectedInstance.execCommand("Underline");\r
1027                                         tinyMCE.cancelEvent(e);\r
1028                                         return false;\r
1029                                 }\r
1030                         }\r
1031 \r
1032                         // Return key pressed\r
1033                         if (tinyMCE.isMSIE && tinyMCE.settings['force_br_newlines'] && e.keyCode == 13) {\r
1034                                 if (e.target.editorId)\r
1035                                         tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];\r
1036 \r
1037                                 if (tinyMCE.selectedInstance) {\r
1038                                         var sel = tinyMCE.selectedInstance.getDoc().selection;\r
1039                                         var rng = sel.createRange();\r
1040 \r
1041                                         if (tinyMCE.getParentElement(rng.parentElement(), "li") != null)\r
1042                                                 return false;\r
1043 \r
1044                                         // Cancel event\r
1045                                         e.returnValue = false;\r
1046                                         e.cancelBubble = true;\r
1047 \r
1048                                         // Insert BR element\r
1049                                         rng.pasteHTML("<br />");\r
1050                                         rng.collapse(false);\r
1051                                         rng.select();\r
1052 \r
1053                                         tinyMCE.execCommand("mceAddUndoLevel");\r
1054                                         tinyMCE.triggerNodeChange(false);\r
1055                                         return false;\r
1056                                 }\r
1057                         }\r
1058 \r
1059                         // Backspace or delete\r
1060                         if (e.keyCode == 8 || e.keyCode == 46) {\r
1061                                 tinyMCE.selectedElement = e.target;\r
1062                                 tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a");\r
1063                                 tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img");\r
1064                                 tinyMCE.triggerNodeChange(false);\r
1065                         }\r
1066 \r
1067                         return false;\r
1068                 break;\r
1069 \r
1070                 case "keyup":\r
1071                 case "keydown":\r
1072                         if (e.target.editorId)\r
1073                                 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];\r
1074                         else\r
1075                                 return;\r
1076 \r
1077                         if (tinyMCE.selectedInstance)\r
1078                                 tinyMCE.selectedInstance.switchSettings();\r
1079 \r
1080                         var inst = tinyMCE.selectedInstance;\r
1081 \r
1082                         // Handle backspace\r
1083                         if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {\r
1084                                 // Insert P element instead of BR\r
1085                                 if (tinyMCE.selectedInstance._handleBackSpace(e.type)) {\r
1086                                         // Cancel event\r
1087                                         tinyMCE.execCommand("mceAddUndoLevel");\r
1088                                         e.preventDefault();\r
1089                                         return false;\r
1090                                 }\r
1091                         }\r
1092 \r
1093                         tinyMCE.selectedElement = null;\r
1094                         tinyMCE.selectedNode = null;\r
1095                         var elm = tinyMCE.selectedInstance.getFocusElement();\r
1096                         tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a");\r
1097                         tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img");\r
1098                         tinyMCE.selectedElement = elm;\r
1099 \r
1100                         // Update visualaids on tabs\r
1101                         if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9)\r
1102                                 tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);\r
1103 \r
1104                         // Fix empty elements on return/enter, check where enter occured\r
1105                         if (tinyMCE.isMSIE && e.type == "keydown" && e.keyCode == 13)\r
1106                                 tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement();\r
1107 \r
1108                         // Fix empty elements on return/enter\r
1109                         if (tinyMCE.isMSIE && e.type == "keyup" && e.keyCode == 13) {\r
1110                                 var elm = tinyMCE.enterKeyElement;\r
1111                                 if (elm) {\r
1112                                         var re = new RegExp('^HR|IMG|BR$','g'); // Skip these\r
1113                                         var dre = new RegExp('^H[1-6]$','g'); // Add double on these\r
1114 \r
1115                                         if (!elm.hasChildNodes() && !re.test(elm.nodeName)) {\r
1116                                                 if (dre.test(elm.nodeName))\r
1117                                                         elm.innerHTML = "&nbsp;&nbsp;";\r
1118                                                 else\r
1119                                                         elm.innerHTML = "&nbsp;";\r
1120                                         }\r
1121                                 }\r
1122                         }\r
1123 \r
1124                         // Check if it's a position key\r
1125                         var keys = tinyMCE.posKeyCodes;\r
1126                         var posKey = false;\r
1127                         for (var i=0; i<keys.length; i++) {\r
1128                                 if (keys[i] == e.keyCode) {\r
1129                                         posKey = true;\r
1130                                         break;\r
1131                                 }\r
1132                         }\r
1133 \r
1134                         // MSIE custom key handling\r
1135                         if (tinyMCE.isMSIE && tinyMCE.settings['custom_undo_redo']) {\r
1136                                 var keys = new Array(8,46); // Backspace,Delete\r
1137                                 for (var i=0; i<keys.length; i++) {\r
1138                                         if (keys[i] == e.keyCode) {\r
1139                                                 if (e.type == "keyup")\r
1140                                                         tinyMCE.triggerNodeChange(false);\r
1141                                         }\r
1142                                 }\r
1143 \r
1144                                 if (tinyMCE.settings['custom_undo_redo_keyboard_shortcuts']) {\r
1145                                         if (e.keyCode == 90 && (e.ctrlKey && !e.altKey) && e.type == "keydown") { // Ctrl+Z\r
1146                                                 tinyMCE.selectedInstance.execCommand("Undo");\r
1147                                                 tinyMCE.triggerNodeChange(false);\r
1148                                         }\r
1149 \r
1150                                         if (e.keyCode == 89 && (e.ctrlKey && !e.altKey) && e.type == "keydown") { // Ctrl+Y\r
1151                                                 tinyMCE.selectedInstance.execCommand("Redo");\r
1152                                                 tinyMCE.triggerNodeChange(false);\r
1153                                         }\r
1154 \r
1155                                         if ((e.keyCode == 90 || e.keyCode == 89) && (e.ctrlKey && !e.altKey)) {\r
1156                                                 // Cancel event\r
1157                                                 e.returnValue = false;\r
1158                                                 e.cancelBubble = true;\r
1159                                                 return false;\r
1160                                         }\r
1161                                 }\r
1162                         }\r
1163 \r
1164                         // If undo/redo key\r
1165                         if ((e.keyCode == 90 || e.keyCode == 89) && (e.ctrlKey && !e.altKey))\r
1166                                 return true;\r
1167 \r
1168                         // If Ctrl key\r
1169                         if (e.keyCode == 17)\r
1170                                 return true;\r
1171 \r
1172                         // Handle Undo/Redo when typing content\r
1173 \r
1174                         // Start typing (non position key)\r
1175                         if (!posKey && e.type == "keyup")\r
1176                                 tinyMCE.execCommand("mceStartTyping");\r
1177 \r
1178                         // End typing (position key) or some Ctrl event\r
1179                         if (e.type == "keyup" && (posKey || e.ctrlKey))\r
1180                                 tinyMCE.execCommand("mceEndTyping");\r
1181 \r
1182                         if (posKey && e.type == "keyup")\r
1183                                 tinyMCE.triggerNodeChange(false);\r
1184 \r
1185                         if (tinyMCE.isMSIE && e.ctrlKey)\r
1186                                 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);\r
1187                 break;\r
1188 \r
1189                 case "mousedown":\r
1190                 case "mouseup":\r
1191                 case "click":\r
1192                 case "focus":\r
1193                         if (tinyMCE.selectedInstance)\r
1194                                 tinyMCE.selectedInstance.switchSettings();\r
1195 \r
1196                         // Check instance event trigged on\r
1197                         var targetBody = tinyMCE.getParentElement(e.target, "body");\r
1198                         for (var instanceName in tinyMCE.instances) {\r
1199                                 if (!tinyMCE.isInstance(tinyMCE.instances[instanceName]))\r
1200                                         continue;\r
1201 \r
1202                                 var inst = tinyMCE.instances[instanceName];\r
1203 \r
1204                                 // Reset design mode if lost (on everything just in case)\r
1205                                 inst.autoResetDesignMode();\r
1206 \r
1207                                 if (inst.getBody() == targetBody) {\r
1208                                         tinyMCE.selectedInstance = inst;\r
1209                                         tinyMCE.selectedElement = e.target;\r
1210                                         tinyMCE.linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");\r
1211                                         tinyMCE.imgElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "img");\r
1212                                         break;\r
1213                                 }\r
1214                         }\r
1215 \r
1216                         if (tinyMCE.isSafari) {\r
1217                                 tinyMCE.selectedInstance.lastSafariSelection = tinyMCE.selectedInstance.getBookmark();\r
1218                                 tinyMCE.selectedInstance.lastSafariSelectedElement = tinyMCE.selectedElement;\r
1219 \r
1220                                 var lnk = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");\r
1221 \r
1222                                 // Patch the darned link\r
1223                                 if (lnk && e.type == "mousedown") {\r
1224                                         lnk.setAttribute("mce_real_href", lnk.getAttribute("href"));\r
1225                                         lnk.setAttribute("href", "javascript:void(0);");\r
1226                                 }\r
1227 \r
1228                                 // Patch back\r
1229                                 if (lnk && e.type == "click") {\r
1230                                         window.setTimeout(function() {\r
1231                                                 lnk.setAttribute("href", lnk.getAttribute("mce_real_href"));\r
1232                                                 lnk.removeAttribute("mce_real_href");\r
1233                                         }, 10);\r
1234                                 }\r
1235                         }\r
1236 \r
1237                         // Reset selected node\r
1238                         if (e.type != "focus")\r
1239                                 tinyMCE.selectedNode = null;\r
1240 \r
1241                         tinyMCE.triggerNodeChange(false);\r
1242                         tinyMCE.execCommand("mceEndTyping");\r
1243 \r
1244                         if (e.type == "mouseup")\r
1245                                 tinyMCE.execCommand("mceAddUndoLevel");\r
1246 \r
1247                         // Just in case\r
1248                         if (!tinyMCE.selectedInstance && e.target.editorId)\r
1249                                 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];\r
1250 \r
1251                         return false;\r
1252                 break;\r
1253     } // end switch\r
1254 }; // end function\r
1255 \r
1256 TinyMCE.prototype.switchClass = function(element, class_name, lock_state) {\r
1257         var lockChanged = false;\r
1258 \r
1259         if (typeof(lock_state) != "undefined" && element != null) {\r
1260                 element.classLock = lock_state;\r
1261                 lockChanged = true;\r
1262         }\r
1263 \r
1264         if (element != null && (lockChanged || !element.classLock)) {\r
1265                 element.oldClassName = element.className;\r
1266                 element.className = class_name;\r
1267         }\r
1268 };\r
1269 \r
1270 TinyMCE.prototype.restoreAndSwitchClass = function(element, class_name) {\r
1271         if (element != null && !element.classLock) {\r
1272                 this.restoreClass(element);\r
1273                 this.switchClass(element, class_name);\r
1274         }\r
1275 };\r
1276 \r
1277 TinyMCE.prototype.switchClassSticky = function(element_name, class_name, lock_state) {\r
1278         var element, lockChanged = false;\r
1279 \r
1280         // Performance issue\r
1281         if (!this.stickyClassesLookup[element_name])\r
1282                 this.stickyClassesLookup[element_name] = document.getElementById(element_name);\r
1283 \r
1284 //      element = document.getElementById(element_name);\r
1285         element = this.stickyClassesLookup[element_name];\r
1286 \r
1287         if (typeof(lock_state) != "undefined" && element != null) {\r
1288                 element.classLock = lock_state;\r
1289                 lockChanged = true;\r
1290         }\r
1291 \r
1292         if (element != null && (lockChanged || !element.classLock)) {\r
1293                 element.className = class_name;\r
1294                 element.oldClassName = class_name;\r
1295 \r
1296                 // Fix opacity in Opera\r
1297                 if (tinyMCE.isOpera) {\r
1298                         if (class_name == "mceButtonDisabled") {\r
1299                                 var suffix = "";\r
1300 \r
1301                                 if (!element.mceOldSrc)\r
1302                                         element.mceOldSrc = element.src;\r
1303 \r
1304                                 if (this.operaOpacityCounter > -1)\r
1305                                         suffix = '?rnd=' + this.operaOpacityCounter++;\r
1306 \r
1307                                 element.src = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/images/opacity.png" + suffix;\r
1308                                 element.style.backgroundImage = "url('" + element.mceOldSrc + "')";\r
1309                         } else {\r
1310                                 if (element.mceOldSrc) {\r
1311                                         element.src = element.mceOldSrc;\r
1312                                         element.parentNode.style.backgroundImage = "";\r
1313                                         element.mceOldSrc = null;\r
1314                                 }\r
1315                         }\r
1316                 }\r
1317         }\r
1318 };\r
1319 \r
1320 TinyMCE.prototype.restoreClass = function(element) {\r
1321         if (element != null && element.oldClassName && !element.classLock) {\r
1322                 element.className = element.oldClassName;\r
1323                 element.oldClassName = null;\r
1324         }\r
1325 };\r
1326 \r
1327 TinyMCE.prototype.setClassLock = function(element, lock_state) {\r
1328         if (element != null)\r
1329                 element.classLock = lock_state;\r
1330 };\r
1331 \r
1332 TinyMCE.prototype.addEvent = function(obj, name, handler) {\r
1333         if (tinyMCE.isMSIE) {\r
1334                 obj.attachEvent("on" + name, handler);\r
1335         } else\r
1336                 obj.addEventListener(name, handler, false);\r
1337 };\r
1338 \r
1339 TinyMCE.prototype.submitPatch = function() {\r
1340         tinyMCE.removeTinyMCEFormElements(this);\r
1341         tinyMCE.triggerSave();\r
1342         this.mceOldSubmit();\r
1343         tinyMCE.isNotDirty = true;\r
1344 };\r
1345 \r
1346 TinyMCE.prototype.onLoad = function() {\r
1347         for (var c=0; c<tinyMCE.configs.length; c++) {\r
1348                 tinyMCE.settings = tinyMCE.configs[c];\r
1349 \r
1350                 var selector = tinyMCE.getParam("editor_selector");\r
1351                 var deselector = tinyMCE.getParam("editor_deselector");\r
1352                 var elementRefAr = new Array();\r
1353 \r
1354                 // Add submit triggers\r
1355                 if (document.forms && tinyMCE.settings['add_form_submit_trigger'] && !tinyMCE.submitTriggers) {\r
1356                         for (var i=0; i<document.forms.length; i++) {\r
1357                                 var form = document.forms[i];\r
1358 \r
1359                                 tinyMCE.addEvent(form, "submit", TinyMCE.prototype.handleEvent);\r
1360                                 tinyMCE.addEvent(form, "reset", TinyMCE.prototype.handleEvent);\r
1361                                 tinyMCE.submitTriggers = true; // Do it only once\r
1362 \r
1363                                 // Patch the form.submit function\r
1364                                 if (tinyMCE.settings['submit_patch']) {\r
1365                                         try {\r
1366                                                 form.mceOldSubmit = form.submit;\r
1367                                                 form.submit = TinyMCE.prototype.submitPatch;\r
1368                                         } catch (e) {\r
1369                                                 // Do nothing\r
1370                                         }\r
1371                                 }\r
1372                         }\r
1373                 }\r
1374 \r
1375                 // Add editor instances based on mode\r
1376                 var mode = tinyMCE.settings['mode'];\r
1377                 switch (mode) {\r
1378                         case "exact":\r
1379                                 var elements = tinyMCE.getParam('elements', '', true, ',');\r
1380 \r
1381                                 for (var i=0; i<elements.length; i++) {\r
1382                                         var element = tinyMCE._getElementById(elements[i]);\r
1383                                         var trigger = element ? element.getAttribute(tinyMCE.settings['textarea_trigger']) : "";\r
1384 \r
1385                                         if (tinyMCE.getAttrib(element, "class").indexOf(deselector) != -1)\r
1386                                                 continue;\r
1387 \r
1388                                         if (trigger == "false")\r
1389                                                 continue;\r
1390 \r
1391                                         if (tinyMCE.settings['ask'] && element) {\r
1392                                                 elementRefAr[elementRefAr.length] = element;\r
1393                                                 continue;\r
1394                                         }\r
1395 \r
1396                                         if (element)\r
1397                                                 tinyMCE.addMCEControl(element, elements[i]);\r
1398                                         else if (tinyMCE.settings['debug'])\r
1399                                                 alert("Error: Could not find element by id or name: " + elements[i]);\r
1400                                 }\r
1401                         break;\r
1402 \r
1403                         case "specific_textareas":\r
1404                         case "textareas":\r
1405                                 var nodeList = document.getElementsByTagName("textarea");\r
1406 \r
1407                                 for (var i=0; i<nodeList.length; i++) {\r
1408                                         var elm = nodeList.item(i);\r
1409                                         var trigger = elm.getAttribute(tinyMCE.settings['textarea_trigger']);\r
1410 \r
1411                                         if (selector != '' && tinyMCE.getAttrib(elm, "class").indexOf(selector) == -1)\r
1412                                                 continue;\r
1413 \r
1414                                         if (selector != '')\r
1415                                                 trigger = selector != "" ? "true" : "";\r
1416 \r
1417                                         if (tinyMCE.getAttrib(elm, "class").indexOf(deselector) != -1)\r
1418                                                 continue;\r
1419 \r
1420                                         if ((mode == "specific_textareas" && trigger == "true") || (mode == "textareas" && trigger != "false"))\r
1421                                                 elementRefAr[elementRefAr.length] = elm;\r
1422                                 }\r
1423                         break;\r
1424                 }\r
1425 \r
1426                 for (var i=0; i<elementRefAr.length; i++) {\r
1427                         var element = elementRefAr[i];\r
1428                         var elementId = element.name ? element.name : element.id;\r
1429 \r
1430                         if (tinyMCE.settings['ask']) {\r
1431                                 // Focus breaks in Mozilla\r
1432                                 if (tinyMCE.isGecko) {\r
1433                                         var settings = tinyMCE.settings;\r
1434 \r
1435                                         tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE.prototype.confirmAdd(e, settings);}, 10);});\r
1436                                 } else {\r
1437                                         var settings = tinyMCE.settings;\r
1438 \r
1439                                         tinyMCE.addEvent(element, "focus", function () { TinyMCE.prototype.confirmAdd(null, settings); });\r
1440                                 }\r
1441                         } else\r
1442                                 tinyMCE.addMCEControl(element, elementId);\r
1443                 }\r
1444 \r
1445                 // Handle auto focus\r
1446                 if (tinyMCE.settings['auto_focus']) {\r
1447                         window.setTimeout(function () {\r
1448                                 var inst = tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);\r
1449                                 inst.selectNode(inst.getBody(), true, true);\r
1450                                 inst.contentWindow.focus();\r
1451                         }, 10);\r
1452                 }\r
1453 \r
1454                 tinyMCE.executeCallback('oninit', '_oninit', 0);\r
1455         }\r
1456 };\r
1457 \r
1458 TinyMCE.prototype.removeMCEControl = function(editor_id) {\r
1459         var inst = tinyMCE.getInstanceById(editor_id);\r
1460 \r
1461         if (inst) {\r
1462                 inst.switchSettings();\r
1463 \r
1464                 editor_id = inst.editorId;\r
1465                 var html = tinyMCE.getContent(editor_id);\r
1466 \r
1467                 // Remove editor instance from instances array\r
1468                 var tmpInstances = new Array();\r
1469                 for (var instanceName in tinyMCE.instances) {\r
1470                         var instance = tinyMCE.instances[instanceName];\r
1471                         if (!tinyMCE.isInstance(instance))\r
1472                                 continue;\r
1473 \r
1474                         if (instanceName != editor_id)\r
1475                                         tmpInstances[instanceName] = instance;\r
1476                 }\r
1477                 tinyMCE.instances = tmpInstances;\r
1478 \r
1479                 tinyMCE.selectedElement = null;\r
1480                 tinyMCE.selectedInstance = null;\r
1481 \r
1482                 // Remove element\r
1483                 var replaceElement = document.getElementById(editor_id + "_parent");\r
1484                 var oldTargetElement = inst.oldTargetElement;\r
1485                 var targetName = oldTargetElement.nodeName.toLowerCase();\r
1486 \r
1487                 if (targetName == "textarea" || targetName == "input") {\r
1488                         // Just show the old text area\r
1489                         replaceElement.parentNode.removeChild(replaceElement);\r
1490                         oldTargetElement.style.display = "inline";\r
1491                         oldTargetElement.value = html;\r
1492                 } else {\r
1493                         oldTargetElement.innerHTML = html;\r
1494 \r
1495                         replaceElement.parentNode.insertBefore(oldTargetElement, replaceElement);\r
1496                         replaceElement.parentNode.removeChild(replaceElement);\r
1497                 }\r
1498         }\r
1499 };\r
1500 \r
1501 TinyMCE.prototype._cleanupElementName = function(element_name, element) {\r
1502         var name = "";\r
1503 \r
1504         element_name = element_name.toLowerCase();\r
1505 \r
1506         // Never include body\r
1507         if (element_name == "body")\r
1508                 return null;\r
1509 \r
1510         // If verification mode\r
1511         if (tinyMCE.cleanup_verify_html) {\r
1512                 // Check if invalid element\r
1513                 for (var i=0; i<tinyMCE.cleanup_invalidElements.length; i++) {\r
1514                         if (tinyMCE.cleanup_invalidElements[i] == element_name)\r
1515                                 return null;\r
1516                 }\r
1517 \r
1518                 // Check if valid element\r
1519                 var validElement = false;\r
1520                 var elementAttribs = null;\r
1521                 for (var i=0; i<tinyMCE.cleanup_validElements.length && !elementAttribs; i++) {\r
1522                         for (var x=0, n=tinyMCE.cleanup_validElements[i][0].length; x<n; x++) {\r
1523                                 var elmMatch = tinyMCE.cleanup_validElements[i][0][x];\r
1524 \r
1525                                 if (elmMatch.charAt(0) == '+' || elmMatch.charAt(0) == '-')\r
1526                                         elmMatch = elmMatch.substring(1);\r
1527 \r
1528                                 // Handle wildcard/regexp\r
1529                                 if (elmMatch.match(new RegExp('\\*|\\?|\\+', 'g')) != null) {\r
1530                                         elmMatch = elmMatch.replace(new RegExp('\\?', 'g'), '(\\S?)');\r
1531                                         elmMatch = elmMatch.replace(new RegExp('\\+', 'g'), '(\\S+)');\r
1532                                         elmMatch = elmMatch.replace(new RegExp('\\*', 'g'), '(\\S*)');\r
1533                                         elmMatch = "^" + elmMatch + "$";\r
1534                                         if (element_name.match(new RegExp(elmMatch, 'g'))) {\r
1535                                                 elementAttribs = tinyMCE.cleanup_validElements[i];\r
1536                                                 validElement = true;\r
1537                                                 break;\r
1538                                         }\r
1539                                 }\r
1540 \r
1541                                 // Handle non regexp\r
1542                                 if (element_name == elmMatch) {\r
1543                                         elementAttribs = tinyMCE.cleanup_validElements[i];\r
1544                                         validElement = true;\r
1545                                         element_name = elementAttribs[0][0];\r
1546                                         break;\r
1547                                 }\r
1548                         }\r
1549                 }\r
1550 \r
1551                 if (!validElement)\r
1552                         return null;\r
1553         }\r
1554 \r
1555         if (element_name.charAt(0) == '+' || element_name.charAt(0) == '-')\r
1556                 name = element_name.substring(1);\r
1557 \r
1558         // Special Mozilla stuff\r
1559         if (!tinyMCE.isMSIE) {\r
1560                 // Fix for bug #958498\r
1561                 if (name == "strong" && !tinyMCE.cleanup_on_save)\r
1562                         element_name = "b";\r
1563                 else if (name == "em" && !tinyMCE.cleanup_on_save)\r
1564                         element_name = "i";\r
1565         }\r
1566 \r
1567         var elmData = new Object();\r
1568 \r
1569         elmData.element_name = element_name;\r
1570         elmData.valid_attribs = elementAttribs;\r
1571 \r
1572         return elmData;\r
1573 };\r
1574 \r
1575 /**\r
1576  * This function moves CSS styles to/from attributes.\r
1577  */\r
1578 TinyMCE.prototype._moveStyle = function(elm, style, attrib) {\r
1579         if (tinyMCE.cleanup_inline_styles) {\r
1580                 var val = tinyMCE.getAttrib(elm, attrib);\r
1581 \r
1582                 if (val != '') {\r
1583                         val = '' + val;\r
1584 \r
1585                         switch (attrib) {\r
1586                                 case "background":\r
1587                                         val = "url('" + val + "')";\r
1588                                         break;\r
1589 \r
1590                                 case "bordercolor":\r
1591                                         if (elm.style.borderStyle == '' || elm.style.borderStyle == 'none')\r
1592                                                 elm.style.borderStyle = 'solid';\r
1593                                         break;\r
1594 \r
1595                                 case "border":\r
1596                                 case "width":\r
1597                                 case "height":\r
1598                                         if (attrib == "border" && elm.style.borderWidth > 0)\r
1599                                                 return;\r
1600 \r
1601                                         if (val.indexOf('%') == -1)\r
1602                                                 val += 'px';\r
1603                                         break;\r
1604 \r
1605                                 case "vspace":\r
1606                                 case "hspace":\r
1607                                         elm.style.marginTop = val + "px";\r
1608                                         elm.style.marginBottom = val + "px";\r
1609                                         elm.removeAttribute(attrib);\r
1610                                         return;\r
1611 \r
1612                                 case "align":\r
1613                                         if (elm.nodeName == "IMG") {\r
1614                                                 if (tinyMCE.isMSIE)\r
1615                                                         elm.style.styleFloat = val;\r
1616                                                 else\r
1617                                                         elm.style.cssFloat = val;\r
1618                                         } else\r
1619                                                 elm.style.textAlign = val;\r
1620 \r
1621                                         elm.removeAttribute(attrib);\r
1622                                         return;\r
1623                         }\r
1624 \r
1625                         if (val != '') {\r
1626                                 eval('elm.style.' + style + ' = val;');\r
1627                                 elm.removeAttribute(attrib);\r
1628                         }\r
1629                 }\r
1630         } else {\r
1631                 if (style == '')\r
1632                         return;\r
1633 \r
1634                 var val = eval('elm.style.' + style) == '' ? tinyMCE.getAttrib(elm, attrib) : eval('elm.style.' + style);\r
1635                 val = val == null ? '' : '' + val;\r
1636 \r
1637                 switch (attrib) {\r
1638                         // Always move background to style\r
1639                         case "background":\r
1640                                 if (val.indexOf('url') == -1 && val != '')\r
1641                                         val = "url('" + val + "');";\r
1642 \r
1643                                 if (val != '') {\r
1644                                         elm.style.backgroundImage = val;\r
1645                                         elm.removeAttribute(attrib);\r
1646                                 }\r
1647                                 return;\r
1648 \r
1649                         case "border":\r
1650                         case "width":\r
1651                         case "height":\r
1652                                 val = val.replace('px', '');\r
1653                                 break;\r
1654 \r
1655                         case "align":\r
1656                                 if (tinyMCE.getAttrib(elm, 'align') == '') {\r
1657                                         if (elm.nodeName == "IMG") {\r
1658                                                 if (tinyMCE.isMSIE && elm.style.styleFloat != '') {\r
1659                                                         val = elm.style.styleFloat;\r
1660                                                         style = 'styleFloat';\r
1661                                                 } else if (tinyMCE.isGecko && elm.style.cssFloat != '') {\r
1662                                                         val = elm.style.cssFloat;\r
1663                                                         style = 'cssFloat';\r
1664                                                 }\r
1665                                         }\r
1666                                 }\r
1667                                 break;\r
1668                 }\r
1669 \r
1670                 if (val != '') {\r
1671                         elm.removeAttribute(attrib);\r
1672                         elm.setAttribute(attrib, val);\r
1673                         eval('elm.style.' + style + ' = "";');\r
1674                 }\r
1675         }\r
1676 };\r
1677 \r
1678 TinyMCE.prototype._cleanupAttribute = function(valid_attributes, element_name, attribute_node, element_node) {\r
1679         var attribName = attribute_node.nodeName.toLowerCase();\r
1680         var attribValue = attribute_node.nodeValue;\r
1681         var attribMustBeValue = null;\r
1682         var verified = false;\r
1683 \r
1684         // Mozilla attibute, remove them\r
1685         if (attribName.indexOf('moz_') != -1)\r
1686                 return null;\r
1687 \r
1688         if (!tinyMCE.cleanup_on_save && (attribName == "mce_href" || attribName == "mce_src"))\r
1689                 return {name : attribName, value : attribValue};\r
1690 \r
1691         // Verify attrib\r
1692         if (tinyMCE.cleanup_verify_html && !verified) {\r
1693                 for (var i=1; i<valid_attributes.length; i++) {\r
1694                         var attribMatch = valid_attributes[i][0];\r
1695                         var re = null;\r
1696 \r
1697                         // Build regexp from wildcard\r
1698                         if (attribMatch.match(new RegExp('\\*|\\?|\\+', 'g')) != null) {\r
1699                                 attribMatch = attribMatch.replace(new RegExp('\\?', 'g'), '(\\S?)');\r
1700                                 attribMatch = attribMatch.replace(new RegExp('\\+', 'g'), '(\\S+)');\r
1701                                 attribMatch = attribMatch.replace(new RegExp('\\*', 'g'), '(\\S*)');\r
1702                                 attribMatch = "^" + attribMatch + "$";\r
1703                                 re = new RegExp(attribMatch, 'g');\r
1704                         }\r
1705 \r
1706                         if ((re && attribName.match(re) != null) || attribName == attribMatch) {\r
1707                                 verified = true;\r
1708                                 attribMustBeValue = valid_attributes[i][3];\r
1709                                 break;\r
1710                         }\r
1711                 }\r
1712 \r
1713                 if (!verified)\r
1714                         return false;\r
1715         } else\r
1716                 verified = true;\r
1717 \r
1718         // Treat some attribs diffrent\r
1719         switch (attribName) {\r
1720                 case "size":\r
1721                         if (tinyMCE.isMSIE5 && element_name == "font")\r
1722                                 attribValue = element_node.size;\r
1723                         break;\r
1724 \r
1725                 case "width":\r
1726                 case "height":\r
1727                 case "border":\r
1728                         // Old MSIE needs this\r
1729                         if (tinyMCE.isMSIE5)\r
1730                                 attribValue = eval("element_node." + attribName);\r
1731                         break;\r
1732 \r
1733                 case "shape":\r
1734                         attribValue = attribValue.toLowerCase();\r
1735                         break;\r
1736 \r
1737                 case "cellspacing":\r
1738                         if (tinyMCE.isMSIE5)\r
1739                                 attribValue = element_node.cellSpacing;\r
1740                         break;\r
1741 \r
1742                 case "cellpadding":\r
1743                         if (tinyMCE.isMSIE5)\r
1744                                 attribValue = element_node.cellPadding;\r
1745                         break;\r
1746 \r
1747                 case "color":\r
1748                         if (tinyMCE.isMSIE5 && element_name == "font")\r
1749                                 attribValue = element_node.color;\r
1750                         break;\r
1751 \r
1752                 case "class":\r
1753                         // Remove mceItem classes from anchors\r
1754                         if (tinyMCE.cleanup_on_save && attribValue.indexOf('mceItemAnchor') != -1)\r
1755                                 attribValue = attribValue.replace(/mceItem[a-z0-9]+/gi, '');\r
1756 \r
1757                         if (element_name == "table" || element_name == "td") {\r
1758                                 // Handle visual aid\r
1759                                 if (tinyMCE.cleanup_visual_table_class != "")\r
1760                                         attribValue = tinyMCE.getVisualAidClass(attribValue, !tinyMCE.cleanup_on_save);\r
1761                         }\r
1762 \r
1763                         if (!tinyMCE._verifyClass(element_node) || attribValue == "")\r
1764                                 return null;\r
1765 \r
1766                         break;\r
1767 \r
1768                 case "onfocus":\r
1769                 case "onblur":\r
1770                 case "onclick":\r
1771                 case "ondblclick":\r
1772                 case "onmousedown":\r
1773                 case "onmouseup":\r
1774                 case "onmouseover":\r
1775                 case "onmousemove":\r
1776                 case "onmouseout":\r
1777                 case "onkeypress":\r
1778                 case "onkeydown":\r
1779                 case "onkeydown":\r
1780                 case "onkeyup":\r
1781                         attribValue = tinyMCE.cleanupEventStr("" + attribValue);\r
1782 \r
1783                         if (attribValue.indexOf('return false;') == 0)\r
1784                                 attribValue = attribValue.substring(14);\r
1785 \r
1786                         break;\r
1787 \r
1788                 case "style":\r
1789                         attribValue = tinyMCE.serializeStyle(tinyMCE.parseStyle(tinyMCE.getAttrib(element_node, "style")));\r
1790                         break;\r
1791 \r
1792                 // Convert the URLs of these\r
1793                 case "href":\r
1794                 case "src":\r
1795                 case "longdesc":\r
1796                         attribValue = tinyMCE.getAttrib(element_node, attribName);\r
1797 \r
1798                         // Use mce_href instead\r
1799                         var href = tinyMCE.getAttrib(element_node, "mce_href");\r
1800                         if (attribName == "href" && href != "")\r
1801                                 attribValue = href;\r
1802 \r
1803                         // Use mce_src instead\r
1804                         var src = tinyMCE.getAttrib(element_node, "mce_src");\r
1805                         if (attribName == "src" && src != "")\r
1806                                 attribValue = src;\r
1807 \r
1808                         // Always use absolute URLs within TinyMCE\r
1809                         if (!tinyMCE.cleanup_on_save)\r
1810                                 attribValue = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], attribValue);\r
1811                         else if (tinyMCE.getParam('convert_urls'))\r
1812                                 attribValue = eval(tinyMCE.cleanup_urlconverter_callback + "(attribValue, element_node, tinyMCE.cleanup_on_save);");\r
1813 \r
1814                         break;\r
1815 \r
1816                 case "colspan":\r
1817                 case "rowspan":\r
1818                         // Not needed\r
1819                         if (attribValue == "1")\r
1820                                 return null;\r
1821                         break;\r
1822 \r
1823                 // Skip these\r
1824                 case "_moz-userdefined":\r
1825                 case "editorid":\r
1826                 case "mce_href":\r
1827                 case "mce_src":\r
1828                         return null;\r
1829         }\r
1830 \r
1831         // Not the must be value\r
1832         if (attribMustBeValue != null) {\r
1833                 var isCorrect = false;\r
1834                 for (var i=0; i<attribMustBeValue.length; i++) {\r
1835                         if (attribValue == attribMustBeValue[i]) {\r
1836                                 isCorrect = true;\r
1837                                 break;\r
1838                         }\r
1839                 }\r
1840 \r
1841                 if (!isCorrect)\r
1842                         return null;\r
1843         }\r
1844 \r
1845         var attrib = new Object();\r
1846 \r
1847         attrib.name = attribName;\r
1848         attrib.value = attribValue;\r
1849 \r
1850         return attrib;\r
1851 };\r
1852 \r
1853 TinyMCE.prototype.clearArray = function(ar) {\r
1854         // Since stupid people tend to extend core objects like\r
1855         // Array with their own crap I needed to make functions that clean away\r
1856         // this junk so the arrays get clean and nice as they should be\r
1857         for (var key in ar)\r
1858                 ar[key] = null;\r
1859 };\r
1860 \r
1861 TinyMCE.prototype.isInstance = function(inst) {\r
1862         return inst != null && typeof(inst) == "object" && inst.isTinyMCEControl;\r
1863 };\r
1864 \r
1865 TinyMCE.prototype.parseStyle = function(str) {\r
1866         var ar = new Array();\r
1867 \r
1868         if (str == null)\r
1869                 return ar;\r
1870 \r
1871         var st = str.split(';');\r
1872 \r
1873         tinyMCE.clearArray(ar);\r
1874 \r
1875         for (var i=0; i<st.length; i++) {\r
1876                 if (st[i] == '')\r
1877                         continue;\r
1878 \r
1879                 var re = new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');\r
1880                 var pa = st[i].replace(re, '$1||$2').split('||');\r
1881 //tinyMCE.debug(str, pa[0] + "=" + pa[1], st[i].replace(re, '$1||$2'));\r
1882                 if (pa.length == 2)\r
1883                         ar[pa[0].toLowerCase()] = pa[1];\r
1884         }\r
1885 \r
1886         return ar;\r
1887 };\r
1888 \r
1889 TinyMCE.prototype.compressStyle = function(ar, pr, sf, res) {\r
1890         var box = new Array();\r
1891 \r
1892         box[0] = ar[pr + '-top' + sf];\r
1893         box[1] = ar[pr + '-left' + sf];\r
1894         box[2] = ar[pr + '-right' + sf];\r
1895         box[3] = ar[pr + '-bottom' + sf];\r
1896 \r
1897         for (var i=0; i<box.length; i++) {\r
1898                 if (box[i] == null)\r
1899                         return;\r
1900 \r
1901                 for (var a=0; a<box.length; a++) {\r
1902                         if (box[a] != box[i])\r
1903                                 return;\r
1904                 }\r
1905         }\r
1906 \r
1907         // They are all the same\r
1908         ar[res] = box[0];\r
1909         ar[pr + '-top' + sf] = null;\r
1910         ar[pr + '-left' + sf] = null;\r
1911         ar[pr + '-right' + sf] = null;\r
1912         ar[pr + '-bottom' + sf] = null;\r
1913 };\r
1914 \r
1915 TinyMCE.prototype.serializeStyle = function(ar) {\r
1916         var str = "";\r
1917 \r
1918         // Compress box\r
1919         tinyMCE.compressStyle(ar, "border", "", "border");\r
1920         tinyMCE.compressStyle(ar, "border", "-width", "border-width");\r
1921         tinyMCE.compressStyle(ar, "border", "-color", "border-color");\r
1922 \r
1923         for (var key in ar) {\r
1924                 var val = ar[key];\r
1925                 if (typeof(val) == 'function')\r
1926                         continue;\r
1927 \r
1928                 if (val != null && val != '') {\r
1929                         val = '' + val; // Force string\r
1930 \r
1931                         // Fix style URL\r
1932                         val = val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)", 'gi'), "url('$1')");\r
1933 \r
1934                         // Convert URL\r
1935                         if (val.indexOf('url(') != -1 && tinyMCE.getParam('convert_urls')) {\r
1936                                 var m = new RegExp("url\\('(.*?)'\\)").exec(val);\r
1937 \r
1938                                 if (m.length > 1)\r
1939                                         val = "url('" + eval(tinyMCE.getParam('urlconverter_callback') + "(m[1], null, true);") + "')";\r
1940                         }\r
1941 \r
1942                         // Force HEX colors\r
1943                         if (tinyMCE.getParam("force_hex_style_colors"))\r
1944                                 val = tinyMCE.convertRGBToHex(val, true);\r
1945 \r
1946                         if (val != "url('')")\r
1947                                 str += key.toLowerCase() + ": " + val + "; ";\r
1948                 }\r
1949         }\r
1950 \r
1951         if (new RegExp('; $').test(str))\r
1952                 str = str.substring(0, str.length - 2);\r
1953 \r
1954         return str;\r
1955 };\r
1956 \r
1957 TinyMCE.prototype.convertRGBToHex = function(s, k) {\r
1958         if (s.toLowerCase().indexOf('rgb') != -1) {\r
1959                 var re = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");\r
1960                 var rgb = s.replace(re, "$1,$2,$3,$4,$5").split(',');\r
1961                 if (rgb.length == 5) {\r
1962                         r = parseInt(rgb[1]).toString(16);\r
1963                         g = parseInt(rgb[2]).toString(16);\r
1964                         b = parseInt(rgb[3]).toString(16);\r
1965 \r
1966                         r = r.length == 1 ? '0' + r : r;\r
1967                         g = g.length == 1 ? '0' + g : g;\r
1968                         b = b.length == 1 ? '0' + b : b;\r
1969 \r
1970                         s = "#" + r + g + b;\r
1971 \r
1972                         if (k)\r
1973                                 s = rgb[0] + s + rgb[4];\r
1974                 }\r
1975         }\r
1976 \r
1977         return s;\r
1978 };\r
1979 \r
1980 TinyMCE.prototype.convertHexToRGB = function(s) {\r
1981         if (s.indexOf('#') != -1) {\r
1982                 s = s.replace(new RegExp('[^0-9A-F]', 'gi'), '');\r
1983                 return "rgb(" + parseInt(s.substring(0, 2), 16) + "," + parseInt(s.substring(2, 4), 16) + "," + parseInt(s.substring(4, 6), 16) + ")";\r
1984         }\r
1985 \r
1986         return s;\r
1987 };\r
1988 \r
1989 TinyMCE.prototype._verifyClass = function(node) {\r
1990         // Sometimes the class gets set to null, weird Gecko bug?\r
1991         if (tinyMCE.isGecko) {\r
1992                 var className = node.getAttribute('class');\r
1993                 if (!className)\r
1994                         return false;\r
1995         }\r
1996 \r
1997         // Trim CSS class\r
1998         if (tinyMCE.isMSIE)\r
1999                 var className = node.getAttribute('className');\r
2000 \r
2001         if (tinyMCE.cleanup_verify_css_classes && tinyMCE.cleanup_on_save) {\r
2002                 var csses = tinyMCE.getCSSClasses();\r
2003                 nonDefinedCSS = true;\r
2004                 for (var c=0; c<csses.length; c++) {\r
2005                         if (csses[c] == className) {\r
2006                                 nonDefinedCSS = false;\r
2007                                 break;\r
2008                         }\r
2009                 }\r
2010 \r
2011                 if (nonDefinedCSS && className.indexOf('mce_') != 0) {\r
2012                         node.removeAttribute('className');\r
2013                         node.removeAttribute('class');\r
2014                         return false;\r
2015                 }\r
2016         }\r
2017 \r
2018         return true;\r
2019 };\r
2020 \r
2021 TinyMCE.prototype.cleanupNode = function(node) {\r
2022         var output = "";\r
2023 \r
2024         switch (node.nodeType) {\r
2025                 case 1: // Element\r
2026                         var elementData = tinyMCE._cleanupElementName(node.nodeName, node);\r
2027                         var elementName = elementData ? elementData.element_name : null;\r
2028                         var elementValidAttribs = elementData ? elementData.valid_attribs : null;\r
2029                         var elementAttribs = "";\r
2030                         var openTag = false, nonEmptyTag = false;\r
2031 \r
2032                         if (elementName != null && elementName.charAt(0) == '+') {\r
2033                                 elementName = elementName.substring(1);\r
2034                                 openTag = true;\r
2035                         }\r
2036 \r
2037                         if (elementName != null && elementName.charAt(0) == '-') {\r
2038                                 elementName = elementName.substring(1);\r
2039                                 nonEmptyTag = true;\r
2040                         }\r
2041 \r
2042                         // Checking DOM tree for MSIE weirdness!!\r
2043                         if (tinyMCE.isMSIE && tinyMCE.settings['fix_content_duplication']) {\r
2044                                 var lookup = tinyMCE.cleanup_elementLookupTable;\r
2045 \r
2046                                 for (var i=0; i<lookup.length; i++) {\r
2047                                         // Found element reference else were, hmm?\r
2048                                         if (lookup[i] == node)\r
2049                                                 return output;\r
2050                                 }\r
2051 \r
2052                                 // Add element to lookup table\r
2053                                 lookup[lookup.length] = node;\r
2054                         }\r
2055 \r
2056                         // Element not valid (only render children)\r
2057                         if (!elementName) {\r
2058                                 if (node.hasChildNodes()) {\r
2059                                         for (var i=0; i<node.childNodes.length; i++)\r
2060                                                 output += this.cleanupNode(node.childNodes[i]);\r
2061                                 }\r
2062 \r
2063                                 return output;\r
2064                         }\r
2065 \r
2066                         if (tinyMCE.cleanup_on_save) {\r
2067                                 if (node.nodeName == "A" && node.className == "mceItemAnchor") {\r
2068                                         if (node.hasChildNodes()) {\r
2069                                                 for (var i=0; i<node.childNodes.length; i++)\r
2070                                                         output += this.cleanupNode(node.childNodes[i]);\r
2071                                         }\r
2072 \r
2073                                         return '<a name="' + this.convertStringToXML(node.getAttribute("name")) + '"></a>' + output;\r
2074                                 }\r
2075                         }\r
2076 \r
2077                         // Remove deprecated attributes\r
2078                         var re = new RegExp("^(TABLE|TD|TR)$");\r
2079                         if (re.test(node.nodeName)) {\r
2080                                 // Move attrib to style\r
2081                                 if ((node.nodeName != "TABLE" || tinyMCE.cleanup_inline_styles) && (width = tinyMCE.getAttrib(node, "width")) != '') {\r
2082                                         node.style.width = width.indexOf('%') != -1 ? width : width.replace(/[^0-9]/gi, '') + "px";\r
2083                                         node.removeAttribute("width");\r
2084                                 }\r
2085 \r
2086                                 // Is table and not inline\r
2087                                 if ((node.nodeName == "TABLE" && !tinyMCE.cleanup_inline_styles) && node.style.width != '') {\r
2088                                         tinyMCE.setAttrib(node, "width", node.style.width.replace('px',''));\r
2089                                         node.style.width = '';\r
2090                                 }\r
2091 \r
2092                                 // Move attrib to style\r
2093                                 if ((height = tinyMCE.getAttrib(node, "height")) != '') {\r
2094                                         height = "" + height; // Force string\r
2095                                         node.style.height = height.indexOf('%') != -1 ? height : height.replace(/[^0-9]/gi, '') + "px";\r
2096                                         node.removeAttribute("height");\r
2097                                 }\r
2098                         }\r
2099 \r
2100                         // Handle inline/outline styles\r
2101                         if (tinyMCE.cleanup_inline_styles) {\r
2102                                 var re = new RegExp("^(TABLE|TD|TR|IMG|HR)$");\r
2103                                 if (re.test(node.nodeName) && tinyMCE.getAttrib(node, "class").indexOf('mceItem') == -1) {\r
2104                                         tinyMCE._moveStyle(node, 'width', 'width');\r
2105                                         tinyMCE._moveStyle(node, 'height', 'height');\r
2106                                         tinyMCE._moveStyle(node, 'borderWidth', 'border');\r
2107                                         tinyMCE._moveStyle(node, '', 'vspace');\r
2108                                         tinyMCE._moveStyle(node, '', 'hspace');\r
2109                                         tinyMCE._moveStyle(node, 'textAlign', 'align');\r
2110                                         tinyMCE._moveStyle(node, 'backgroundColor', 'bgColor');\r
2111                                         tinyMCE._moveStyle(node, 'borderColor', 'borderColor');\r
2112                                         tinyMCE._moveStyle(node, 'backgroundImage', 'background');\r
2113 \r
2114                                         // Refresh element in old MSIE\r
2115                                         if (tinyMCE.isMSIE5)\r
2116                                                 node.outerHTML = node.outerHTML;\r
2117                                 } else if (tinyMCE.isBlockElement(node))\r
2118                                         tinyMCE._moveStyle(node, 'textAlign', 'align');\r
2119 \r
2120                                 if (node.nodeName == "FONT")\r
2121                                         tinyMCE._moveStyle(node, 'color', 'color');\r
2122                         }\r
2123 \r
2124                         // Set attrib data\r
2125                         if (elementValidAttribs) {\r
2126                                 for (var a=1; a<elementValidAttribs.length; a++) {\r
2127                                         var attribName, attribDefaultValue, attribForceValue, attribValue;\r
2128 \r
2129                                         attribName = elementValidAttribs[a][0];\r
2130                                         attribDefaultValue = elementValidAttribs[a][1];\r
2131                                         attribForceValue = elementValidAttribs[a][2];\r
2132 \r
2133                                         if (attribDefaultValue != null || attribForceValue != null) {\r
2134                                                 var attribValue = node.getAttribute(attribName);\r
2135 \r
2136                                                 if (node.getAttribute(attribName) == null || node.getAttribute(attribName) == "")\r
2137                                                         attribValue = attribDefaultValue;\r
2138 \r
2139                                                 attribValue = attribForceValue ? attribForceValue : attribValue;\r
2140 \r
2141                                                 // Is to generate id\r
2142                                                 if (attribValue == "{$uid}")\r
2143                                                         attribValue = "uid_" + (tinyMCE.cleanup_idCount++);\r
2144 \r
2145                                                 // Add visual aid class\r
2146                                                 if (attribName == "class")\r
2147                                                         attribValue = tinyMCE.getVisualAidClass(attribValue, tinyMCE.cleanup_on_save);\r
2148 \r
2149                                                 node.setAttribute(attribName, attribValue);\r
2150                                                 //alert(attribName + "=" + attribValue);\r
2151                                         }\r
2152                                 }\r
2153                         }\r
2154 \r
2155                         if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && elementName == "style")\r
2156                                 return "<style>" + node.innerHTML + "</style>";\r
2157 \r
2158                         // Remove empty tables\r
2159                         if (elementName == "table" && !node.hasChildNodes())\r
2160                                 return "";\r
2161 \r
2162                         // Handle element attributes\r
2163                         if (node.attributes.length > 0) {\r
2164                                 var lastAttrib = "";\r
2165 \r
2166                                 for (var i=0; i<node.attributes.length; i++) {\r
2167                                         if (node.attributes[i].specified) {\r
2168                                                 // Is the attrib already processed (removed duplicate attributes in opera TD[align=left])\r
2169                                                 if (tinyMCE.isOpera) {\r
2170                                                         if (node.attributes[i].nodeName == lastAttrib)\r
2171                                                                 continue;\r
2172 \r
2173                                                         lastAttrib = node.attributes[i].nodeName;\r
2174                                                 }\r
2175 \r
2176                                                 // tinyMCE.debug(node.nodeName, node.attributes[i].nodeName, node.attributes[i].nodeValue, node.innerHTML);\r
2177                                                 var attrib = tinyMCE._cleanupAttribute(elementValidAttribs, elementName, node.attributes[i], node);\r
2178                                                 if (attrib && attrib.value != "")\r
2179                                                         elementAttribs += " " + attrib.name + "=" + '"' + this.convertStringToXML("" + attrib.value) + '"';\r
2180                                         }\r
2181                                 }\r
2182                         }\r
2183 \r
2184                         // MSIE table summary fix (MSIE 5.5)\r
2185                         if (tinyMCE.isMSIE && elementName == "table" && node.getAttribute("summary") != null && elementAttribs.indexOf('summary') == -1) {\r
2186                                 var summary = tinyMCE.getAttrib(node, 'summary');\r
2187                                 if (summary != '')\r
2188                                         elementAttribs += " summary=" + '"' + this.convertStringToXML(summary) + '"';\r
2189                         }\r
2190 \r
2191                         // Handle missing attributes in MSIE 5.5\r
2192                         if (tinyMCE.isMSIE5 && /^(td|img|a)$/.test(elementName)) {\r
2193                                 var ma = new Array("scope", "longdesc", "hreflang", "charset", "type");\r
2194 \r
2195                                 for (var u=0; u<ma.length; u++) {\r
2196                                         if (node.getAttribute(ma[u]) != null) {\r
2197                                                 var s = tinyMCE.getAttrib(node, ma[u]);\r
2198 \r
2199                                                 if (s != '')\r
2200                                                         elementAttribs += " " + ma[u] + "=" + '"' + this.convertStringToXML(s) + '"';\r
2201                                         }\r
2202                                 }\r
2203                         }\r
2204 \r
2205                         // MSIE form element issue\r
2206                         if (tinyMCE.isMSIE && elementName == "input") {\r
2207                                 if (node.type) {\r
2208                                         if (!elementAttribs.match(/ type=/g))\r
2209                                                 elementAttribs += " type=" + '"' + node.type + '"';\r
2210                                 }\r
2211 \r
2212                                 if (node.value) {\r
2213                                         if (!elementAttribs.match(/ value=/g))\r
2214                                                 elementAttribs += " value=" + '"' + node.value + '"';\r
2215                                 }\r
2216                         }\r
2217 \r
2218                         // Add nbsp to some elements\r
2219                         if ((elementName == "p" || elementName == "td") && (node.innerHTML == "" || node.innerHTML == "&nbsp;"))\r
2220                                 return "<" + elementName + elementAttribs + ">" + this.convertStringToXML(String.fromCharCode(160)) + "</" + elementName + ">";\r
2221 \r
2222                         // Is MSIE script element\r
2223                         if (tinyMCE.isMSIE && elementName == "script")\r
2224                                 return "<" + elementName + elementAttribs + ">" + node.text + "</" + elementName + ">";\r
2225 \r
2226                         // Clean up children\r
2227                         if (node.hasChildNodes()) {\r
2228                                 // If not empty span\r
2229                                 if (!(elementName == "span" && elementAttribs == "" && tinyMCE.getParam("trim_span_elements"))) {\r
2230                                         // Force BR\r
2231                                         if (elementName == "p" && tinyMCE.cleanup_force_br_newlines)\r
2232                                                 output += "<div" + elementAttribs + ">";\r
2233                                         else\r
2234                                                 output += "<" + elementName + elementAttribs + ">";\r
2235                                 }\r
2236 \r
2237                                 for (var i=0; i<node.childNodes.length; i++)\r
2238                                         output += this.cleanupNode(node.childNodes[i]);\r
2239 \r
2240                                 // If not empty span\r
2241                                 if (!(elementName == "span" && elementAttribs == "" && tinyMCE.getParam("trim_span_elements"))) {\r
2242                                         // Force BR\r
2243                                         if (elementName == "p" && tinyMCE.cleanup_force_br_newlines)\r
2244                                                 output += "</div><br />";\r
2245                                         else\r
2246                                                 output += "</" + elementName + ">";\r
2247                                 }\r
2248                         } else {\r
2249                                 if (!nonEmptyTag) {\r
2250                                         if (openTag)\r
2251                                                 output += "<" + elementName + elementAttribs + "></" + elementName + ">";\r
2252                                         else\r
2253                                                 output += "<" + elementName + elementAttribs + " />";\r
2254                                 }\r
2255                         }\r
2256 \r
2257                         return output;\r
2258 \r
2259                 case 3: // Text\r
2260                         // Do not convert script elements\r
2261                         if (node.parentNode.nodeName == "SCRIPT" || node.parentNode.nodeName == "NOSCRIPT" || node.parentNode.nodeName == "STYLE")\r
2262                                 return node.nodeValue;\r
2263 \r
2264                         return this.convertStringToXML(node.nodeValue);\r
2265 \r
2266                 case 8: // Comment\r
2267                         return "<!--" + node.nodeValue + "-->";\r
2268 \r
2269                 default: // Unknown\r
2270                         return "[UNKNOWN NODETYPE " + node.nodeType + "]";\r
2271         }\r
2272 };\r
2273 \r
2274 TinyMCE.prototype.convertStringToXML = function(html_data) {\r
2275     var output = "";\r
2276 \r
2277         for (var i=0; i<html_data.length; i++) {\r
2278                 var chr = html_data.charCodeAt(i);\r
2279 \r
2280                 // Numeric entities\r
2281                 if (tinyMCE.settings['entity_encoding'] == "numeric") {\r
2282                         if (chr > 127)\r
2283                                 output += '&#' + chr + ";";\r
2284                         else\r
2285                                 output += String.fromCharCode(chr);\r
2286 \r
2287                         continue;\r
2288                 }\r
2289 \r
2290                 // Raw entities\r
2291                 if (tinyMCE.settings['entity_encoding'] == "raw") {\r
2292                         output += String.fromCharCode(chr);\r
2293                         continue;\r
2294                 }\r
2295 \r
2296                 // Named entities\r
2297                 if (typeof(tinyMCE.settings['cleanup_entities']["c" + chr]) != 'undefined' && tinyMCE.settings['cleanup_entities']["c" + chr] != '')\r
2298                         output += '&' + tinyMCE.settings['cleanup_entities']["c" + chr] + ';';\r
2299                 else\r
2300                         output += '' + String.fromCharCode(chr);\r
2301     }\r
2302 \r
2303     return output;\r
2304 };\r
2305 \r
2306 TinyMCE.prototype._getCleanupElementName = function(chunk) {\r
2307         var pos;\r
2308 \r
2309         if (chunk.charAt(0) == '+')\r
2310                 chunk = chunk.substring(1);\r
2311 \r
2312         if (chunk.charAt(0) == '-')\r
2313                 chunk = chunk.substring(1);\r
2314 \r
2315         if ((pos = chunk.indexOf('/')) != -1)\r
2316                 chunk = chunk.substring(0, pos);\r
2317 \r
2318         if ((pos = chunk.indexOf('[')) != -1)\r
2319                 chunk = chunk.substring(0, pos);\r
2320 \r
2321         return chunk;\r
2322 };\r
2323 \r
2324 TinyMCE.prototype._initCleanup = function() {\r
2325         // Parse valid elements and attributes\r
2326         var validElements = tinyMCE.settings["valid_elements"];\r
2327         validElements = validElements.split(',');\r
2328 \r
2329         // Handle extended valid elements\r
2330         var extendedValidElements = tinyMCE.settings["extended_valid_elements"];\r
2331         extendedValidElements = extendedValidElements.split(',');\r
2332         for (var i=0; i<extendedValidElements.length; i++) {\r
2333                 var elementName = this._getCleanupElementName(extendedValidElements[i]);\r
2334                 var skipAdd = false;\r
2335 \r
2336                 // Check if it's defined before, if so override that one\r
2337                 for (var x=0; x<validElements.length; x++) {\r
2338                         if (this._getCleanupElementName(validElements[x]) == elementName) {\r
2339                                 validElements[x] = extendedValidElements[i];\r
2340                                 skipAdd = true;\r
2341                                 break;\r
2342                         }\r
2343                 }\r
2344 \r
2345                 if (!skipAdd)\r
2346                         validElements[validElements.length] = extendedValidElements[i];\r
2347         }\r
2348 \r
2349         for (var i=0; i<validElements.length; i++) {\r
2350                 var item = validElements[i];\r
2351 \r
2352                 item = item.replace('[','|');\r
2353                 item = item.replace(']','');\r
2354 \r
2355                 // Split and convert\r
2356                 var attribs = item.split('|');\r
2357                 for (var x=0; x<attribs.length; x++)\r
2358                         attribs[x] = attribs[x].toLowerCase();\r
2359 \r
2360                 // Handle change elements\r
2361                 attribs[0] = attribs[0].split('/');\r
2362 \r
2363                 // Handle default attribute values\r
2364                 for (var x=1; x<attribs.length; x++) {\r
2365                         var attribName = attribs[x];\r
2366                         var attribDefault = null;\r
2367                         var attribForce = null;\r
2368                         var attribMustBe = null;\r
2369 \r
2370                         // Default value\r
2371                         if ((pos = attribName.indexOf('=')) != -1) {\r
2372                                 attribDefault = attribName.substring(pos+1);\r
2373                                 attribName = attribName.substring(0, pos);\r
2374                         }\r
2375 \r
2376                         // Force check\r
2377                         if ((pos = attribName.indexOf(':')) != -1) {\r
2378                                 attribForce = attribName.substring(pos+1);\r
2379                                 attribName = attribName.substring(0, pos);\r
2380                         }\r
2381 \r
2382                         // Force check\r
2383                         if ((pos = attribName.indexOf('<')) != -1) {\r
2384                                 attribMustBe = attribName.substring(pos+1).split('?');\r
2385                                 attribName = attribName.substring(0, pos);\r
2386                         }\r
2387 \r
2388                         attribs[x] = new Array(attribName, attribDefault, attribForce, attribMustBe);\r
2389                 }\r
2390 \r
2391                 validElements[i] = attribs;\r
2392         }\r
2393 \r
2394         var invalidElements = tinyMCE.settings['invalid_elements'].split(',');\r
2395         for (var i=0; i<invalidElements.length; i++)\r
2396                 invalidElements[i] = invalidElements[i].toLowerCase();\r
2397 \r
2398         // Set these for performance\r
2399         tinyMCE.settings['cleanup_validElements'] = validElements;\r
2400         tinyMCE.settings['cleanup_invalidElements'] = invalidElements;\r
2401 };\r
2402 \r
2403 TinyMCE.prototype._cleanupHTML = function(inst, doc, config, element, visual, on_save) {\r
2404         if (!tinyMCE.settings['cleanup']) {\r
2405                 tinyMCE.handleVisualAid(inst.getBody(), true, false, inst);\r
2406 \r
2407                 var html = element.innerHTML;\r
2408 \r
2409                 // Remove mce_href/mce_src\r
2410                 html = html.replace(new RegExp('(mce_href|mce_src)=".*?"', 'gi'), '');\r
2411                 html = html.replace(/\s+>/gi, '>');\r
2412 \r
2413                 return html;\r
2414         }\r
2415 \r
2416         if (on_save && tinyMCE.getParam("convert_fonts_to_spans"))\r
2417                 tinyMCE.convertFontsToSpans(doc);\r
2418 \r
2419         // Call custom cleanup code\r
2420         tinyMCE._customCleanup(inst, on_save ? "get_from_editor_dom" : "insert_to_editor_dom", doc.body);\r
2421 \r
2422         // Move bgcolor to style\r
2423         var n = doc.getElementsByTagName("font");\r
2424         for (var i=0; i<n.length; i++) {\r
2425                 var c = "";\r
2426                 if ((c = tinyMCE.getAttrib(n[i], "bgcolor")) != "") {\r
2427                         n[i].style.backgroundColor = c;\r
2428                         tinyMCE.setAttrib(n[i], "bgcolor", "");\r
2429                 }\r
2430         }\r
2431 \r
2432         // Set these for performance\r
2433         tinyMCE.cleanup_validElements = tinyMCE.settings['cleanup_validElements'];\r
2434         tinyMCE.cleanup_invalidElements = tinyMCE.settings['cleanup_invalidElements'];\r
2435         tinyMCE.cleanup_verify_html = tinyMCE.settings['verify_html'];\r
2436         tinyMCE.cleanup_force_br_newlines = tinyMCE.settings['force_br_newlines'];\r
2437         tinyMCE.cleanup_urlconverter_callback = tinyMCE.settings['urlconverter_callback'];\r
2438         tinyMCE.cleanup_verify_css_classes = tinyMCE.settings['verify_css_classes'];\r
2439         tinyMCE.cleanup_visual_table_class = tinyMCE.settings['visual_table_class'];\r
2440         tinyMCE.cleanup_apply_source_formatting = tinyMCE.settings['apply_source_formatting'];\r
2441         tinyMCE.cleanup_inline_styles = tinyMCE.settings['inline_styles'];\r
2442         tinyMCE.cleanup_visual_aid = visual;\r
2443         tinyMCE.cleanup_on_save = on_save;\r
2444         tinyMCE.cleanup_idCount = 0;\r
2445         tinyMCE.cleanup_elementLookupTable = new Array();\r
2446 \r
2447         var startTime = new Date().getTime();\r
2448 \r
2449         // Cleanup madness that breaks the editor in MSIE\r
2450         if (tinyMCE.isMSIE) {\r
2451                 // Remove null ids from HR elements, results in runtime error\r
2452                 var nodes = element.getElementsByTagName("hr");\r
2453                 for (var i=0; i<nodes.length; i++) {\r
2454                         if (nodes[i].id == "null")\r
2455                                 nodes[i].removeAttribute("id");\r
2456                 }\r
2457 \r
2458                 tinyMCE.setInnerHTML(element, tinyMCE.regexpReplace(element.innerHTML, '<p>[ \n\r]*<hr.*>[ \n\r]*</p>', '<hr />', 'gi'));\r
2459                 tinyMCE.setInnerHTML(element, tinyMCE.regexpReplace(element.innerHTML, '<!([^-(DOCTYPE)]* )|<!/[^-]*>', '', 'gi'));\r
2460         }\r
2461 \r
2462         var html = this.cleanupNode(element);\r
2463 \r
2464         if (tinyMCE.settings['debug'])\r
2465                 tinyMCE.debug("Cleanup process executed in: " + (new Date().getTime()-startTime) + " ms.");\r
2466 \r
2467         // Remove pesky HR paragraphs and other crap\r
2468         html = tinyMCE.regexpReplace(html, '<p><hr /></p>', '<hr />');\r
2469         html = tinyMCE.regexpReplace(html, '<p>&nbsp;</p><hr /><p>&nbsp;</p>', '<hr />');\r
2470         html = tinyMCE.regexpReplace(html, '<td>\\s*<br />\\s*</td>', '<td>&nbsp;</td>');\r
2471         html = tinyMCE.regexpReplace(html, '<p>\\s*<br />\\s*</p>', '<p>&nbsp;</p>');\r
2472         html = tinyMCE.regexpReplace(html, '<p>\\s*&nbsp;\\s*<br />\\s*&nbsp;\\s*</p>', '<p>&nbsp;</p>');\r
2473         html = tinyMCE.regexpReplace(html, '<p>\\s*&nbsp;\\s*<br />\\s*</p>', '<p>&nbsp;</p>');\r
2474         html = tinyMCE.regexpReplace(html, '<p>\\s*<br />\\s*&nbsp;\\s*</p>', '<p>&nbsp;</p>');\r
2475 \r
2476         // Remove empty anchors\r
2477         html = html.replace(new RegExp('<a>(.*?)</a>', 'gi'), '$1');\r
2478 \r
2479         // Remove some mozilla crap\r
2480         if (!tinyMCE.isMSIE)\r
2481                 html = html.replace(new RegExp('<o:p _moz-userdefined="" />', 'g'), "");\r
2482 \r
2483         if (tinyMCE.settings['remove_linebreaks'])\r
2484                 html = html.replace(new RegExp('\r|\n', 'g'), ' ');\r
2485 \r
2486         if (tinyMCE.getParam('apply_source_formatting')) {\r
2487                 html = html.replace(new RegExp('<(p|div)([^>]*)>', 'g'), "\n<$1$2>\n");\r
2488                 html = html.replace(new RegExp('<\/(p|div)([^>]*)>', 'g'), "\n</$1$2>\n");\r
2489                 html = html.replace(new RegExp('<br />', 'g'), "<br />\n");\r
2490         }\r
2491 \r
2492         if (tinyMCE.settings['force_br_newlines']) {\r
2493                 var re = new RegExp('<p>&nbsp;</p>', 'g');\r
2494                 html = html.replace(re, "<br />");\r
2495         }\r
2496 \r
2497         if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt']) {\r
2498                 // Remove weridness!\r
2499                 var re = new RegExp('&lt;&gt;', 'g');\r
2500                 html = html.replace(re, "");\r
2501         }\r
2502 \r
2503         // Call custom cleanup code\r
2504         html = tinyMCE._customCleanup(inst, on_save ? "get_from_editor" : "insert_to_editor", html);\r
2505 \r
2506         // Emtpy node, return empty\r
2507         var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "").toLowerCase();\r
2508         if (chk == "<br/>" || chk == "<br>" || chk == "<p>&nbsp;</p>" || chk == "<p>&#160;</p>" || chk == "<p></p>")\r
2509                 html = "";\r
2510 \r
2511         if (tinyMCE.settings["preformatted"])\r
2512                 return "<pre>" + html + "</pre>";\r
2513 \r
2514         return html;\r
2515 };\r
2516 \r
2517 TinyMCE.prototype.insertLink = function(href, target, title, onclick, style_class) {\r
2518         tinyMCE.execCommand('mceBeginUndoLevel');\r
2519 \r
2520         if (this.selectedInstance && this.selectedElement && this.selectedElement.nodeName.toLowerCase() == "img") {\r
2521                 var doc = this.selectedInstance.getDoc();\r
2522                 var linkElement = tinyMCE.getParentElement(this.selectedElement, "a");\r
2523                 var newLink = false;\r
2524 \r
2525                 if (!linkElement) {\r
2526                         linkElement = doc.createElement("a");\r
2527                         newLink = true;\r
2528                 }\r
2529 \r
2530                 var mhref = href;\r
2531                 var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, linkElement);");\r
2532                 mhref = tinyMCE.getParam('convert_urls') ? href : mhref;\r
2533 \r
2534                 tinyMCE.setAttrib(linkElement, 'href', thref);\r
2535                 tinyMCE.setAttrib(linkElement, 'mce_href', mhref);\r
2536                 tinyMCE.setAttrib(linkElement, 'target', target);\r
2537                 tinyMCE.setAttrib(linkElement, 'title', title);\r
2538         tinyMCE.setAttrib(linkElement, 'onclick', onclick);\r
2539                 tinyMCE.setAttrib(linkElement, 'class', style_class);\r
2540 \r
2541                 if (newLink) {\r
2542                         linkElement.appendChild(this.selectedElement.cloneNode(true));\r
2543                         this.selectedElement.parentNode.replaceChild(linkElement, this.selectedElement);\r
2544                 }\r
2545 \r
2546                 return;\r
2547         }\r
2548 \r
2549         if (!this.linkElement && this.selectedInstance) {\r
2550                 if (tinyMCE.isSafari) {\r
2551                         tinyMCE.execCommand("mceInsertContent", false, '<a href="' + tinyMCE.uniqueURL + '">' + this.selectedInstance.getSelectedHTML() + '</a>');\r
2552                 } else\r
2553                         this.selectedInstance.contentDocument.execCommand("createlink", false, tinyMCE.uniqueURL);\r
2554 \r
2555                 tinyMCE.linkElement = this.getElementByAttributeValue(this.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);\r
2556 \r
2557                 var elementArray = this.getElementsByAttributeValue(this.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);\r
2558 \r
2559                 for (var i=0; i<elementArray.length; i++) {\r
2560                         var mhref = href;\r
2561                         var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, elementArray[i]);");\r
2562                         mhref = tinyMCE.getParam('convert_urls') ? href : mhref;\r
2563 \r
2564                         tinyMCE.setAttrib(elementArray[i], 'href', thref);\r
2565                         tinyMCE.setAttrib(elementArray[i], 'mce_href', mhref);\r
2566                         tinyMCE.setAttrib(elementArray[i], 'target', target);\r
2567                         tinyMCE.setAttrib(elementArray[i], 'title', title);\r
2568             tinyMCE.setAttrib(elementArray[i], 'onclick', onclick);\r
2569                         tinyMCE.setAttrib(elementArray[i], 'class', style_class);\r
2570                 }\r
2571 \r
2572                 tinyMCE.linkElement = elementArray[0];\r
2573         }\r
2574 \r
2575         if (this.linkElement) {\r
2576                 var mhref = href;\r
2577                 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, this.linkElement);");\r
2578                 mhref = tinyMCE.getParam('convert_urls') ? href : mhref;\r
2579 \r
2580                 tinyMCE.setAttrib(this.linkElement, 'href', href);\r
2581                 tinyMCE.setAttrib(this.linkElement, 'mce_href', mhref);\r
2582                 tinyMCE.setAttrib(this.linkElement, 'target', target);\r
2583                 tinyMCE.setAttrib(this.linkElement, 'title', title);\r
2584         tinyMCE.setAttrib(this.linkElement, 'onclick', onclick);\r
2585                 tinyMCE.setAttrib(this.linkElement, 'class', style_class);\r
2586         }\r
2587 \r
2588         tinyMCE.execCommand('mceEndUndoLevel');\r
2589 };\r
2590 \r
2591 TinyMCE.prototype.insertImage = function(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout) {\r
2592         tinyMCE.execCommand('mceBeginUndoLevel');\r
2593 \r
2594         if (src == "")\r
2595                 return;\r
2596 \r
2597         if (!this.imgElement && tinyMCE.isSafari) {\r
2598                 var html = "";\r
2599 \r
2600                 html += '<img src="' + src + '" alt="' + alt + '"';\r
2601                 html += ' border="' + border + '" hspace="' + hspace + '"';\r
2602                 html += ' vspace="' + vspace + '" width="' + width + '"';\r
2603                 html += ' height="' + height + '" align="' + align + '" title="' + title + '" onmouseover="' + onmouseover + '" onmouseout="' + onmouseout + '" />';\r
2604 \r
2605                 tinyMCE.execCommand("mceInsertContent", false, html);\r
2606         } else {\r
2607                 if (!this.imgElement && this.selectedInstance) {\r
2608                         if (tinyMCE.isSafari)\r
2609                                 tinyMCE.execCommand("mceInsertContent", false, '<img src="' + tinyMCE.uniqueURL + '" />');\r
2610                         else\r
2611                                 this.selectedInstance.contentDocument.execCommand("insertimage", false, tinyMCE.uniqueURL);\r
2612 \r
2613                         tinyMCE.imgElement = this.getElementByAttributeValue(this.selectedInstance.contentDocument.body, "img", "src", tinyMCE.uniqueURL);\r
2614                 }\r
2615         }\r
2616 \r
2617         if (this.imgElement) {\r
2618                 var needsRepaint = false;\r
2619                 var msrc = src;\r
2620 \r
2621                 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, tinyMCE.imgElement);");\r
2622 \r
2623                 if (tinyMCE.getParam('convert_urls'))\r
2624                         msrc = src;\r
2625 \r
2626                 if (onmouseover && onmouseover != "")\r
2627                         onmouseover = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, tinyMCE.imgElement);") + "';";\r
2628 \r
2629                 if (onmouseout && onmouseout != "")\r
2630                         onmouseout = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, tinyMCE.imgElement);") + "';";\r
2631 \r
2632                 // Use alt as title if it's undefined\r
2633                 if (typeof(title) == "undefined")\r
2634                         title = alt;\r
2635 \r
2636                 if (width != this.imgElement.getAttribute("width") || height != this.imgElement.getAttribute("height") || align != this.imgElement.getAttribute("align"))\r
2637                         needsRepaint = true;\r
2638 \r
2639                 tinyMCE.setAttrib(this.imgElement, 'src', src);\r
2640                 tinyMCE.setAttrib(this.imgElement, 'mce_src', msrc);\r
2641                 tinyMCE.setAttrib(this.imgElement, 'alt', alt);\r
2642                 tinyMCE.setAttrib(this.imgElement, 'title', title);\r
2643                 tinyMCE.setAttrib(this.imgElement, 'align', align);\r
2644                 tinyMCE.setAttrib(this.imgElement, 'border', border, true);\r
2645                 tinyMCE.setAttrib(this.imgElement, 'hspace', hspace, true);\r
2646                 tinyMCE.setAttrib(this.imgElement, 'vspace', vspace, true);\r
2647                 tinyMCE.setAttrib(this.imgElement, 'width', width, true);\r
2648                 tinyMCE.setAttrib(this.imgElement, 'height', height, true);\r
2649                 tinyMCE.setAttrib(this.imgElement, 'onmouseover', onmouseover);\r
2650                 tinyMCE.setAttrib(this.imgElement, 'onmouseout', onmouseout);\r
2651 \r
2652                 // Fix for bug #989846 - Image resize bug\r
2653                 if (width && width != "")\r
2654                         this.imgElement.style.pixelWidth = width;\r
2655 \r
2656                 if (height && height != "")\r
2657                         this.imgElement.style.pixelHeight = height;\r
2658 \r
2659                 if (needsRepaint)\r
2660                         tinyMCE.selectedInstance.repaint();\r
2661         }\r
2662 \r
2663         tinyMCE.execCommand('mceEndUndoLevel');\r
2664 };\r
2665 \r
2666 TinyMCE.prototype.getElementByAttributeValue = function(node, element_name, attrib, value) {\r
2667         var elements = this.getElementsByAttributeValue(node, element_name, attrib, value);\r
2668         if (elements.length == 0)\r
2669                 return null;\r
2670 \r
2671         return elements[0];\r
2672 };\r
2673 \r
2674 TinyMCE.prototype.getElementsByAttributeValue = function(node, element_name, attrib, value) {\r
2675         var elements = new Array();\r
2676 \r
2677         if (node && node.nodeName.toLowerCase() == element_name) {\r
2678                 if (node.getAttribute(attrib) && node.getAttribute(attrib).indexOf(value) != -1)\r
2679                         elements[elements.length] = node;\r
2680         }\r
2681 \r
2682         if (node && node.hasChildNodes()) {\r
2683                 for (var x=0, n=node.childNodes.length; x<n; x++) {\r
2684                         var childElements = this.getElementsByAttributeValue(node.childNodes[x], element_name, attrib, value);\r
2685                         for (var i=0, m=childElements.length; i<m; i++)\r
2686                                 elements[elements.length] = childElements[i];\r
2687                 }\r
2688         }\r
2689 \r
2690         return elements;\r
2691 };\r
2692 \r
2693 TinyMCE.prototype.isBlockElement = function(node) {\r
2694         return node != null && node.nodeType == 1 && this.blockRegExp.test(node.nodeName);\r
2695 };\r
2696 \r
2697 TinyMCE.prototype.getParentBlockElement = function(node) {\r
2698         // Search up the tree for block element\r
2699         while (node) {\r
2700                 if (this.blockRegExp.test(node.nodeName))\r
2701                         return node;\r
2702 \r
2703                 node = node.parentNode;\r
2704         }\r
2705 \r
2706         return null;\r
2707 };\r
2708 \r
2709 TinyMCE.prototype.getNodeTree = function(node, node_array, type, node_name) {\r
2710         if (typeof(type) == "undefined" || node.nodeType == type && (typeof(node_name) == "undefined" || node.nodeName == node_name))\r
2711                 node_array[node_array.length] = node;\r
2712 \r
2713         if (node.hasChildNodes()) {\r
2714                 for (var i=0; i<node.childNodes.length; i++)\r
2715                         tinyMCE.getNodeTree(node.childNodes[i], node_array, type, node_name);\r
2716         }\r
2717 \r
2718         return node_array;\r
2719 };\r
2720 \r
2721 TinyMCE.prototype.getParentElement = function(node, names, attrib_name, attrib_value) {\r
2722         if (typeof(names) == "undefined") {\r
2723                 if (node.nodeType == 1)\r
2724                         return node;\r
2725 \r
2726                 // Find parent node that is a element\r
2727                 while ((node = node.parentNode) != null && node.nodeType != 1) ;\r
2728 \r
2729                 return node;\r
2730         }\r
2731 \r
2732         var namesAr = names.split(',');\r
2733 \r
2734         if (node == null)\r
2735                 return null;\r
2736 \r
2737         do {\r
2738                 for (var i=0; i<namesAr.length; i++) {\r
2739                         if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() || names == "*") {\r
2740                                 if (typeof(attrib_name) == "undefined")\r
2741                                         return node;\r
2742                                 else if (node.getAttribute(attrib_name)) {\r
2743                                         if (typeof(attrib_value) == "undefined") {\r
2744                                                 if (node.getAttribute(attrib_name) != "")\r
2745                                                         return node;\r
2746                                         } else if (node.getAttribute(attrib_name) == attrib_value)\r
2747                                                 return node;\r
2748                                 }\r
2749                         }\r
2750                 }\r
2751         } while ((node = node.parentNode) != null);\r
2752 \r
2753         return null;\r
2754 };\r
2755 \r
2756 TinyMCE.prototype.convertURL = function(url, node, on_save) {\r
2757         var prot = document.location.protocol;\r
2758         var host = document.location.hostname;\r
2759         var port = document.location.port;\r
2760 \r
2761         // Pass through file protocol\r
2762         if (prot == "file:")\r
2763                 return url;\r
2764 \r
2765         // Something is wrong, remove weirdness\r
2766         url = tinyMCE.regexpReplace(url, '(http|https):///', '/');\r
2767 \r
2768         // Mailto link or anchor (Pass through)\r
2769         if (url.indexOf('mailto:') != -1 || url.indexOf('javascript:') != -1 || tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0) == "#")\r
2770                 return url;\r
2771 \r
2772         // Fix relative/Mozilla\r
2773         if (!tinyMCE.isMSIE && !on_save && url.indexOf("://") == -1 && url.charAt(0) != '/')\r
2774                 return tinyMCE.settings['base_href'] + url;\r
2775 \r
2776         // Handle relative URLs\r
2777         if (on_save && tinyMCE.getParam('relative_urls')) {\r
2778                 var curl = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);\r
2779                 if (curl.charAt(0) == '/')\r
2780                         curl = tinyMCE.settings['document_base_prefix'] + curl;\r
2781 \r
2782                 var urlParts = tinyMCE.parseURL(curl);\r
2783                 var tmpUrlParts = tinyMCE.parseURL(tinyMCE.settings['document_base_url']);\r
2784 \r
2785                 // Force relative\r
2786                 if (urlParts['host'] == tmpUrlParts['host'] && (urlParts['port'] == tmpUrlParts['port']))\r
2787                         return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'], curl);\r
2788         }\r
2789 \r
2790         // Handle absolute URLs\r
2791         if (!tinyMCE.getParam('relative_urls')) {\r
2792                 var urlParts = tinyMCE.parseURL(url);\r
2793                 var baseUrlParts = tinyMCE.parseURL(tinyMCE.settings['base_href']);\r
2794 \r
2795                 // Force absolute URLs from relative URLs\r
2796                 url = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);\r
2797 \r
2798                 // If anchor and path is the same page\r
2799                 if (urlParts['anchor'] && urlParts['path'] == baseUrlParts['path'])\r
2800                         return "#" + urlParts['anchor'];\r
2801         }\r
2802 \r
2803         // Remove current domain\r
2804         if (tinyMCE.getParam('remove_script_host')) {\r
2805                 var start = "", portPart = "";\r
2806 \r
2807                 if (port != "")\r
2808                         portPart = ":" + port;\r
2809 \r
2810                 start = prot + "//" + host + portPart + "/";\r
2811 \r
2812                 if (url.indexOf(start) == 0)\r
2813                         url = url.substring(start.length-1);\r
2814         }\r
2815 \r
2816         return url;\r
2817 };\r
2818 \r
2819 /**\r
2820  * Parses a URL in to its diffrent components.\r
2821  */\r
2822 TinyMCE.prototype.parseURL = function(url_str) {\r
2823         var urlParts = new Array();\r
2824 \r
2825         if (url_str) {\r
2826                 var pos, lastPos;\r
2827 \r
2828                 // Parse protocol part\r
2829                 pos = url_str.indexOf('://');\r
2830                 if (pos != -1) {\r
2831                         urlParts['protocol'] = url_str.substring(0, pos);\r
2832                         lastPos = pos + 3;\r
2833                 }\r
2834 \r
2835                 // Find port or path start\r
2836                 for (var i=lastPos; i<url_str.length; i++) {\r
2837                         var chr = url_str.charAt(i);\r
2838 \r
2839                         if (chr == ':')\r
2840                                 break;\r
2841 \r
2842                         if (chr == '/')\r
2843                                 break;\r
2844                 }\r
2845                 pos = i;\r
2846 \r
2847                 // Get host\r
2848                 urlParts['host'] = url_str.substring(lastPos, pos);\r
2849 \r
2850                 // Get port\r
2851                 urlParts['port'] = "";\r
2852                 lastPos = pos;\r
2853                 if (url_str.charAt(pos) == ':') {\r
2854                         pos = url_str.indexOf('/', lastPos);\r
2855                         urlParts['port'] = url_str.substring(lastPos+1, pos);\r
2856                 }\r
2857 \r
2858                 // Get path\r
2859                 lastPos = pos;\r
2860                 pos = url_str.indexOf('?', lastPos);\r
2861 \r
2862                 if (pos == -1)\r
2863                         pos = url_str.indexOf('#', lastPos);\r
2864 \r
2865                 if (pos == -1)\r
2866                         pos = url_str.length;\r
2867 \r
2868                 urlParts['path'] = url_str.substring(lastPos, pos);\r
2869 \r
2870                 // Get query\r
2871                 lastPos = pos;\r
2872                 if (url_str.charAt(pos) == '?') {\r
2873                         pos = url_str.indexOf('#');\r
2874                         pos = (pos == -1) ? url_str.length : pos;\r
2875                         urlParts['query'] = url_str.substring(lastPos+1, pos);\r
2876                 }\r
2877 \r
2878                 // Get anchor\r
2879                 lastPos = pos;\r
2880                 if (url_str.charAt(pos) == '#') {\r
2881                         pos = url_str.length;\r
2882                         urlParts['anchor'] = url_str.substring(lastPos+1, pos);\r
2883                 }\r
2884         }\r
2885 \r
2886         return urlParts;\r
2887 };\r
2888 \r
2889 TinyMCE.prototype.serializeURL = function(up) {\r
2890         var url = "";\r
2891 \r
2892         if (up['protocol'])\r
2893                 url += up['protocol'] + "://";\r
2894 \r
2895         if (up['host'])\r
2896                 url += up['host'];\r
2897 \r
2898         if (up['port'])\r
2899                 url += ":" + up['port'];\r
2900 \r
2901         if (up['path'])\r
2902                 url += up['path'];\r
2903 \r
2904         if (up['query'])\r
2905                 url += "?" + up['query'];\r
2906 \r
2907         if (up['anchor'])\r
2908                 url += "#" + up['anchor'];\r
2909 \r
2910         return url;\r
2911 };\r
2912 \r
2913 /**\r
2914  * Converts an absolute path to relative path.\r
2915  */\r
2916 TinyMCE.prototype.convertAbsoluteURLToRelativeURL = function(base_url, url_to_relative) {\r
2917         var baseURL = this.parseURL(base_url);\r
2918         var targetURL = this.parseURL(url_to_relative);\r
2919         var strTok1;\r
2920         var strTok2;\r
2921         var breakPoint = 0;\r
2922         var outPath = "";\r
2923         var forceSlash = false;\r
2924 \r
2925         if (targetURL.path == "")\r
2926                 targetURL.path = "/";\r
2927         else\r
2928                 forceSlash = true;\r
2929 \r
2930         // Crop away last path part\r
2931         base_url = baseURL.path.substring(0, baseURL.path.lastIndexOf('/'));\r
2932         strTok1 = base_url.split('/');\r
2933         strTok2 = targetURL.path.split('/');\r
2934 \r
2935         if (strTok1.length >= strTok2.length) {\r
2936                 for (var i=0; i<strTok1.length; i++) {\r
2937                         if (i >= strTok2.length || strTok1[i] != strTok2[i]) {\r
2938                                 breakPoint = i + 1;\r
2939                                 break;\r
2940                         }\r
2941                 }\r
2942         }\r
2943 \r
2944         if (strTok1.length < strTok2.length) {\r
2945                 for (var i=0; i<strTok2.length; i++) {\r
2946                         if (i >= strTok1.length || strTok1[i] != strTok2[i]) {\r
2947                                 breakPoint = i + 1;\r
2948                                 break;\r
2949                         }\r
2950                 }\r
2951         }\r
2952 \r
2953         if (breakPoint == 1)\r
2954                 return targetURL.path;\r
2955 \r
2956         for (var i=0; i<(strTok1.length-(breakPoint-1)); i++)\r
2957                 outPath += "../";\r
2958 \r
2959         for (var i=breakPoint-1; i<strTok2.length; i++) {\r
2960                 if (i != (breakPoint-1))\r
2961                         outPath += "/" + strTok2[i];\r
2962                 else\r
2963                         outPath += strTok2[i];\r
2964         }\r
2965 \r
2966         targetURL.protocol = null;\r
2967         targetURL.host = null;\r
2968         targetURL.port = null;\r
2969         targetURL.path = outPath == "" && forceSlash ? "/" : outPath;\r
2970 \r
2971         // Remove document prefix from local anchors\r
2972         var fileName = baseURL.path;\r
2973         var pos;\r
2974 \r
2975         if ((pos = fileName.lastIndexOf('/')) != -1)\r
2976                 fileName = fileName.substring(pos + 1);\r
2977 \r
2978         // Is local anchor\r
2979         if (fileName == targetURL.path && targetURL.anchor != "")\r
2980                 targetURL.path = "";\r
2981 \r
2982         return this.serializeURL(targetURL);\r
2983 };\r
2984 \r
2985 TinyMCE.prototype.convertRelativeToAbsoluteURL = function(base_url, relative_url) {\r
2986         var baseURL = TinyMCE.prototype.parseURL(base_url);\r
2987         var relURL = TinyMCE.prototype.parseURL(relative_url);\r
2988 \r
2989         if (relative_url == "" || relative_url.charAt(0) == '/' || relative_url.indexOf('://') != -1 || relative_url.indexOf('mailto:') != -1 || relative_url.indexOf('javascript:') != -1)\r
2990                 return relative_url;\r
2991 \r
2992         // Split parts\r
2993         baseURLParts = baseURL['path'].split('/');\r
2994         relURLParts = relURL['path'].split('/');\r
2995 \r
2996         // Remove empty chunks\r
2997         var newBaseURLParts = new Array();\r
2998         for (var i=baseURLParts.length-1; i>=0; i--) {\r
2999                 if (baseURLParts[i].length == 0)\r
3000                         continue;\r
3001 \r
3002                 newBaseURLParts[newBaseURLParts.length] = baseURLParts[i];\r
3003         }\r
3004         baseURLParts = newBaseURLParts.reverse();\r
3005 \r
3006         // Merge relURLParts chunks\r
3007         var newRelURLParts = new Array();\r
3008         var numBack = 0;\r
3009         for (var i=relURLParts.length-1; i>=0; i--) {\r
3010                 if (relURLParts[i].length == 0 || relURLParts[i] == ".")\r
3011                         continue;\r
3012 \r
3013                 if (relURLParts[i] == '..') {\r
3014                         numBack++;\r
3015                         continue;\r
3016                 }\r
3017 \r
3018                 if (numBack > 0) {\r
3019                         numBack--;\r
3020                         continue;\r
3021                 }\r
3022 \r
3023                 newRelURLParts[newRelURLParts.length] = relURLParts[i];\r
3024         }\r
3025 \r
3026         relURLParts = newRelURLParts.reverse();\r
3027 \r
3028         // Remove end from absolute path\r
3029         var len = baseURLParts.length-numBack;\r
3030         var absPath = (len <= 0 ? "" : "/") + baseURLParts.slice(0, len).join('/') + "/" + relURLParts.join('/');\r
3031         var start = "", end = "";\r
3032 \r
3033         // Build output URL\r
3034         relURL.protocol = baseURL.protocol;\r
3035         relURL.host = baseURL.host;\r
3036         relURL.port = baseURL.port;\r
3037 \r
3038         // Re-add trailing slash if it's removed\r
3039         if (relURL.path.charAt(relURL.path.length-1) == "/")\r
3040                 absPath += "/";\r
3041 \r
3042         relURL.path = absPath;\r
3043 \r
3044         return TinyMCE.prototype.serializeURL(relURL);\r
3045 };\r
3046 \r
3047 TinyMCE.prototype.getParam = function(name, default_value, strip_whitespace, split_chr) {\r
3048         var value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];\r
3049 \r
3050         // Fix bool values\r
3051         if (value == "true" || value == "false")\r
3052                 return (value == "true");\r
3053 \r
3054         if (strip_whitespace)\r
3055                 value = tinyMCE.regexpReplace(value, "[ \t\r\n]", "");\r
3056 \r
3057         if (typeof(split_chr) != "undefined" && split_chr != null) {\r
3058                 value = value.split(split_chr);\r
3059                 var outArray = new Array();\r
3060 \r
3061                 for (var i=0; i<value.length; i++) {\r
3062                         if (value[i] && value[i] != "")\r
3063                                 outArray[outArray.length] = value[i];\r
3064                 }\r
3065 \r
3066                 value = outArray;\r
3067         }\r
3068 \r
3069         return value;\r
3070 };\r
3071 \r
3072 TinyMCE.prototype.getLang = function(name, default_value, parse_entities) {\r
3073         var value = (typeof(tinyMCELang[name]) == "undefined") ? default_value : tinyMCELang[name];\r
3074 \r
3075         if (parse_entities)\r
3076                 value = tinyMCE.entityDecode(value);\r
3077 \r
3078         return value;\r
3079 };\r
3080 \r
3081 TinyMCE.prototype.entityDecode = function(s) {\r
3082         var e = document.createElement("div");\r
3083         e.innerHTML = s;\r
3084         return e.innerHTML;\r
3085 };\r
3086 \r
3087 TinyMCE.prototype.addToLang = function(prefix, ar) {\r
3088         for (var key in ar) {\r
3089                 if (typeof(ar[key]) == 'function')\r
3090                         continue;\r
3091 \r
3092                 tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = ar[key];\r
3093         }\r
3094 \r
3095 //      for (var key in ar)\r
3096 //              tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = "|" + ar[key] + "|";\r
3097 };\r
3098 \r
3099 TinyMCE.prototype.replaceVar = function(replace_haystack, replace_var, replace_str) {\r
3100         var re = new RegExp('{\\\$' + replace_var + '}', 'g');\r
3101         return replace_haystack.replace(re, replace_str);\r
3102 };\r
3103 \r
3104 TinyMCE.prototype.replaceVars = function(replace_haystack, replace_vars) {\r
3105         for (var key in replace_vars) {\r
3106                 var value = replace_vars[key];\r
3107                 if (typeof(value) == 'function')\r
3108                         continue;\r
3109 \r
3110                 replace_haystack = tinyMCE.replaceVar(replace_haystack, key, value);\r
3111         }\r
3112 \r
3113         return replace_haystack;\r
3114 };\r
3115 \r
3116 TinyMCE.prototype.triggerNodeChange = function(focus, setup_content) {\r
3117         if (tinyMCE.settings['handleNodeChangeCallback']) {\r
3118                 if (tinyMCE.selectedInstance) {\r
3119                         var inst = tinyMCE.selectedInstance;\r
3120                         var editorId = inst.editorId;\r
3121                         var elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement();\r
3122                         var undoIndex = -1;\r
3123                         var undoLevels = -1;\r
3124                         var anySelection = false;\r
3125                         var selectedText = inst.getSelectedText();\r
3126 \r
3127                         inst.switchSettings();\r
3128 \r
3129                         if (tinyMCE.settings["auto_resize"]) {\r
3130                                 var doc = inst.getDoc();\r
3131 \r
3132                                 inst.iframeElement.style.width = doc.body.offsetWidth + "px";\r
3133                                 inst.iframeElement.style.height = doc.body.offsetHeight + "px";\r
3134                         }\r
3135 \r
3136                         if (tinyMCE.selectedElement)\r
3137                                 anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (selectedText && selectedText.length > 0);\r
3138 \r
3139                         if (tinyMCE.settings['custom_undo_redo']) {\r
3140                                 undoIndex = inst.undoIndex;\r
3141                                 undoLevels = inst.undoLevels.length;\r
3142                         }\r
3143 \r
3144                         tinyMCE.executeCallback('handleNodeChangeCallback', '_handleNodeChange', 0, editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content);\r
3145                 }\r
3146         }\r
3147 \r
3148         if (this.selectedInstance && (typeof(focus) == "undefined" || focus))\r
3149                 this.selectedInstance.contentWindow.focus();\r
3150 };\r
3151 \r
3152 TinyMCE.prototype._customCleanup = function(inst, type, content) {\r
3153         // Call custom cleanup\r
3154         var customCleanup = tinyMCE.settings['cleanup_callback'];\r
3155         if (customCleanup != "" && eval("typeof(" + customCleanup + ")") != "undefined")\r
3156                 content = eval(customCleanup + "(type, content, inst);");\r
3157 \r
3158         // Trigger plugin cleanups\r
3159         var plugins = tinyMCE.getParam('plugins', '', true, ',');\r
3160         for (var i=0; i<plugins.length; i++) {\r
3161                 if (eval("typeof(TinyMCE_" + plugins[i] +  "_cleanup)") != "undefined")\r
3162                         content = eval("TinyMCE_" + plugins[i] +  "_cleanup(type, content, inst);");\r
3163         }\r
3164 \r
3165         return content;\r
3166 };\r
3167 \r
3168 TinyMCE.prototype.getContent = function(editor_id) {\r
3169         if (typeof(editor_id) != "undefined")\r
3170                 tinyMCE.selectedInstance = tinyMCE.getInstanceById(editor_id);\r
3171 \r
3172         if (tinyMCE.selectedInstance) {\r
3173                 var old = this.selectedInstance.getBody().innerHTML;\r
3174                 var html = tinyMCE._cleanupHTML(this.selectedInstance, this.selectedInstance.getDoc(), tinyMCE.settings, this.selectedInstance.getBody(), false, true);\r
3175                 tinyMCE.setInnerHTML(this.selectedInstance.getBody(), old);\r
3176                 return html;\r
3177         }\r
3178 \r
3179         return null;\r
3180 };\r
3181 \r
3182 TinyMCE.prototype.setContent = function(html_content) {\r
3183         if (tinyMCE.selectedInstance) {\r
3184                 tinyMCE.selectedInstance.execCommand('mceSetContent', false, html_content);\r
3185                 tinyMCE.selectedInstance.repaint();\r
3186         }\r
3187 };\r
3188 \r
3189 TinyMCE.prototype.importThemeLanguagePack = function(name) {\r
3190         if (typeof(name) == "undefined")\r
3191                 name = tinyMCE.settings['theme'];\r
3192 \r
3193         tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings['language'] + '.js');\r
3194 };\r
3195 \r
3196 TinyMCE.prototype.importPluginLanguagePack = function(name, valid_languages) {\r
3197         var lang = "en";\r
3198 \r
3199         valid_languages = valid_languages.split(',');\r
3200         for (var i=0; i<valid_languages.length; i++) {\r
3201                 if (tinyMCE.settings['language'] == valid_languages[i])\r
3202                         lang = tinyMCE.settings['language'];\r
3203         }\r
3204 \r
3205         tinyMCE.loadScript(tinyMCE.baseURL + '/plugins/' + name + '/langs/' + lang +  '.js');\r
3206 };\r
3207 \r
3208 /**\r
3209  * Adds themeurl, settings and lang to HTML code.\r
3210  */\r
3211 TinyMCE.prototype.applyTemplate = function(html, args) {\r
3212         html = tinyMCE.replaceVar(html, "themeurl", tinyMCE.themeURL);\r
3213 \r
3214         if (typeof(args) != "undefined")\r
3215                 html = tinyMCE.replaceVars(html, args);\r
3216 \r
3217         html = tinyMCE.replaceVars(html, tinyMCE.settings);\r
3218         html = tinyMCE.replaceVars(html, tinyMCELang);\r
3219 \r
3220         return html;\r
3221 };\r
3222 \r
3223 TinyMCE.prototype.openWindow = function(template, args) {\r
3224         var html, width, height, x, y, resizable, scrollbars, url;\r
3225 \r
3226         args['mce_template_file'] = template['file'];\r
3227         args['mce_width'] = template['width'];\r
3228         args['mce_height'] = template['height'];\r
3229         tinyMCE.windowArgs = args;\r
3230 \r
3231         html = template['html'];\r
3232         if (!(width = parseInt(template['width'])))\r
3233                 width = 320;\r
3234 \r
3235         if (!(height = parseInt(template['height'])))\r
3236                 height = 200;\r
3237 \r
3238         // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!\r
3239         if (tinyMCE.isMSIE)\r
3240                 height += 40;\r
3241         else\r
3242                 height += 20;\r
3243 \r
3244         x = parseInt(screen.width / 2.0) - (width / 2.0);\r
3245         y = parseInt(screen.height / 2.0) - (height / 2.0);\r
3246 \r
3247         resizable = (args && args['resizable']) ? args['resizable'] : "no";\r
3248         scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";\r
3249 \r
3250         if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)\r
3251                 url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];\r
3252         else\r
3253                 url = template['file'];\r
3254 \r
3255         // Replace all args as variables in URL\r
3256         for (var name in args) {\r
3257                 if (typeof(args[name]) == 'function')\r
3258                         continue;\r
3259 \r
3260                 url = tinyMCE.replaceVar(url, name, escape(args[name]));\r
3261         }\r
3262 \r
3263         if (html) {\r
3264                 html = tinyMCE.replaceVar(html, "css", this.settings['popups_css']);\r
3265                 html = tinyMCE.applyTemplate(html, args);\r
3266 \r
3267                 var win = window.open("", "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=yes,minimizable=" + resizable + ",modal=yes,width=" + width + ",height=" + height + ",resizable=" + resizable);\r
3268                 if (win == null) {\r
3269                         alert(tinyMCELang['lang_popup_blocked']);\r
3270                         return;\r
3271                 }\r
3272 \r
3273                 win.document.write(html);\r
3274                 win.document.close();\r
3275                 win.resizeTo(width, height);\r
3276                 win.focus();\r
3277         } else {\r
3278                 if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && resizable != 'yes' && tinyMCE.settings["dialog_type"] == "modal") {\r
3279             var features = "resizable:" + resizable \r
3280                 + ";scroll:"\r
3281                 + scrollbars + ";status:yes;center:yes;help:no;dialogWidth:"\r
3282                 + width + "px;dialogHeight:" + height + "px;";\r
3283 \r
3284                         window.showModalDialog(url, window, features);\r
3285                 } else {\r
3286                         var modal = (resizable == "yes") ? "no" : "yes";\r
3287 \r
3288                         if (tinyMCE.isGecko && tinyMCE.isMac)\r
3289                                 modal = "no";\r
3290 \r
3291                         if (template['close_previous'] != "no")\r
3292                                 try {tinyMCE.lastWindow.close();} catch (ex) {}\r
3293 \r
3294                         var win = window.open(url, "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable);\r
3295                         if (win == null) {\r
3296                                 alert(tinyMCELang['lang_popup_blocked']);\r
3297                                 return;\r
3298                         }\r
3299 \r
3300                         if (template['close_previous'] != "no")\r
3301                                 tinyMCE.lastWindow = win;\r
3302 \r
3303                         eval('try { win.resizeTo(width, height); } catch(e) { }');\r
3304 \r
3305                         // Make it bigger if statusbar is forced\r
3306                         if (tinyMCE.isGecko) {\r
3307                                 if (win.document.defaultView.statusbar.visible)\r
3308                                         win.resizeBy(0, tinyMCE.isMac ? 10 : 24);\r
3309                         }\r
3310 \r
3311                         win.focus();\r
3312                 }\r
3313         }\r
3314 };\r
3315 \r
3316 TinyMCE.prototype.closeWindow = function(win) {\r
3317         win.close();\r
3318 };\r
3319 \r
3320 TinyMCE.prototype.getVisualAidClass = function(class_name, state) {\r
3321         var aidClass = tinyMCE.settings['visual_table_class'];\r
3322 \r
3323         if (typeof(state) == "undefined")\r
3324                 state = tinyMCE.settings['visual'];\r
3325 \r
3326         // Split\r
3327         var classNames = new Array();\r
3328         var ar = class_name.split(' ');\r
3329         for (var i=0; i<ar.length; i++) {\r
3330                 if (ar[i] == aidClass)\r
3331                         ar[i] = "";\r
3332 \r
3333                 if (ar[i] != "")\r
3334                         classNames[classNames.length] = ar[i];\r
3335         }\r
3336 \r
3337         if (state)\r
3338                 classNames[classNames.length] = aidClass;\r
3339 \r
3340         // Glue\r
3341         var className = "";\r
3342         for (var i=0; i<classNames.length; i++) {\r
3343                 if (i > 0)\r
3344                         className += " ";\r
3345 \r
3346                 className += classNames[i];\r
3347         }\r
3348 \r
3349         return className;\r
3350 };\r
3351 \r
3352 TinyMCE.prototype.handleVisualAid = function(el, deep, state, inst) {\r
3353         if (!el)\r
3354                 return;\r
3355 \r
3356         var tableElement = null;\r
3357 \r
3358         switch (el.nodeName) {\r
3359                 case "TABLE":\r
3360                         var oldW = el.style.width;\r
3361                         var oldH = el.style.height;\r
3362                         var bo = tinyMCE.getAttrib(el, "border");\r
3363 \r
3364                         bo = bo == "" || bo == "0" ? true : false;\r
3365 \r
3366                         tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo));\r
3367 \r
3368                         el.style.width = oldW;\r
3369                         el.style.height = oldH;\r
3370 \r
3371                         for (var y=0; y<el.rows.length; y++) {\r
3372                                 for (var x=0; x<el.rows[y].cells.length; x++) {\r
3373                                         var cn = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x], "class"), state && bo);\r
3374                                         tinyMCE.setAttrib(el.rows[y].cells[x], "class", cn);\r
3375                                 }\r
3376                         }\r
3377 \r
3378                         break;\r
3379 \r
3380                 case "A":\r
3381                         var anchorName = tinyMCE.getAttrib(el, "name");\r
3382 \r
3383                         if (anchorName != '' && state) {\r
3384                                 el.title = anchorName;\r
3385                                 el.className = 'mceItemAnchor';\r
3386                         } else if (anchorName != '' && !state)\r
3387                                 el.className = '';\r
3388 \r
3389                         break;\r
3390         }\r
3391 \r
3392         if (deep && el.hasChildNodes()) {\r
3393                 for (var i=0; i<el.childNodes.length; i++)\r
3394                         tinyMCE.handleVisualAid(el.childNodes[i], deep, state, inst);\r
3395         }\r
3396 };\r
3397 \r
3398 TinyMCE.prototype.getAttrib = function(elm, name, default_value) {\r
3399         if (typeof(default_value) == "undefined")\r
3400                 default_value = "";\r
3401 \r
3402         // Not a element\r
3403         if (!elm || elm.nodeType != 1)\r
3404                 return default_value;\r
3405 \r
3406         var v = elm.getAttribute(name);\r
3407 \r
3408         // Try className for class attrib\r
3409         if (name == "class" && !v)\r
3410                 v = elm.className;\r
3411 \r
3412         // Workaround for a issue with Firefox 1.5rc2+\r
3413         if (tinyMCE.isGecko && name == "src" && elm.src != null && elm.src != "")\r
3414                 v = elm.src;\r
3415 \r
3416         // Workaround for a issue with Firefox 1.5rc2+\r
3417         if (tinyMCE.isGecko && name == "href" && elm.href != null && elm.href != "")\r
3418                 v = elm.href;\r
3419 \r
3420         if (name == "style" && !tinyMCE.isOpera)\r
3421                 v = elm.style.cssText;\r
3422 \r
3423         return (v && v != "") ? v : default_value;\r
3424 };\r
3425 \r
3426 TinyMCE.prototype.setAttrib = function(element, name, value, fix_value) {\r
3427         if (typeof(value) == "number" && value != null)\r
3428                 value = "" + value;\r
3429 \r
3430         if (fix_value) {\r
3431                 if (value == null)\r
3432                         value = "";\r
3433 \r
3434                 var re = new RegExp('[^0-9%]', 'g');\r
3435                 value = value.replace(re, '');\r
3436         }\r
3437 \r
3438         if (name == "style")\r
3439                 element.style.cssText = value;\r
3440 \r
3441         if (name == "class")\r
3442                 element.className = value;\r
3443 \r
3444         if (value != null && value != "" && value != -1)\r
3445                 element.setAttribute(name, value);\r
3446         else\r
3447                 element.removeAttribute(name);\r
3448 };\r
3449 \r
3450 TinyMCE.prototype.setStyleAttrib = function(elm, name, value) {\r
3451         eval('elm.style.' + name + '=value;');\r
3452 \r
3453         // Style attrib deleted\r
3454         if (tinyMCE.isMSIE && value == null || value == '') {\r
3455                 var str = tinyMCE.serializeStyle(tinyMCE.parseStyle(elm.style.cssText));\r
3456                 elm.style.cssText = str;\r
3457                 elm.setAttribute("style", str);\r
3458         }\r
3459 };\r
3460 \r
3461 TinyMCE.prototype.convertSpansToFonts = function(doc) {\r
3462         var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');\r
3463 \r
3464         var h = doc.body.innerHTML;\r
3465         h = h.replace(/<span/gi, '<font');\r
3466         h = h.replace(/<\/span/gi, '</font');\r
3467         doc.body.innerHTML = h;\r
3468 \r
3469         var s = doc.getElementsByTagName("font");\r
3470         for (var i=0; i<s.length; i++) {\r
3471                 var size = tinyMCE.trim(s[i].style.fontSize).toLowerCase();\r
3472                 var fSize = 0;\r
3473 \r
3474                 for (var x=0; x<sizes.length; x++) {\r
3475                         if (sizes[x] == size) {\r
3476                                 fSize = x + 1;\r
3477                                 break;\r
3478                         }\r
3479                 }\r
3480 \r
3481                 if (fSize > 0) {\r
3482                         tinyMCE.setAttrib(s[i], 'size', fSize);\r
3483                         s[i].style.fontSize = '';\r
3484                 }\r
3485 \r
3486                 var fFace = s[i].style.fontFamily;\r
3487                 if (fFace != null && fFace != "") {\r
3488                         tinyMCE.setAttrib(s[i], 'face', fFace);\r
3489                         s[i].style.fontFamily = '';\r
3490                 }\r
3491 \r
3492                 var fColor = s[i].style.color;\r
3493                 if (fColor != null && fColor != "") {\r
3494                         tinyMCE.setAttrib(s[i], 'color', tinyMCE.convertRGBToHex(fColor));\r
3495                         s[i].style.color = '';\r
3496                 }\r
3497         }\r
3498 };\r
3499 \r
3500 TinyMCE.prototype.convertFontsToSpans = function(doc) {\r
3501         var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');\r
3502 \r
3503         var h = doc.body.innerHTML;\r
3504         h = h.replace(/<font/gi, '<span');\r
3505         h = h.replace(/<\/font/gi, '</span');\r
3506         doc.body.innerHTML = h;\r
3507 \r
3508         var fsClasses = tinyMCE.getParam('font_size_classes');\r
3509         if (fsClasses != '')\r
3510                 fsClasses = fsClasses.replace(/\s+/, '').split(',');\r
3511         else\r
3512                 fsClasses = null;\r
3513 \r
3514         var s = doc.getElementsByTagName("span");\r
3515         for (var i=0; i<s.length; i++) {\r
3516                 var fSize, fFace, fColor;\r
3517 \r
3518                 fSize = tinyMCE.getAttrib(s[i], 'size');\r
3519                 fFace = tinyMCE.getAttrib(s[i], 'face');\r
3520                 fColor = tinyMCE.getAttrib(s[i], 'color');\r
3521 \r
3522                 if (fSize != "") {\r
3523                         fSize = parseInt(fSize);\r
3524 \r
3525                         if (fSize > 0 && fSize < 8) {\r
3526                                 if (fsClasses != null)\r
3527                                         tinyMCE.setAttrib(s[i], 'class', fsClasses[fSize-1]);\r
3528                                 else\r
3529                                         s[i].style.fontSize = sizes[fSize-1];\r
3530                         }\r
3531 \r
3532                         s[i].removeAttribute('size');\r
3533                 }\r
3534 \r
3535                 if (fFace != "") {\r
3536                         s[i].style.fontFamily = fFace;\r
3537                         s[i].removeAttribute('face');\r
3538                 }\r
3539 \r
3540                 if (fColor != "") {\r
3541                         s[i].style.color = fColor;\r
3542                         s[i].removeAttribute('color');\r
3543                 }\r
3544         }\r
3545 };\r
3546 \r
3547 /*\r
3548 TinyMCE.prototype.applyClassesToFonts = function(doc, size) {\r
3549         var f = doc.getElementsByTagName("font");\r
3550         for (var i=0; i<f.length; i++) {\r
3551                 var s = tinyMCE.getAttrib(f[i], "size");\r
3552 \r
3553                 if (s != "")\r
3554                         tinyMCE.setAttrib(f[i], 'class', "mceItemFont" + s);\r
3555         }\r
3556 \r
3557         if (typeof(size) != "undefined") {\r
3558                 var css = "";\r
3559 \r
3560                 for (var x=0; x<doc.styleSheets.length; x++) {\r
3561                         for (var i=0; i<doc.styleSheets[x].rules.length; i++) {\r
3562                                 if (doc.styleSheets[x].rules[i].selectorText == '#mceSpanFonts .mceItemFont' + size) {\r
3563                                         css = doc.styleSheets[x].rules[i].style.cssText;\r
3564                                         break;\r
3565                                 }\r
3566                         }\r
3567 \r
3568                         if (css != "")\r
3569                                 break;\r
3570                 }\r
3571 \r
3572                 if (doc.styleSheets[0].rules[0].selectorText == "FONT")\r
3573                         doc.styleSheets[0].removeRule(0);\r
3574 \r
3575                 doc.styleSheets[0].addRule("FONT", css, 0);\r
3576         }\r
3577 };\r
3578 */\r
3579 \r
3580 TinyMCE.prototype.setInnerHTML = function(e, h) {\r
3581         if (tinyMCE.isMSIE && !tinyMCE.isOpera) {\r
3582                 e.innerHTML = tinyMCE.uniqueTag + h;\r
3583                 e.firstChild.removeNode(true);\r
3584         } else {\r
3585                 h = this.fixGeckoBaseHREFBug(1, e, h);\r
3586                 e.innerHTML = h;\r
3587                 this.fixGeckoBaseHREFBug(2, e, h);\r
3588         }\r
3589 };\r
3590 \r
3591 TinyMCE.prototype.fixGeckoBaseHREFBug = function(m, e, h) {\r
3592         if (tinyMCE.isGecko) {\r
3593                 if (m == 1) {\r
3594                         h = h.replace(/\ssrc=/gi, " xsrc=");\r
3595                         h = h.replace(/\shref=/gi, " xhref=");\r
3596 \r
3597                         return h;\r
3598                 } else {\r
3599                         if (h.indexOf(' xsrc') != -1) {\r
3600                                 var n = e.getElementsByTagName("img");\r
3601                                 for (var i=0; i<n.length; i++) {\r
3602                                         var xsrc = tinyMCE.getAttrib(n[i], "xsrc");\r
3603 \r
3604                                         if (xsrc != "") {\r
3605                                                 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);\r
3606                                                 n[i].removeAttribute("xsrc");\r
3607                                         }\r
3608                                 }\r
3609 \r
3610                                 // Select image form fields\r
3611                                 var n = e.getElementsByTagName("select");\r
3612                                 for (var i=0; i<n.length; i++) {\r
3613                                         var xsrc = tinyMCE.getAttrib(n[i], "xsrc");\r
3614 \r
3615                                         if (xsrc != "") {\r
3616                                                 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);\r
3617                                                 n[i].removeAttribute("xsrc");\r
3618                                         }\r
3619                                 }\r
3620 \r
3621                                 // iframes\r
3622                                 var n = e.getElementsByTagName("iframe");\r
3623                                 for (var i=0; i<n.length; i++) {\r
3624                                         var xsrc = tinyMCE.getAttrib(n[i], "xsrc");\r
3625 \r
3626                                         if (xsrc != "") {\r
3627                                                 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);\r
3628                                                 n[i].removeAttribute("xsrc");\r
3629                                         }\r
3630                                 }\r
3631                         }\r
3632 \r
3633                         if (h.indexOf(' xhref') != -1) {\r
3634                                 var n = e.getElementsByTagName("a");\r
3635                                 for (var i=0; i<n.length; i++) {\r
3636                                         var xhref = tinyMCE.getAttrib(n[i], "xhref");\r
3637 \r
3638                                         if (xhref != "") {\r
3639                                                 n[i].href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xhref);\r
3640                                                 n[i].removeAttribute("xhref");\r
3641                                         }\r
3642                                 }\r
3643                         }\r
3644                 }\r
3645         }\r
3646 \r
3647         return h;\r
3648 };\r
3649 \r
3650 TinyMCE.prototype.getOuterHTML = function(e) {\r
3651         if (tinyMCE.isMSIE)\r
3652                 return e.outerHTML;\r
3653 \r
3654         var d = e.ownerDocument.createElement("body");\r
3655         d.appendChild(e);\r
3656         return d.innerHTML;\r
3657 };\r
3658 \r
3659 TinyMCE.prototype.setOuterHTML = function(doc, e, h) {\r
3660         if (tinyMCE.isMSIE) {\r
3661                 e.outerHTML = h;\r
3662                 return;\r
3663         }\r
3664 \r
3665         var d = e.ownerDocument.createElement("body");\r
3666         d.innerHTML = h;\r
3667         e.parentNode.replaceChild(d.firstChild, e);\r
3668 };\r
3669 \r
3670 TinyMCE.prototype.insertAfter = function(nc, rc){\r
3671         if (rc.nextSibling)\r
3672                 rc.parentNode.insertBefore(nc, rc.nextSibling);\r
3673         else\r
3674                 rc.parentNode.appendChild(nc);\r
3675 };\r
3676 \r
3677 TinyMCE.prototype.cleanupAnchors = function(doc) {\r
3678         var an = doc.getElementsByTagName("a");\r
3679 \r
3680         for (var i=0; i<an.length; i++) {\r
3681                 if (tinyMCE.getAttrib(an[i], "name") != "") {\r
3682                         var cn = an[i].childNodes;\r
3683                         for (var x=cn.length-1; x>=0; x--)\r
3684                                 tinyMCE.insertAfter(cn[x], an[i]);\r
3685                 }\r
3686         }\r
3687 };\r
3688 \r
3689 TinyMCE.prototype._setHTML = function(doc, html_content) {\r
3690         // Force closed anchors open\r
3691         //html_content = html_content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');\r
3692 \r
3693         html_content = tinyMCE.cleanupHTMLCode(html_content);\r
3694 \r
3695         // Try innerHTML if it fails use pasteHTML in MSIE\r
3696         try {\r
3697                 tinyMCE.setInnerHTML(doc.body, html_content);\r
3698         } catch (e) {\r
3699                 if (this.isMSIE)\r
3700                         doc.body.createTextRange().pasteHTML(html_content);\r
3701         }\r
3702 \r
3703         // Content duplication bug fix\r
3704         if (tinyMCE.isMSIE && tinyMCE.settings['fix_content_duplication']) {\r
3705                 // Remove P elements in P elements\r
3706                 var paras = doc.getElementsByTagName("P");\r
3707                 for (var i=0; i<paras.length; i++) {\r
3708                         var node = paras[i];\r
3709                         while ((node = node.parentNode) != null) {\r
3710                                 if (node.nodeName == "P")\r
3711                                         node.outerHTML = node.innerHTML;\r
3712                         }\r
3713                 }\r
3714 \r
3715                 // Content duplication bug fix (Seems to be word crap)\r
3716                 var html = doc.body.innerHTML;\r
3717 \r
3718                 if (html.indexOf('="mso') != -1) {\r
3719                         for (var i=0; i<doc.body.all.length; i++) {\r
3720                                 var el = doc.body.all[i];\r
3721                                 el.removeAttribute("className","",0);\r
3722                                 el.removeAttribute("style","",0);\r
3723                         }\r
3724 \r
3725                         html = doc.body.innerHTML;\r
3726                         html = tinyMCE.regexpReplace(html, "<o:p><\/o:p>", "<br />");\r
3727                         html = tinyMCE.regexpReplace(html, "<o:p>&nbsp;<\/o:p>", "");\r
3728                         html = tinyMCE.regexpReplace(html, "<st1:.*?>", "");\r
3729                         html = tinyMCE.regexpReplace(html, "<p><\/p>", "");\r
3730                         html = tinyMCE.regexpReplace(html, "<p><\/p>\r\n<p><\/p>", "");\r
3731                         html = tinyMCE.regexpReplace(html, "<p>&nbsp;<\/p>", "<br />");\r
3732                         html = tinyMCE.regexpReplace(html, "<p>\s*(<p>\s*)?", "<p>");\r
3733                         html = tinyMCE.regexpReplace(html, "<\/p>\s*(<\/p>\s*)?", "</p>");\r
3734                 }\r
3735 \r
3736                 // Always set the htmlText output\r
3737                 tinyMCE.setInnerHTML(doc.body, html);\r
3738         }\r
3739 \r
3740         tinyMCE.cleanupAnchors(doc);\r
3741 \r
3742         if (tinyMCE.getParam("convert_fonts_to_spans"))\r
3743                 tinyMCE.convertSpansToFonts(doc);\r
3744 };\r
3745 \r
3746 TinyMCE.prototype.getImageSrc = function(str) {\r
3747         var pos = -1;\r
3748 \r
3749         if (!str)\r
3750                 return "";\r
3751 \r
3752         if ((pos = str.indexOf('this.src=')) != -1) {\r
3753                 var src = str.substring(pos + 10);\r
3754 \r
3755                 src = src.substring(0, src.indexOf('\''));\r
3756 \r
3757                 return src;\r
3758         }\r
3759 \r
3760         return "";\r
3761 };\r
3762 \r
3763 TinyMCE.prototype._getElementById = function(element_id) {\r
3764         var elm = document.getElementById(element_id);\r
3765         if (!elm) {\r
3766                 // Check for element in forms\r
3767                 for (var j=0; j<document.forms.length; j++) {\r
3768                         for (var k=0; k<document.forms[j].elements.length; k++) {\r
3769                                 if (document.forms[j].elements[k].name == element_id) {\r
3770                                         elm = document.forms[j].elements[k];\r
3771                                         break;\r
3772                                 }\r
3773                         }\r
3774                 }\r
3775         }\r
3776 \r
3777         return elm;\r
3778 };\r
3779 \r
3780 TinyMCE.prototype.getEditorId = function(form_element) {\r
3781         var inst = this.getInstanceById(form_element);\r
3782         if (!inst)\r
3783                 return null;\r
3784 \r
3785         return inst.editorId;\r
3786 };\r
3787 \r
3788 TinyMCE.prototype.getInstanceById = function(editor_id) {\r
3789         var inst = this.instances[editor_id];\r
3790         if (!inst) {\r
3791                 for (var n in tinyMCE.instances) {\r
3792                         var instance = tinyMCE.instances[n];\r
3793                         if (!tinyMCE.isInstance(instance))\r
3794                                 continue;\r
3795 \r
3796                         if (instance.formTargetElementId == editor_id) {\r
3797                                 inst = instance;\r
3798                                 break;\r
3799                         }\r
3800                 }\r
3801         }\r
3802 \r
3803         return inst;\r
3804 };\r
3805 \r
3806 TinyMCE.prototype.queryInstanceCommandValue = function(editor_id, command) {\r
3807         var inst = tinyMCE.getInstanceById(editor_id);\r
3808         if (inst)\r
3809                 return inst.queryCommandValue(command);\r
3810 \r
3811         return false;\r
3812 };\r
3813 \r
3814 TinyMCE.prototype.queryInstanceCommandState = function(editor_id, command) {\r
3815         var inst = tinyMCE.getInstanceById(editor_id);\r
3816         if (inst)\r
3817                 return inst.queryCommandState(command);\r
3818 \r
3819         return null;\r
3820 };\r
3821 \r
3822 TinyMCE.prototype.setWindowArg = function(name, value) {\r
3823         this.windowArgs[name] = value;\r
3824 };\r
3825 \r
3826 TinyMCE.prototype.getWindowArg = function(name, default_value) {\r
3827         return (typeof(this.windowArgs[name]) == "undefined") ? default_value : this.windowArgs[name];\r
3828 };\r
3829 \r
3830 TinyMCE.prototype.getCSSClasses = function(editor_id, doc) {\r
3831         var output = new Array();\r
3832 \r
3833         // Is cached, use that\r
3834         if (typeof(tinyMCE.cssClasses) != "undefined")\r
3835                 return tinyMCE.cssClasses;\r
3836 \r
3837         if (typeof(editor_id) == "undefined" && typeof(doc) == "undefined") {\r
3838                 var instance;\r
3839 \r
3840                 for (var instanceName in tinyMCE.instances) {\r
3841                         instance = tinyMCE.instances[instanceName];\r
3842                         if (!tinyMCE.isInstance(instance))\r
3843                                 continue;\r
3844 \r
3845                         break;\r
3846                 }\r
3847 \r
3848                 doc = instance.getDoc();\r
3849         }\r
3850 \r
3851         if (typeof(doc) == "undefined") {\r
3852                 var instance = tinyMCE.getInstanceById(editor_id);\r
3853                 doc = instance.getDoc();\r
3854         }\r
3855 \r
3856         if (doc) {\r
3857                 var styles = tinyMCE.isMSIE ? doc.styleSheets : doc.styleSheets;\r
3858 \r
3859                 if (styles && styles.length > 0) {\r
3860                         for (var x=0; x<styles.length; x++) {\r
3861                                 var csses = null;\r
3862 \r
3863                                 // Just ignore any errors\r
3864                                 eval("try {var csses = tinyMCE.isMSIE ? doc.styleSheets(" + x + ").rules : doc.styleSheets[" + x + "].cssRules;} catch(e) {}");\r
3865                                 if (!csses)\r
3866                                         return new Array();\r
3867 \r
3868                                 for (var i=0; i<csses.length; i++) {\r
3869                                         var selectorText = csses[i].selectorText;\r
3870 \r
3871                                         // Can be multiple rules per selector\r
3872                                         if (selectorText) {\r
3873                                                 var rules = selectorText.split(',');\r
3874                                                 for (var c=0; c<rules.length; c++) {\r
3875                                                         // Invalid rule\r
3876                                                         if (rules[c].indexOf(' ') != -1 || rules[c].indexOf(':') != -1 || rules[c].indexOf('mceItem') != -1)\r
3877                                                                 continue;\r
3878 \r
3879                                                         if (rules[c] == "." + tinyMCE.settings['visual_table_class'])\r
3880                                                                 continue;\r
3881 \r
3882                                                         // Is class rule\r
3883                                                         if (rules[c].indexOf('.') != -1) {\r
3884                                                                 //alert(rules[c].substring(rules[c].indexOf('.')));\r
3885                                                                 output[output.length] = rules[c].substring(rules[c].indexOf('.')+1);\r
3886                                                         }\r
3887                                                 }\r
3888                                         }\r
3889                                 }\r
3890                         }\r
3891                 }\r
3892         }\r
3893 \r
3894         // Cache em\r
3895         if (output.length > 0)\r
3896                 tinyMCE.cssClasses = output;\r
3897 \r
3898         return output;\r
3899 };\r
3900 \r
3901 TinyMCE.prototype.regexpReplace = function(in_str, reg_exp, replace_str, opts) {\r
3902         if (in_str == null)\r
3903                 return in_str;\r
3904 \r
3905         if (typeof(opts) == "undefined")\r
3906                 opts = 'g';\r
3907 \r
3908         var re = new RegExp(reg_exp, opts);\r
3909         return in_str.replace(re, replace_str);\r
3910 };\r
3911 \r
3912 TinyMCE.prototype.trim = function(str) {\r
3913         return str.replace(/^\s*|\s*$/g, "");\r
3914 };\r
3915 \r
3916 TinyMCE.prototype.cleanupEventStr = function(str) {\r
3917         str = "" + str;\r
3918         str = str.replace('function anonymous()\n{\n', '');\r
3919         str = str.replace('\n}', '');\r
3920         str = str.replace(/^return true;/gi, ''); // Remove event blocker\r
3921 \r
3922         return str;\r
3923 };\r
3924 \r
3925 TinyMCE.prototype.getAbsPosition = function(node) {\r
3926         var pos = new Object();\r
3927 \r
3928         pos.absLeft = pos.absTop = 0;\r
3929 \r
3930         var parentNode = node;\r
3931         while (parentNode) {\r
3932                 pos.absLeft += parentNode.offsetLeft;\r
3933                 pos.absTop += parentNode.offsetTop;\r
3934 \r
3935                 parentNode = parentNode.offsetParent;\r
3936         }\r
3937 \r
3938         return pos;\r
3939 };\r
3940 \r
3941 TinyMCE.prototype.getControlHTML = function(control_name) {\r
3942         var themePlugins = tinyMCE.getParam('plugins', '', true, ',');\r
3943         var templateFunction;\r
3944 \r
3945         // Is it defined in any plugins\r
3946         for (var i=themePlugins.length; i>=0; i--) {\r
3947                 templateFunction = 'TinyMCE_' + themePlugins[i] + "_getControlHTML";\r
3948                 if (eval("typeof(" + templateFunction + ")") != 'undefined') {\r
3949                         var html = eval(templateFunction + "('" + control_name + "');");\r
3950                         if (html != "")\r
3951                                 return tinyMCE.replaceVar(html, "pluginurl", tinyMCE.baseURL + "/plugins/" + themePlugins[i]);\r
3952                 }\r
3953         }\r
3954 \r
3955         return eval('TinyMCE_' + tinyMCE.settings['theme'] + "_getControlHTML" + "('" + control_name + "');");\r
3956 };\r
3957 \r
3958 TinyMCE.prototype._themeExecCommand = function(editor_id, element, command, user_interface, value) {\r
3959         var themePlugins = tinyMCE.getParam('plugins', '', true, ',');\r
3960         var templateFunction;\r
3961 \r
3962         // Is it defined in any plugins\r
3963         for (var i=themePlugins.length; i>=0; i--) {\r
3964                 templateFunction = 'TinyMCE_' + themePlugins[i] + "_execCommand";\r
3965                 if (eval("typeof(" + templateFunction + ")") != 'undefined') {\r
3966                         if (eval(templateFunction + "(editor_id, element, command, user_interface, value);"))\r
3967                                 return true;\r
3968                 }\r
3969         }\r
3970 \r
3971         // Theme funtion\r
3972         templateFunction = 'TinyMCE_' + tinyMCE.settings['theme'] + "_execCommand";\r
3973         if (eval("typeof(" + templateFunction + ")") != 'undefined')\r
3974                 return eval(templateFunction + "(editor_id, element, command, user_interface, value);");\r
3975 \r
3976         // Pass to normal\r
3977         return false;\r
3978 };\r
3979 \r
3980 TinyMCE.prototype._getThemeFunction = function(suffix, skip_plugins) {\r
3981         if (skip_plugins)\r
3982                 return 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;\r
3983 \r
3984         var themePlugins = tinyMCE.getParam('plugins', '', true, ',');\r
3985         var templateFunction;\r
3986 \r
3987         // Is it defined in any plugins\r
3988         for (var i=themePlugins.length; i>=0; i--) {\r
3989                 templateFunction = 'TinyMCE_' + themePlugins[i] + suffix;\r
3990                 if (eval("typeof(" + templateFunction + ")") != 'undefined')\r
3991                         return templateFunction;\r
3992         }\r
3993 \r
3994         return 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;\r
3995 };\r
3996 \r
3997 \r
3998 TinyMCE.prototype.isFunc = function(func_name) {\r
3999         if (func_name == null || func_name == "")\r
4000                 return false;\r
4001 \r
4002         return eval("typeof(" + func_name + ")") != "undefined";\r
4003 };\r
4004 \r
4005 TinyMCE.prototype.exec = function(func_name, args) {\r
4006         var str = func_name + '(';\r
4007 \r
4008         // Add all arguments\r
4009         for (var i=3; i<args.length; i++) {\r
4010                 str += 'args[' + i + ']';\r
4011 \r
4012                 if (i < args.length-1)\r
4013                         str += ',';\r
4014         }\r
4015 \r
4016         str += ');';\r
4017 \r
4018         return eval(str);\r
4019 };\r
4020 \r
4021 TinyMCE.prototype.executeCallback = function(param, suffix, mode) {\r
4022         switch (mode) {\r
4023                 // No chain\r
4024                 case 0:\r
4025                         var state = false;\r
4026 \r
4027                         // Execute each plugin callback\r
4028                         var plugins = tinyMCE.getParam('plugins', '', true, ',');\r
4029                         for (var i=0; i<plugins.length; i++) {\r
4030                                 var func = "TinyMCE_" + plugins[i] + suffix;\r
4031                                 if (tinyMCE.isFunc(func)) {\r
4032                                         tinyMCE.exec(func, this.executeCallback.arguments);\r
4033                                         state = true;\r
4034                                 }\r
4035                         }\r
4036 \r
4037                         // Execute theme callback\r
4038                         var func = 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;\r
4039                         if (tinyMCE.isFunc(func)) {\r
4040                                 tinyMCE.exec(func, this.executeCallback.arguments);\r
4041                                 state = true;\r
4042                         }\r
4043 \r
4044                         // Execute settings callback\r
4045                         var func = tinyMCE.getParam(param, '');\r
4046                         if (tinyMCE.isFunc(func)) {\r
4047                                 tinyMCE.exec(func, this.executeCallback.arguments);\r
4048                                 state = true;\r
4049                         }\r
4050 \r
4051                         return state;\r
4052 \r
4053                 // Chain mode\r
4054                 case 1:\r
4055                         // Execute each plugin callback\r
4056                         var plugins = tinyMCE.getParam('plugins', '', true, ',');\r
4057                         for (var i=0; i<plugins.length; i++) {\r
4058                                 var func = "TinyMCE_" + plugins[i] + suffix;\r
4059                                 if (tinyMCE.isFunc(func)) {\r
4060                                         if (tinyMCE.exec(func, this.executeCallback.arguments))\r
4061                                                 return true;\r
4062                                 }\r
4063                         }\r
4064 \r
4065                         // Execute theme callback\r
4066                         var func = 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;\r
4067                         if (tinyMCE.isFunc(func)) {\r
4068                                 if (tinyMCE.exec(func, this.executeCallback.arguments))\r
4069                                         return true;\r
4070                         }\r
4071 \r
4072                         // Execute settings callback\r
4073                         var func = tinyMCE.getParam(param, '');\r
4074                         if (tinyMCE.isFunc(func)) {\r
4075                                 if (tinyMCE.exec(func, this.executeCallback.arguments))\r
4076                                         return true;\r
4077                         }\r
4078 \r
4079                         return false;\r
4080         }\r
4081 };\r
4082 \r
4083 TinyMCE.prototype.debug = function() {\r
4084         var msg = "";\r
4085 \r
4086         var elm = document.getElementById("tinymce_debug");\r
4087         if (!elm) {\r
4088                 var debugDiv = document.createElement("div");\r
4089                 debugDiv.setAttribute("className", "debugger");\r
4090                 debugDiv.className = "debugger";\r
4091                 debugDiv.innerHTML = '\\r
4092                         Debug output:\\r
4093                         <textarea id="tinymce_debug" style="width: 100%; height: 300px" wrap="nowrap"></textarea>';\r
4094 \r
4095                 document.body.appendChild(debugDiv);\r
4096                 elm = document.getElementById("tinymce_debug");\r
4097         }\r
4098 \r
4099         var args = this.debug.arguments;\r
4100         for (var i=0; i<args.length; i++) {\r
4101                 msg += args[i];\r
4102                 if (i<args.length-1)\r
4103                         msg += ', ';\r
4104         }\r
4105 \r
4106         elm.value += msg + "\n";\r
4107 };\r
4108 \r
4109 // TinyMCEControl\r
4110 function TinyMCEControl(settings) {\r
4111         // Undo levels\r
4112         this.undoLevels = new Array();\r
4113         this.undoIndex = 0;\r
4114         this.typingUndoIndex = -1;\r
4115         this.undoRedo = true;\r
4116         this.isTinyMCEControl = true;\r
4117 \r
4118         // Default settings\r
4119         this.settings = settings;\r
4120         this.settings['theme'] = tinyMCE.getParam("theme", "default");\r
4121         this.settings['width'] = tinyMCE.getParam("width", -1);\r
4122         this.settings['height'] = tinyMCE.getParam("height", -1);\r
4123 };\r
4124 \r
4125 TinyMCEControl.prototype.repaint = function() {\r
4126         if (tinyMCE.isMSIE && !tinyMCE.isOpera)\r
4127                 return;\r
4128 \r
4129         // Ugly mozilla hack to remove ghost resize handles\r
4130         try {\r
4131                 this.getBody().style.display = 'none';\r
4132                 this.getDoc().execCommand('selectall', false, null);\r
4133                 this.getSel().collapseToStart();\r
4134                 this.getBody().style.display = 'block';\r
4135         } catch (ex) {\r
4136                 // Could I care less!!\r
4137         }\r
4138 };\r
4139 \r
4140 TinyMCEControl.prototype.switchSettings = function() {\r
4141         if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings['index']) {\r
4142                 tinyMCE.settings = this.settings;\r
4143                 tinyMCE.currentConfig = this.settings['index'];\r
4144         }\r
4145 };\r
4146 \r
4147 TinyMCEControl.prototype.convertAllRelativeURLs = function() {\r
4148         var body = this.getBody();\r
4149 \r
4150         // Convert all image URL:s to absolute URL\r
4151         var elms = body.getElementsByTagName("img");\r
4152         for (var i=0; i<elms.length; i++) {\r
4153                 var src = tinyMCE.getAttrib(elms[i], 'src');\r
4154 \r
4155                 var msrc = tinyMCE.getAttrib(elms[i], 'mce_src');\r
4156                 if (msrc != "")\r
4157                         src = msrc;\r
4158 \r
4159                 if (src != "") {\r
4160                         src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);\r
4161                         elms[i].setAttribute("src", src);\r
4162                 }\r
4163         }\r
4164 \r
4165         // Convert all link URL:s to absolute URL\r
4166         var elms = body.getElementsByTagName("a");\r
4167         for (var i=0; i<elms.length; i++) {\r
4168                 var href = tinyMCE.getAttrib(elms[i], 'href');\r
4169 \r
4170                 var mhref = tinyMCE.getAttrib(elms[i], 'mce_href');\r
4171                 if (mhref != "")\r
4172                         href = mhref;\r
4173 \r
4174                 if (href && href != "") {\r
4175                         href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], href);\r
4176                         elms[i].setAttribute("href", href);\r
4177                 }\r
4178         }\r
4179 };\r
4180 \r
4181 TinyMCEControl.prototype.getSelectedHTML = function() {\r
4182         if (tinyMCE.isSafari) {\r
4183                 // Not realy perfect!!\r
4184 \r
4185                 return this.getRng().toString();\r
4186         }\r
4187 \r
4188         var elm = document.createElement("body");\r
4189 \r
4190         if (tinyMCE.isGecko)\r
4191                 elm.appendChild(this.getRng().cloneContents());\r
4192         else\r
4193                 elm.innerHTML = this.getRng().htmlText;\r
4194 \r
4195         return tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, elm, this.visualAid);\r
4196 };\r
4197 \r
4198 TinyMCEControl.prototype.getBookmark = function() {\r
4199         var rng = this.getRng();\r
4200 \r
4201         if (tinyMCE.isSafari)\r
4202                 return rng;\r
4203 \r
4204         if (tinyMCE.isMSIE)\r
4205                 return rng;\r
4206 \r
4207         if (tinyMCE.isGecko)\r
4208                 return rng.cloneRange();\r
4209 \r
4210         return null;\r
4211 };\r
4212 \r
4213 TinyMCEControl.prototype.moveToBookmark = function(bookmark) {\r
4214         if (tinyMCE.isSafari) {\r
4215                 var sel = this.getSel().realSelection;\r
4216 \r
4217                 sel.setBaseAndExtent(bookmark.startContainer, bookmark.startOffset, bookmark.endContainer, bookmark.endOffset);\r
4218 \r
4219                 return true;\r
4220         }\r
4221 \r
4222         if (tinyMCE.isMSIE)\r
4223                 return bookmark.select();\r
4224 \r
4225         if (tinyMCE.isGecko) {\r
4226                 var rng = this.getDoc().createRange();\r
4227                 var sel = this.getSel();\r
4228 \r
4229                 rng.setStart(bookmark.startContainer, bookmark.startOffset);\r
4230                 rng.setEnd(bookmark.endContainer, bookmark.endOffset);\r
4231 \r
4232                 sel.removeAllRanges();\r
4233                 sel.addRange(rng);\r
4234 \r
4235                 return true;\r
4236         }\r
4237 \r
4238         return false;\r
4239 };\r
4240 \r
4241 TinyMCEControl.prototype.getSelectedText = function() {\r
4242         if (tinyMCE.isMSIE) {\r
4243                 var doc = this.getDoc();\r
4244 \r
4245                 if (doc.selection.type == "Text") {\r
4246                         var rng = doc.selection.createRange();\r
4247                         selectedText = rng.text;\r
4248                 } else\r
4249                         selectedText = '';\r
4250         } else {\r
4251                 var sel = this.getSel();\r
4252 \r
4253                 if (sel && sel.toString)\r
4254                         selectedText = sel.toString();\r
4255                 else\r
4256                         selectedText = '';\r
4257         }\r
4258 \r
4259         return selectedText;\r
4260 };\r
4261 \r
4262 TinyMCEControl.prototype.selectNode = function(node, collapse, select_text_node, to_start) {\r
4263         if (!node)\r
4264                 return;\r
4265 \r
4266         if (typeof(collapse) == "undefined")\r
4267                 collapse = true;\r
4268 \r
4269         if (typeof(select_text_node) == "undefined")\r
4270                 select_text_node = false;\r
4271 \r
4272         if (typeof(to_start) == "undefined")\r
4273                 to_start = true;\r
4274 \r
4275         if (tinyMCE.isMSIE) {\r
4276                 var rng = this.getBody().createTextRange();\r
4277 \r
4278                 try {\r
4279                         rng.moveToElementText(node);\r
4280 \r
4281                         if (collapse)\r
4282                                 rng.collapse(to_start);\r
4283 \r
4284                         rng.select();\r
4285                 } catch (e) {\r
4286                         // Throws illigal agrument in MSIE some times\r
4287                 }\r
4288         } else {\r
4289                 var sel = this.getSel();\r
4290 \r
4291                 if (!sel)\r
4292                         return;\r
4293 \r
4294                 if (tinyMCE.isSafari) {\r
4295                         sel.realSelection.setBaseAndExtent(node, 0, node, node.innerText.length);\r
4296 \r
4297                         if (collapse) {\r
4298                                 if (to_start)\r
4299                                         sel.realSelection.collapseToStart();\r
4300                                 else\r
4301                                         sel.realSelection.collapseToEnd();\r
4302                         }\r
4303 \r
4304                         this.scrollToNode(node);\r
4305 \r
4306                         return;\r
4307                 }\r
4308 \r
4309                 var rng = this.getDoc().createRange();\r
4310 \r
4311                 if (select_text_node) {\r
4312                         // Find first textnode in tree\r
4313                         var nodes = tinyMCE.getNodeTree(node, new Array(), 3);\r
4314                         if (nodes.length > 0)\r
4315                                 rng.selectNodeContents(nodes[0]);\r
4316                         else\r
4317                                 rng.selectNodeContents(node);\r
4318                 } else\r
4319                         rng.selectNode(node);\r
4320 \r
4321                 if (collapse) {\r
4322                         // Special treatment of textnode collapse\r
4323                         if (!to_start && node.nodeType == 3) {\r
4324                                 rng.setStart(node, node.nodeValue.length);\r
4325                                 rng.setEnd(node, node.nodeValue.length);\r
4326                         } else\r
4327                                 rng.collapse(to_start);\r
4328                 }\r
4329 \r
4330                 sel.removeAllRanges();\r
4331                 sel.addRange(rng);\r
4332         }\r
4333 \r
4334         this.scrollToNode(node);\r
4335 \r
4336         // Set selected element\r
4337         tinyMCE.selectedElement = null;\r
4338         if (node.nodeType == 1)\r
4339                 tinyMCE.selectedElement = node;\r
4340 };\r
4341 \r
4342 TinyMCEControl.prototype.scrollToNode = function(node) {\r
4343         // Scroll to node position\r
4344         var pos = tinyMCE.getAbsPosition(node);\r
4345         var doc = this.getDoc();\r
4346         var scrollX = doc.body.scrollLeft + doc.documentElement.scrollLeft;\r
4347         var scrollY = doc.body.scrollTop + doc.documentElement.scrollTop;\r
4348         var height = tinyMCE.isMSIE ? document.getElementById(this.editorId).style.pixelHeight : this.targetElement.clientHeight;\r
4349 \r
4350         // Only scroll if out of visible area\r
4351         if (!tinyMCE.settings['auto_resize'] && !(pos.absTop > scrollY && pos.absTop < (scrollY - 25 + height)))\r
4352                 this.contentWindow.scrollTo(pos.absLeft, pos.absTop - height + 25); \r
4353 };\r
4354 \r
4355 TinyMCEControl.prototype.getBody = function() {\r
4356         return this.getDoc().body;\r
4357 };\r
4358 \r
4359 TinyMCEControl.prototype.getDoc = function() {\r
4360         return this.contentWindow.document;\r
4361 };\r
4362 \r
4363 TinyMCEControl.prototype.getWin = function() {\r
4364         return this.contentWindow;\r
4365 };\r
4366 \r
4367 TinyMCEControl.prototype.getSel = function() {\r
4368         if (tinyMCE.isMSIE && !tinyMCE.isOpera)\r
4369                 return this.getDoc().selection;\r
4370 \r
4371         var sel = this.contentWindow.getSelection();\r
4372 \r
4373         // Fake getRangeAt\r
4374         if (tinyMCE.isSafari && !sel.getRangeAt) {\r
4375                 var newSel = new Object();\r
4376                 var doc = this.getDoc();\r
4377 \r
4378                 function getRangeAt(idx) {\r
4379                         var rng = new Object();\r
4380 \r
4381                         rng.startContainer = this.focusNode;\r
4382                         rng.endContainer = this.anchorNode;\r
4383                         rng.commonAncestorContainer = this.focusNode;\r
4384                         rng.createContextualFragment = function (html) {\r
4385                                 // Seems to be a tag\r
4386                                 if (html.charAt(0) == '<') {\r
4387                                         var elm = doc.createElement("div");\r
4388 \r
4389                                         elm.innerHTML = html;\r
4390 \r
4391                                         return elm.firstChild;\r
4392                                 }\r
4393 \r
4394                                 return doc.createTextNode("UNSUPPORTED, DUE TO LIMITATIONS IN SAFARI!");\r
4395                         };\r
4396 \r
4397                         rng.deleteContents = function () {\r
4398                                 doc.execCommand("Delete", false, "");\r
4399                         };\r
4400 \r
4401                         return rng;\r
4402                 }\r
4403 \r
4404                 // Patch selection\r
4405 \r
4406                 newSel.focusNode = sel.baseNode;\r
4407                 newSel.focusOffset = sel.baseOffset;\r
4408                 newSel.anchorNode = sel.extentNode;\r
4409                 newSel.anchorOffset = sel.extentOffset;\r
4410                 newSel.getRangeAt = getRangeAt;\r
4411                 newSel.text = "" + sel;\r
4412                 newSel.realSelection = sel;\r
4413 \r
4414                 newSel.toString = function () {return this.text;};\r
4415 \r
4416                 return newSel;\r
4417         }\r
4418 \r
4419         return sel;\r
4420 };\r
4421 \r
4422 TinyMCEControl.prototype.getRng = function() {\r
4423         var sel = this.getSel();\r
4424         if (sel == null)\r
4425                 return null;\r
4426 \r
4427         if (tinyMCE.isMSIE && !tinyMCE.isOpera)\r
4428                 return sel.createRange();\r
4429 \r
4430         if (tinyMCE.isSafari) {\r
4431                 var rng = this.getDoc().createRange();\r
4432                 var sel = this.getSel().realSelection;\r
4433 \r
4434                 rng.setStart(sel.baseNode, sel.baseOffset);\r
4435                 rng.setEnd(sel.extentNode, sel.extentOffset);\r
4436 \r
4437                 return rng;\r
4438         }\r
4439 \r
4440         return this.getSel().getRangeAt(0);\r
4441 };\r
4442 \r
4443 TinyMCEControl.prototype._insertPara = function(e) {\r
4444         function isEmpty(para) {\r
4445                 function isEmptyHTML(html) {\r
4446                         return html.replace(new RegExp('[ \t\r\n]+', 'g'), '').toLowerCase() == "";\r
4447                 }\r
4448 \r
4449                 // Check for images\r
4450                 if (para.getElementsByTagName("img").length > 0)\r
4451                         return false;\r
4452 \r
4453                 // Check for tables\r
4454                 if (para.getElementsByTagName("table").length > 0)\r
4455                         return false;\r
4456 \r
4457                 // Check for HRs\r
4458                 if (para.getElementsByTagName("hr").length > 0)\r
4459                         return false;\r
4460 \r
4461                 // Check all textnodes\r
4462                 var nodes = tinyMCE.getNodeTree(para, new Array(), 3);\r
4463                 for (var i=0; i<nodes.length; i++) {\r
4464                         if (!isEmptyHTML(nodes[i].nodeValue))\r
4465                                 return false;\r
4466                 }\r
4467 \r
4468                 // No images, no tables, no hrs, no text content then it's empty\r
4469                 return true;\r
4470         }\r
4471 \r
4472         var doc = this.getDoc();\r
4473         var sel = this.getSel();\r
4474         var win = this.contentWindow;\r
4475         var rng = sel.getRangeAt(0);\r
4476         var body = doc.body;\r
4477         var rootElm = doc.documentElement;\r
4478         var self = this;\r
4479         var blockName = "P";\r
4480 \r
4481 //      tinyMCE.debug(body.innerHTML);\r
4482 \r
4483 //      debug(e.target, sel.anchorNode.nodeName, sel.focusNode.nodeName, rng.startContainer, rng.endContainer, rng.commonAncestorContainer, sel.anchorOffset, sel.focusOffset, rng.toString());\r
4484 \r
4485         // Setup before range\r
4486         var rngBefore = doc.createRange();\r
4487         rngBefore.setStart(sel.anchorNode, sel.anchorOffset);\r
4488         rngBefore.collapse(true);\r
4489 \r
4490         // Setup after range\r
4491         var rngAfter = doc.createRange();\r
4492         rngAfter.setStart(sel.focusNode, sel.focusOffset);\r
4493         rngAfter.collapse(true);\r
4494 \r
4495         // Setup start/end points\r
4496         var direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;\r
4497         var startNode = direct ? sel.anchorNode : sel.focusNode;\r
4498         var startOffset = direct ? sel.anchorOffset : sel.focusOffset;\r
4499         var endNode = direct ? sel.focusNode : sel.anchorNode;\r
4500         var endOffset = direct ? sel.focusOffset : sel.anchorOffset;\r
4501 \r
4502         startNode = startNode.nodeName == "BODY" ? startNode.firstChild : startNode;\r
4503         endNode = endNode.nodeName == "BODY" ? endNode.firstChild : endNode;\r
4504 \r
4505         // tinyMCE.debug(startNode, endNode);\r
4506 \r
4507         // Get block elements\r
4508         var startBlock = tinyMCE.getParentBlockElement(startNode);\r
4509         var endBlock = tinyMCE.getParentBlockElement(endNode);\r
4510 \r
4511         // Use current block name\r
4512         if (startBlock != null) {\r
4513                 blockName = startBlock.nodeName;\r
4514 \r
4515                 // Use P instead\r
4516                 if (blockName == "TD" || blockName == "TABLE" || (blockName == "DIV" && new RegExp('left|right', 'gi').test(startBlock.style.cssFloat)))\r
4517                         blockName = "P";\r
4518         }\r
4519 \r
4520         // Within a list use normal behaviour\r
4521         if (tinyMCE.getParentElement(startBlock, "OL,UL") != null)\r
4522                 return false;\r
4523 \r
4524         // Within a table create new paragraphs\r
4525         if ((startBlock != null && startBlock.nodeName == "TABLE") || (endBlock != null && endBlock.nodeName == "TABLE"))\r
4526                 startBlock = endBlock = null;\r
4527 \r
4528         // Setup new paragraphs\r
4529         var paraBefore = (startBlock != null && startBlock.nodeName == blockName) ? startBlock.cloneNode(false) : doc.createElement(blockName);\r
4530         var paraAfter = (endBlock != null && endBlock.nodeName == blockName) ? endBlock.cloneNode(false) : doc.createElement(blockName);\r
4531 \r
4532         // Is header, then force paragraph under\r
4533         if (/^(H[1-6])$/.test(blockName))\r
4534                 paraAfter = doc.createElement("p");\r
4535 \r
4536         // Setup chop nodes\r
4537         var startChop = startNode;\r
4538         var endChop = endNode;\r
4539 \r
4540         // Get startChop node\r
4541         node = startChop;\r
4542         do {\r
4543                 if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))\r
4544                         break;\r
4545 \r
4546                 startChop = node;\r
4547         } while ((node = node.previousSibling ? node.previousSibling : node.parentNode));\r
4548 \r
4549         // Get endChop node\r
4550         node = endChop;\r
4551         do {\r
4552                 if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))\r
4553                         break;\r
4554 \r
4555                 endChop = node;\r
4556         } while ((node = node.nextSibling ? node.nextSibling : node.parentNode));\r
4557 \r
4558         // Fix when only a image is within the TD\r
4559         if (startChop.nodeName == "TD")\r
4560                 startChop = startChop.firstChild;\r
4561 \r
4562         if (endChop.nodeName == "TD")\r
4563                 endChop = endChop.lastChild;\r
4564 \r
4565         // If not in a block element\r
4566         if (startBlock == null) {\r
4567                 // Delete selection\r
4568                 rng.deleteContents();\r
4569                 sel.removeAllRanges();\r
4570 \r
4571                 if (startChop != rootElm && endChop != rootElm) {\r
4572                         // Insert paragraph before\r
4573                         rngBefore = rng.cloneRange();\r
4574 \r
4575                         if (startChop == body)\r
4576                                 rngBefore.setStart(startChop, 0);\r
4577                         else\r
4578                                 rngBefore.setStartBefore(startChop);\r
4579 \r
4580                         paraBefore.appendChild(rngBefore.cloneContents());\r
4581 \r
4582                         // Insert paragraph after\r
4583                         if (endChop.parentNode.nodeName == blockName)\r
4584                                 endChop = endChop.parentNode;\r
4585 \r
4586                         // If not after image\r
4587                         //if (rng.startContainer.nodeName != "BODY" && rng.endContainer.nodeName != "BODY")\r
4588                                 rng.setEndAfter(endChop);\r
4589 \r
4590                         if (endChop.nodeName != "#text" && endChop.nodeName != "BODY")\r
4591                                 rngBefore.setEndAfter(endChop);\r
4592 \r
4593                         var contents = rng.cloneContents();\r
4594                         if (contents.firstChild && (contents.firstChild.nodeName == blockName || contents.firstChild.nodeName == "BODY"))\r
4595                                 paraAfter.innerHTML = contents.firstChild.innerHTML;\r
4596                         else\r
4597                                 paraAfter.appendChild(contents);\r
4598 \r
4599                         // Check if it's a empty paragraph\r
4600                         if (isEmpty(paraBefore))\r
4601                                 paraBefore.innerHTML = "&nbsp;";\r
4602 \r
4603                         // Check if it's a empty paragraph\r
4604                         if (isEmpty(paraAfter))\r
4605                                 paraAfter.innerHTML = "&nbsp;";\r
4606 \r
4607                         // Delete old contents\r
4608                         rng.deleteContents();\r
4609                         rngAfter.deleteContents();\r
4610                         rngBefore.deleteContents();\r
4611 \r
4612                         // Insert new paragraphs\r
4613                         paraAfter.normalize();\r
4614                         rngBefore.insertNode(paraAfter);\r
4615                         paraBefore.normalize();\r
4616                         rngBefore.insertNode(paraBefore);\r
4617 \r
4618                         // tinyMCE.debug("1: ", paraBefore.innerHTML, paraAfter.innerHTML);\r
4619                 } else {\r
4620                         body.innerHTML = "<" + blockName + ">&nbsp;</" + blockName + "><" + blockName + ">&nbsp;</" + blockName + ">";\r
4621                         paraAfter = body.childNodes[1];\r
4622                 }\r
4623 \r
4624                 this.selectNode(paraAfter, true, true);\r
4625 \r
4626                 return true;\r
4627         }\r
4628 \r
4629         // Place first part within new paragraph\r
4630         if (startChop.nodeName == blockName)\r
4631                 rngBefore.setStart(startChop, 0);\r
4632         else\r
4633                 rngBefore.setStartBefore(startChop);\r
4634 \r
4635         rngBefore.setEnd(startNode, startOffset);\r
4636         paraBefore.appendChild(rngBefore.cloneContents());\r
4637 \r
4638         // Place secound part within new paragraph\r
4639         rngAfter.setEndAfter(endChop);\r
4640         rngAfter.setStart(endNode, endOffset);\r
4641         var contents = rngAfter.cloneContents();\r
4642 \r
4643         if (contents.firstChild && contents.firstChild.nodeName == blockName) {\r
4644 /*              var nodes = contents.firstChild.childNodes;\r
4645                 for (var i=0; i<nodes.length; i++) {\r
4646                         //tinyMCE.debug(nodes[i].nodeName);\r
4647                         if (nodes[i].nodeName != "BODY")\r
4648                                 paraAfter.appendChild(nodes[i]);\r
4649                 }\r
4650 */\r
4651                 paraAfter.innerHTML = contents.firstChild.innerHTML;\r
4652         } else\r
4653                 paraAfter.appendChild(contents);\r
4654 \r
4655         // Check if it's a empty paragraph\r
4656         if (isEmpty(paraBefore))\r
4657                 paraBefore.innerHTML = "&nbsp;";\r
4658 \r
4659         // Check if it's a empty paragraph\r
4660         if (isEmpty(paraAfter))\r
4661                 paraAfter.innerHTML = "&nbsp;";\r
4662 \r
4663         // Create a range around everything\r
4664         var rng = doc.createRange();\r
4665 \r
4666         if (!startChop.previousSibling && startChop.parentNode.nodeName.toUpperCase() == blockName) {\r
4667                 rng.setStartBefore(startChop.parentNode);\r
4668         } else {\r
4669                 if (rngBefore.startContainer.nodeName.toUpperCase() == blockName && rngBefore.startOffset == 0)\r
4670                         rng.setStartBefore(rngBefore.startContainer);\r
4671                 else\r
4672                         rng.setStart(rngBefore.startContainer, rngBefore.startOffset);\r
4673         }\r
4674 \r
4675         if (!endChop.nextSibling && endChop.parentNode.nodeName.toUpperCase() == blockName)\r
4676                 rng.setEndAfter(endChop.parentNode);\r
4677         else\r
4678                 rng.setEnd(rngAfter.endContainer, rngAfter.endOffset);\r
4679 \r
4680         // Delete all contents and insert new paragraphs\r
4681         rng.deleteContents();\r
4682         rng.insertNode(paraAfter);\r
4683         rng.insertNode(paraBefore);\r
4684         //tinyMCE.debug("2", paraBefore.innerHTML, paraAfter.innerHTML);\r
4685 \r
4686         // Normalize\r
4687         paraAfter.normalize();\r
4688         paraBefore.normalize();\r
4689 \r
4690         this.selectNode(paraAfter, true, true);\r
4691 \r
4692         return true;\r
4693 };\r
4694 \r
4695 TinyMCEControl.prototype._handleBackSpace = function(evt_type) {\r
4696         var doc = this.getDoc();\r
4697         var sel = this.getSel();\r
4698         if (sel == null)\r
4699                 return false;\r
4700 \r
4701         var rng = sel.getRangeAt(0);\r
4702         var node = rng.startContainer;\r
4703         var elm = node.nodeType == 3 ? node.parentNode : node;\r
4704 \r
4705         if (node == null)\r
4706                 return;\r
4707 \r
4708         // Empty node, wrap contents in paragraph\r
4709         if (elm && elm.nodeName == "") {\r
4710                 var para = doc.createElement("p");\r
4711 \r
4712                 while (elm.firstChild)\r
4713                         para.appendChild(elm.firstChild);\r
4714 \r
4715                 elm.parentNode.insertBefore(para, elm);\r
4716                 elm.parentNode.removeChild(elm);\r
4717 \r
4718                 var rng = rng.cloneRange();\r
4719                 rng.setStartBefore(node.nextSibling);\r
4720                 rng.setEndAfter(node.nextSibling);\r
4721                 rng.extractContents();\r
4722 \r
4723                 this.selectNode(node.nextSibling, true, true);\r
4724         }\r
4725 \r
4726         // Remove empty paragraphs\r
4727         var para = tinyMCE.getParentBlockElement(node);\r
4728         if (para != null && para.nodeName.toLowerCase() == 'p' && evt_type == "keypress") {\r
4729                 var htm = para.innerHTML;\r
4730                 var block = tinyMCE.getParentBlockElement(node);\r
4731 \r
4732                 // Empty node, we do the killing!!\r
4733                 if (htm == "" || htm == "&nbsp;" || block.nodeName.toLowerCase() == "li") {\r
4734                         var prevElm = para.previousSibling;\r
4735 \r
4736                         while (prevElm != null && prevElm.nodeType != 1)\r
4737                                 prevElm = prevElm.previousSibling;\r
4738 \r
4739                         if (prevElm == null)\r
4740                                 return false;\r
4741 \r
4742                         // Get previous elements last text node\r
4743                         var nodes = tinyMCE.getNodeTree(prevElm, new Array(), 3);\r
4744                         var lastTextNode = nodes.length == 0 ? null : nodes[nodes.length-1];\r
4745 \r
4746                         // Select the last text node and move curstor to end\r
4747                         if (lastTextNode != null)\r
4748                                 this.selectNode(lastTextNode, true, false, false);\r
4749 \r
4750                         // Remove the empty paragrapsh\r
4751                         para.parentNode.removeChild(para);\r
4752 \r
4753                         //debug("within p element" + para.innerHTML);\r
4754                         //showHTML(this.getBody().innerHTML);\r
4755                         return true;\r
4756                 }\r
4757         }\r
4758 \r
4759         // Remove BR elements\r
4760 /*      while (node != null && (node = node.nextSibling) != null) {\r
4761                 if (node.nodeName.toLowerCase() == 'br')\r
4762                         node.parentNode.removeChild(node);\r
4763                 else if (node.nodeType == 1) // Break at other element\r
4764                         break;\r
4765         }*/\r
4766 \r
4767         //showHTML(this.getBody().innerHTML);\r
4768 \r
4769         return false;\r
4770 };\r
4771 \r
4772 TinyMCEControl.prototype._insertSpace = function() {\r
4773         return true;\r
4774 };\r
4775 \r
4776 TinyMCEControl.prototype.autoResetDesignMode = function() {\r
4777         // Add fix for tab/style.display none/block problems in Gecko\r
4778         if (!tinyMCE.isMSIE && tinyMCE.settings['auto_reset_designmode'] && this.isHidden())\r
4779                 eval('try { this.getDoc().designMode = "On"; } catch(e) {}');\r
4780 };\r
4781 \r
4782 TinyMCEControl.prototype.isHidden = function() {\r
4783         if (tinyMCE.isMSIE)\r
4784                 return false;\r
4785 \r
4786         var sel = this.getSel();\r
4787 \r
4788         // Weird, wheres that cursor selection?\r
4789         return (!sel || !sel.rangeCount || sel.rangeCount == 0);\r
4790 };\r
4791 \r
4792 TinyMCEControl.prototype.isDirty = function() {\r
4793         // Is content modified and not in a submit procedure\r
4794         return this.startContent != tinyMCE.trim(this.getBody().innerHTML) && !tinyMCE.isNotDirty;\r
4795 };\r
4796 \r
4797 TinyMCEControl.prototype._mergeElements = function(scmd, pa, ch, override) {\r
4798         if (scmd == "removeformat") {\r
4799                 pa.className = "";\r
4800                 pa.style.cssText = "";\r
4801                 ch.className = "";\r
4802                 ch.style.cssText = "";\r
4803                 return;\r
4804         }\r
4805 \r
4806         var st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));\r
4807         var stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));\r
4808         var className = tinyMCE.getAttrib(pa, "class");\r
4809 \r
4810         className += " " + tinyMCE.getAttrib(ch, "class");\r
4811 \r
4812         if (override) {\r
4813                 for (var n in st) {\r
4814                         if (typeof(st[n]) == 'function')\r
4815                                 continue;\r
4816 \r
4817                         stc[n] = st[n];\r
4818                 }\r
4819         } else {\r
4820                 for (var n in stc) {\r
4821                         if (typeof(stc[n]) == 'function')\r
4822                                 continue;\r
4823 \r
4824                         st[n] = stc[n];\r
4825                 }\r
4826         }\r
4827 \r
4828         tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));\r
4829         tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));\r
4830         ch.className = "";\r
4831         ch.style.cssText = "";\r
4832         ch.removeAttribute("class");\r
4833         ch.removeAttribute("style");\r
4834 };\r
4835 \r
4836 TinyMCEControl.prototype.setUseCSS = function(b) {\r
4837         var doc = this.getDoc();\r
4838         try {doc.execCommand("useCSS", false, !b);} catch (ex) {}\r
4839         try {doc.execCommand("styleWithCSS", false, b);} catch (ex) {}\r
4840 \r
4841         if (!tinyMCE.getParam("table_inline_editing"))\r
4842                 try {doc.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}\r
4843 \r
4844         if (!tinyMCE.getParam("object_resizing"))\r
4845                 try {doc.execCommand('enableObjectResizing', false, "false");} catch (ex) {}\r
4846 };\r
4847 \r
4848 TinyMCEControl.prototype.execCommand = function(command, user_interface, value) {\r
4849         var doc = this.getDoc();\r
4850         var win = this.getWin();\r
4851         var focusElm = this.getFocusElement();\r
4852 \r
4853         if (this.lastSafariSelection && !new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command)) {\r
4854                 this.moveToBookmark(this.lastSafariSelection);\r
4855                 tinyMCE.selectedElement = this.lastSafariSelectedElement;\r
4856         }\r
4857 \r
4858         // Mozilla issue\r
4859         if (!tinyMCE.isMSIE && !this.useCSS) {\r
4860                 this.setUseCSS(false);\r
4861                 this.useCSS = true;\r
4862         }\r
4863 \r
4864         //debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);\r
4865         this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks\r
4866 \r
4867         // Call theme execcommand\r
4868         if (tinyMCE._themeExecCommand(this.editorId, this.getBody(), command, user_interface, value))\r
4869                 return;\r
4870 \r
4871         // Fix align on images\r
4872         if (focusElm && focusElm.nodeName == "IMG") {\r
4873                 var align = focusElm.getAttribute('align');\r
4874                 var img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;\r
4875 \r
4876                 switch (command) {\r
4877                         case "JustifyLeft":\r
4878                                 if (align == 'left')\r
4879                                         img.removeAttribute('align');\r
4880                                 else\r
4881                                         img.setAttribute('align', 'left');\r
4882 \r
4883                                 // Remove the div\r
4884                                 var div = focusElm.parentNode;\r
4885                                 if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)\r
4886                                         div.parentNode.replaceChild(img, div);\r
4887 \r
4888                                 this.selectNode(img);\r
4889                                 this.repaint();\r
4890                                 tinyMCE.triggerNodeChange();\r
4891                                 return;\r
4892 \r
4893                         case "JustifyCenter":\r
4894                                 img.removeAttribute('align');\r
4895 \r
4896                                 // Is centered\r
4897                                 var div = tinyMCE.getParentElement(focusElm, "div");\r
4898                                 if (div && div.style.textAlign == "center") {\r
4899                                         // Remove div\r
4900                                         if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)\r
4901                                                 div.parentNode.replaceChild(img, div);\r
4902                                 } else {\r
4903                                         // Add div\r
4904                                         var div = this.getDoc().createElement("div");\r
4905                                         div.style.textAlign = 'center';\r
4906                                         div.appendChild(img);\r
4907                                         focusElm.parentNode.replaceChild(div, focusElm);\r
4908                                 }\r
4909 \r
4910                                 this.selectNode(img);\r
4911                                 this.repaint();\r
4912                                 tinyMCE.triggerNodeChange();\r
4913                                 return;\r
4914 \r
4915                         case "JustifyRight":\r
4916                                 if (align == 'right')\r
4917                                         img.removeAttribute('align');\r
4918                                 else\r
4919                                         img.setAttribute('align', 'right');\r
4920 \r
4921                                 // Remove the div\r
4922                                 var div = focusElm.parentNode;\r
4923                                 if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)\r
4924                                         div.parentNode.replaceChild(img, div);\r
4925 \r
4926                                 this.selectNode(img);\r
4927                                 this.repaint();\r
4928                                 tinyMCE.triggerNodeChange();\r
4929                                 return;\r
4930                 }\r
4931         }\r
4932 \r
4933         if (tinyMCE.settings['force_br_newlines']) {\r
4934                 var alignValue = "";\r
4935 \r
4936                 if (doc.selection.type != "Control") {\r
4937                         switch (command) {\r
4938                                         case "JustifyLeft":\r
4939                                                 alignValue = "left";\r
4940                                                 break;\r
4941 \r
4942                                         case "JustifyCenter":\r
4943                                                 alignValue = "center";\r
4944                                                 break;\r
4945 \r
4946                                         case "JustifyFull":\r
4947                                                 alignValue = "justify";\r
4948                                                 break;\r
4949 \r
4950                                         case "JustifyRight":\r
4951                                                 alignValue = "right";\r
4952                                                 break;\r
4953                         }\r
4954 \r
4955                         if (alignValue != "") {\r
4956                                 var rng = doc.selection.createRange();\r
4957 \r
4958                                 if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)\r
4959                                         divElm.setAttribute("align", alignValue);\r
4960                                 else if (rng.pasteHTML && rng.htmlText.length > 0)\r
4961                                         rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");\r
4962 \r
4963                                 tinyMCE.triggerNodeChange();\r
4964                                 return;\r
4965                         }\r
4966                 }\r
4967         }\r
4968 \r
4969         switch (command) {\r
4970                 case "mceRepaint":\r
4971                         this.repaint();\r
4972                         return true;\r
4973 \r
4974                 case "mceStoreSelection":\r
4975                         this.selectionBookmark = this.getBookmark();\r
4976                         return true;\r
4977 \r
4978                 case "mceRestoreSelection":\r
4979                         this.moveToBookmark(this.selectionBookmark);\r
4980                         return true;\r
4981 \r
4982                 case "InsertUnorderedList":\r
4983                 case "InsertOrderedList":\r
4984                         var tag = (command == "InsertUnorderedList") ? "ul" : "ol";\r
4985 \r
4986                         if (tinyMCE.isSafari)\r
4987                                 this.execCommand("mceInsertContent", false, "<" + tag + "><li>&nbsp;</li><" + tag + ">");\r
4988                         else\r
4989                                 this.getDoc().execCommand(command, user_interface, value);\r
4990 \r
4991                         tinyMCE.triggerNodeChange();\r
4992                         break;\r
4993 \r
4994                 case "Strikethrough":\r
4995                         if (tinyMCE.isSafari)\r
4996                                 this.execCommand("mceInsertContent", false, "<strike>" + this.getSelectedHTML() + "</strike>");\r
4997                         else\r
4998                                 this.getDoc().execCommand(command, user_interface, value);\r
4999 \r
5000                         tinyMCE.triggerNodeChange();\r
5001                         break;\r
5002 \r
5003                 case "mceSelectNode":\r
5004                         this.selectNode(value);\r
5005                         tinyMCE.triggerNodeChange();\r
5006                         tinyMCE.selectedNode = value;\r
5007                         break;\r
5008 \r
5009                 case "FormatBlock":\r
5010                         if (value == null || value == "") {\r
5011                                 var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address");\r
5012 \r
5013                                 if (elm)\r
5014                                         this.execCommand("mceRemoveNode", false, elm);\r
5015                         } else\r
5016                                 this.getDoc().execCommand("FormatBlock", false, value);\r
5017 \r
5018                         tinyMCE.triggerNodeChange();\r
5019 \r
5020                         break;\r
5021 \r
5022                 case "mceRemoveNode":\r
5023                         if (!value)\r
5024                                 value = tinyMCE.getParentElement(this.getFocusElement());\r
5025 \r
5026                         if (tinyMCE.isMSIE) {\r
5027                                 value.outerHTML = value.innerHTML;\r
5028                         } else {\r
5029                                 var rng = value.ownerDocument.createRange();\r
5030                                 rng.setStartBefore(value);\r
5031                                 rng.setEndAfter(value);\r
5032                                 rng.deleteContents();\r
5033                                 rng.insertNode(rng.createContextualFragment(value.innerHTML));\r
5034                         }\r
5035 \r
5036                         tinyMCE.triggerNodeChange();\r
5037 \r
5038                         break;\r
5039 \r
5040                 case "mceSelectNodeDepth":\r
5041                         var parentNode = this.getFocusElement();\r
5042                         for (var i=0; parentNode; i++) {\r
5043                                 if (parentNode.nodeName.toLowerCase() == "body")\r
5044                                         break;\r
5045 \r
5046                                 if (parentNode.nodeName.toLowerCase() == "#text") {\r
5047                                         i--;\r
5048                                         parentNode = parentNode.parentNode;\r
5049                                         continue;\r
5050                                 }\r
5051 \r
5052                                 if (i == value) {\r
5053                                         this.selectNode(parentNode, false);\r
5054                                         tinyMCE.triggerNodeChange();\r
5055                                         tinyMCE.selectedNode = parentNode;\r
5056                                         return;\r
5057                                 }\r
5058 \r
5059                                 parentNode = parentNode.parentNode;\r
5060                         }\r
5061 \r
5062                         break;\r
5063 \r
5064                 case "SetStyleInfo":\r
5065                         var rng = this.getRng();\r
5066                         var sel = this.getSel();\r
5067                         var scmd = value['command'];\r
5068                         var sname = value['name'];\r
5069                         var svalue = value['value'] == null ? '' : value['value'];\r
5070                         //var svalue = value['value'] == null ? '' : value['value'];\r
5071                         var wrapper = value['wrapper'] ? value['wrapper'] : "span";\r
5072                         var parentElm = null;\r
5073                         var invalidRe = new RegExp("^BODY|HTML$", "g");\r
5074                         var invalidParentsRe = tinyMCE.settings['merge_styles_invalid_parents'] != '' ? new RegExp(tinyMCE.settings['merge_styles_invalid_parents'], "gi") : null;\r
5075 \r
5076                         // Whole element selected check\r
5077                         if (tinyMCE.isMSIE) {\r
5078                                 // Control range\r
5079                                 if (rng.item)\r
5080                                         parentElm = rng.item(0);\r
5081                                 else {\r
5082                                         var pelm = rng.parentElement();\r
5083                                         var prng = doc.selection.createRange();\r
5084                                         prng.moveToElementText(pelm);\r
5085 \r
5086                                         if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {\r
5087                                                 if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))\r
5088                                                         parentElm = pelm;\r
5089                                         }\r
5090                                 }\r
5091                         } else {\r
5092                                 var felm = this.getFocusElement();\r
5093                                 if (sel.isCollapsed || (/td|tr|tbody|table/ig.test(felm.nodeName) && sel.anchorNode == felm.parentNode))\r
5094                                         parentElm = felm;\r
5095                         }\r
5096 \r
5097                         // Whole element selected\r
5098                         if (parentElm && !invalidRe.test(parentElm.nodeName)) {\r
5099                                 if (scmd == "setstyle")\r
5100                                         tinyMCE.setStyleAttrib(parentElm, sname, svalue);\r
5101 \r
5102                                 if (scmd == "setattrib")\r
5103                                         tinyMCE.setAttrib(parentElm, sname, svalue);\r
5104 \r
5105                                 if (scmd == "removeformat") {\r
5106                                         parentElm.style.cssText = '';\r
5107                                         tinyMCE.setAttrib(parentElm, 'class', '');\r
5108                                 }\r
5109 \r
5110                                 // Remove style/attribs from all children\r
5111                                 var ch = tinyMCE.getNodeTree(parentElm, new Array(), 1);\r
5112                                 for (var z=0; z<ch.length; z++) {\r
5113                                         if (ch[z] == parentElm)\r
5114                                                 continue;\r
5115 \r
5116                                         if (scmd == "setstyle")\r
5117                                                 tinyMCE.setStyleAttrib(ch[z], sname, '');\r
5118 \r
5119                                         if (scmd == "setattrib")\r
5120                                                 tinyMCE.setAttrib(ch[z], sname, '');\r
5121 \r
5122                                         if (scmd == "removeformat") {\r
5123                                                 ch[z].style.cssText = '';\r
5124                                                 tinyMCE.setAttrib(ch[z], 'class', '');\r
5125                                         }\r
5126                                 }\r
5127                         } else {\r
5128                                 doc.execCommand("fontname", false, "#mce_temp_font#");\r
5129                                 var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");\r
5130 \r
5131                                 // Change them all\r
5132                                 for (var x=0; x<elementArray.length; x++) {\r
5133                                         elm = elementArray[x];\r
5134                                         if (elm) {\r
5135                                                 var spanElm = doc.createElement(wrapper);\r
5136 \r
5137                                                 if (scmd == "setstyle")\r
5138                                                         tinyMCE.setStyleAttrib(spanElm, sname, svalue);\r
5139 \r
5140                                                 if (scmd == "setattrib")\r
5141                                                         tinyMCE.setAttrib(spanElm, sname, svalue);\r
5142 \r
5143                                                 if (scmd == "removeformat") {\r
5144                                                         spanElm.style.cssText = '';\r
5145                                                         tinyMCE.setAttrib(spanElm, 'class', '');\r
5146                                                 }\r
5147 \r
5148                                                 if (elm.hasChildNodes()) {\r
5149                                                         for (var i=0; i<elm.childNodes.length; i++)\r
5150                                                                 spanElm.appendChild(elm.childNodes[i].cloneNode(true));\r
5151                                                 }\r
5152 \r
5153                                                 spanElm.setAttribute("mce_new", "true");\r
5154                                                 elm.parentNode.replaceChild(spanElm, elm);\r
5155 \r
5156                                                 // Remove style/attribs from all children\r
5157                                                 var ch = tinyMCE.getNodeTree(spanElm, new Array(), 1);\r
5158                                                 for (var z=0; z<ch.length; z++) {\r
5159                                                         if (ch[z] == spanElm)\r
5160                                                                 continue;\r
5161 \r
5162                                                         if (scmd == "setstyle")\r
5163                                                                 tinyMCE.setStyleAttrib(ch[z], sname, '');\r
5164 \r
5165                                                         if (scmd == "setattrib")\r
5166                                                                 tinyMCE.setAttrib(ch[z], sname, '');\r
5167 \r
5168                                                         if (scmd == "removeformat") {\r
5169                                                                 ch[z].style.cssText = '';\r
5170                                                                 tinyMCE.setAttrib(ch[z], 'class', '');\r
5171                                                         }\r
5172                                                 }\r
5173                                         }\r
5174                                 }\r
5175                         }\r
5176 \r
5177                         // Cleaup wrappers\r
5178                         var nodes = doc.getElementsByTagName(wrapper);\r
5179                         for (var i=nodes.length-1; i>=0; i--) {\r
5180                                 var elm = nodes[i];\r
5181                                 var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";\r
5182 \r
5183                                 elm.removeAttribute("mce_new");\r
5184 \r
5185                                 // Is only child a element\r
5186                                 if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {\r
5187                                         //tinyMCE.debug("merge1" + isNew);\r
5188                                         this._mergeElements(scmd, elm, elm.childNodes[0], isNew);\r
5189                                         continue;\r
5190                                 }\r
5191 \r
5192                                 // Is I the only child\r
5193                                 if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {\r
5194                                         //tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);\r
5195                                         if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))\r
5196                                                 this._mergeElements(scmd, elm.parentNode, elm, false);\r
5197                                 }\r
5198                         }\r
5199 \r
5200                         // Remove empty wrappers\r
5201                         var nodes = doc.getElementsByTagName(wrapper);\r
5202                         for (var i=nodes.length-1; i>=0; i--) {\r
5203                                 var elm = nodes[i];\r
5204                                 var isEmpty = true;\r
5205 \r
5206                                 // Check if it has any attribs\r
5207                                 var tmp = doc.createElement("body");\r
5208                                 tmp.appendChild(elm.cloneNode(false));\r
5209 \r
5210                                 // Is empty span, remove it\r
5211                                 tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');\r
5212                                 //tinyMCE.debug(tmp.innerHTML);\r
5213                                 if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {\r
5214                                         for (var x=0; x<elm.childNodes.length; x++) {\r
5215                                                 if (elm.parentNode != null)\r
5216                                                         elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);\r
5217                                         }\r
5218 \r
5219                                         elm.parentNode.removeChild(elm);\r
5220                                 }\r
5221                         }\r
5222 \r
5223                         // Re add the visual aids\r
5224                         if (scmd == "removeformat")\r
5225                                 tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);\r
5226 \r
5227                         tinyMCE.triggerNodeChange();\r
5228 \r
5229                         break;\r
5230 \r
5231                 case "FontName":\r
5232                         if (value == null) {\r
5233                                 var s = this.getSel();\r
5234 \r
5235                                 // Find font and select it\r
5236                                 if (tinyMCE.isGecko && s.isCollapsed) {\r
5237                                         var f = tinyMCE.getParentElement(this.getFocusElement(), "font");\r
5238 \r
5239                                         if (f != null)\r
5240                                                 this.selectNode(f, false);\r
5241                                 }\r
5242 \r
5243                                 // Remove format\r
5244                                 this.getDoc().execCommand("RemoveFormat", false, null);\r
5245 \r
5246                                 // Collapse range if font was found\r
5247                                 if (f != null && tinyMCE.isGecko) {\r
5248                                         var r = this.getRng().cloneRange();\r
5249                                         r.collapse(true);\r
5250                                         s.removeAllRanges();\r
5251                                         s.addRange(r);\r
5252                                 }\r
5253                         } else\r
5254                                 this.getDoc().execCommand('FontName', false, value);\r
5255 \r
5256                         if (tinyMCE.isGecko)\r
5257                                 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);\r
5258 \r
5259                         return;\r
5260 \r
5261                 case "FontSize":\r
5262                         this.getDoc().execCommand('FontSize', false, value);\r
5263 \r
5264                         if (tinyMCE.isGecko)\r
5265                                 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);\r
5266 \r
5267                         return;\r
5268 \r
5269                 case "forecolor":\r
5270                         this.getDoc().execCommand('forecolor', false, value);\r
5271                         break;\r
5272 \r
5273                 case "HiliteColor":\r
5274                         if (tinyMCE.isGecko) {\r
5275                                 this.setUseCSS(true);\r
5276                                 this.getDoc().execCommand('hilitecolor', false, value);\r
5277                                 this.setUseCSS(false);\r
5278                         } else\r
5279                                 this.getDoc().execCommand('BackColor', false, value);\r
5280                         break;\r
5281 \r
5282                 case "Cut":\r
5283                 case "Copy":\r
5284                 case "Paste":\r
5285                         var cmdFailed = false;\r
5286 \r
5287                         // Try executing command\r
5288                         eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');\r
5289 \r
5290                         if (tinyMCE.isOpera && cmdFailed)\r
5291                                 alert('Currently not supported by your browser, use keyboard shortcuts instead.');\r
5292 \r
5293                         // Alert error in gecko if command failed\r
5294                         if (tinyMCE.isGecko && cmdFailed) {\r
5295                                 // Confirm more info\r
5296                                 if (confirm(tinyMCE.getLang('lang_clipboard_msg')))\r
5297                                         window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');\r
5298 \r
5299                                 return;\r
5300                         } else\r
5301                                 tinyMCE.triggerNodeChange();\r
5302                 break;\r
5303 \r
5304                 case "mceSetContent":\r
5305                         if (!value)\r
5306                                 value = "";\r
5307 \r
5308                         // Call custom cleanup code\r
5309                         value = tinyMCE.storeAwayURLs(value);\r
5310                         value = tinyMCE._customCleanup(this, "insert_to_editor", value);\r
5311                         tinyMCE._setHTML(doc, value);\r
5312                         tinyMCE.setInnerHTML(doc.body, tinyMCE._cleanupHTML(this, doc, tinyMCE.settings, doc.body));\r
5313                         this.convertAllRelativeURLs();\r
5314                         tinyMCE.handleVisualAid(doc.body, true, this.visualAid, this);\r
5315                         tinyMCE._setEventsEnabled(doc.body, false);\r
5316                         return true;\r
5317 \r
5318                 case "mceLink":\r
5319                         var selectedText = "";\r
5320 \r
5321                         if (tinyMCE.isMSIE) {\r
5322                                 var rng = doc.selection.createRange();\r
5323                                 selectedText = rng.text;\r
5324                         } else\r
5325                                 selectedText = this.getSel().toString();\r
5326 \r
5327                         if (!tinyMCE.linkElement) {\r
5328                                 if ((tinyMCE.selectedElement.nodeName.toLowerCase() != "img") && (selectedText.length <= 0))\r
5329                                         return;\r
5330                         }\r
5331 \r
5332                         var href = "", target = "", title = "", onclick = "", action = "insert", style_class = "";\r
5333 \r
5334                         if (tinyMCE.selectedElement.nodeName.toLowerCase() == "a")\r
5335                                 tinyMCE.linkElement = tinyMCE.selectedElement;\r
5336 \r
5337                         // Is anchor not a link\r
5338                         if (tinyMCE.linkElement != null && tinyMCE.getAttrib(tinyMCE.linkElement, 'href') == "")\r
5339                                 tinyMCE.linkElement = null;\r
5340 \r
5341                         if (tinyMCE.linkElement) {\r
5342                                 href = tinyMCE.getAttrib(tinyMCE.linkElement, 'href');\r
5343                                 target = tinyMCE.getAttrib(tinyMCE.linkElement, 'target');\r
5344                                 title = tinyMCE.getAttrib(tinyMCE.linkElement, 'title');\r
5345                 onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');\r
5346                                 style_class = tinyMCE.getAttrib(tinyMCE.linkElement, 'class');\r
5347 \r
5348                                 // Try old onclick to if copy/pasted content\r
5349                                 if (onclick == "")\r
5350                                         onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');\r
5351 \r
5352                                 onclick = tinyMCE.cleanupEventStr(onclick);\r
5353 \r
5354                                 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");\r
5355 \r
5356                                 // Use mce_href if defined\r
5357                                 mceRealHref = tinyMCE.getAttrib(tinyMCE.linkElement, 'mce_href');\r
5358                                 if (mceRealHref != "") {\r
5359                                         href = mceRealHref;\r
5360 \r
5361                                         if (tinyMCE.getParam('convert_urls'))\r
5362                                                 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");\r
5363                                 }\r
5364 \r
5365                                 action = "update";\r
5366                         }\r
5367 \r
5368                         if (this.settings['insertlink_callback']) {\r
5369                                 var returnVal = eval(this.settings['insertlink_callback'] + "(href, target, title, onclick, action, style_class);");\r
5370                                 if (returnVal && returnVal['href'])\r
5371                                         tinyMCE.insertLink(returnVal['href'], returnVal['target'], returnVal['title'], returnVal['onclick'], returnVal['style_class']);\r
5372                         } else {\r
5373                                 tinyMCE.openWindow(this.insertLinkTemplate, {href : href, target : target, title : title, onclick : onclick, action : action, className : style_class, inline : "yes"});\r
5374                         }\r
5375                 break;\r
5376 \r
5377                 case "mceImage":\r
5378                         var src = "", alt = "", border = "", hspace = "", vspace = "", width = "", height = "", align = "";\r
5379                         var title = "", onmouseover = "", onmouseout = "", action = "insert";\r
5380                         var img = tinyMCE.imgElement;\r
5381 \r
5382                         if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img") {\r
5383                                 img = tinyMCE.selectedElement;\r
5384                                 tinyMCE.imgElement = img;\r
5385                         }\r
5386 \r
5387                         if (img) {\r
5388                                 // Is it a internal MCE visual aid image, then skip this one.\r
5389                                 if (tinyMCE.getAttrib(img, 'name').indexOf('mce_') == 0)\r
5390                                         return;\r
5391 \r
5392                                 src = tinyMCE.getAttrib(img, 'src');\r
5393                                 alt = tinyMCE.getAttrib(img, 'alt');\r
5394 \r
5395                                 // Try polling out the title\r
5396                                 if (alt == "")\r
5397                                         alt = tinyMCE.getAttrib(img, 'title');\r
5398 \r
5399                                 // Fix width/height attributes if the styles is specified\r
5400                                 if (tinyMCE.isGecko) {\r
5401                                         var w = img.style.width;\r
5402                                         if (w != null && w != "")\r
5403                                                 img.setAttribute("width", w);\r
5404 \r
5405                                         var h = img.style.height;\r
5406                                         if (h != null && h != "")\r
5407                                                 img.setAttribute("height", h);\r
5408                                 }\r
5409 \r
5410                                 border = tinyMCE.getAttrib(img, 'border');\r
5411                                 hspace = tinyMCE.getAttrib(img, 'hspace');\r
5412                                 vspace = tinyMCE.getAttrib(img, 'vspace');\r
5413                                 width = tinyMCE.getAttrib(img, 'width');\r
5414                                 height = tinyMCE.getAttrib(img, 'height');\r
5415                                 align = tinyMCE.getAttrib(img, 'align');\r
5416                 onmouseover = tinyMCE.getAttrib(img, 'onmouseover');\r
5417                 onmouseout = tinyMCE.getAttrib(img, 'onmouseout');\r
5418                 title = tinyMCE.getAttrib(img, 'title');\r
5419 \r
5420                                 // Is realy specified?\r
5421                                 if (tinyMCE.isMSIE) {\r
5422                                         width = img.attributes['width'].specified ? width : "";\r
5423                                         height = img.attributes['height'].specified ? height : "";\r
5424                                 }\r
5425 \r
5426                                 onmouseover = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseover));\r
5427                                 onmouseout = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseout));\r
5428 \r
5429                                 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");\r
5430 \r
5431                                 // Use mce_src if defined\r
5432                                 mceRealSrc = tinyMCE.getAttrib(img, 'mce_src');\r
5433                                 if (mceRealSrc != "") {\r
5434                                         src = mceRealSrc;\r
5435 \r
5436                                         if (tinyMCE.getParam('convert_urls'))\r
5437                                                 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");\r
5438                                 }\r
5439 \r
5440                                 if (onmouseover != "")\r
5441                                         onmouseover = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, img, true);");\r
5442 \r
5443                                 if (onmouseout != "")\r
5444                                         onmouseout = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, img, true);");\r
5445 \r
5446                                 action = "update";\r
5447                         }\r
5448 \r
5449                         if (this.settings['insertimage_callback']) {\r
5450                                 var returnVal = eval(this.settings['insertimage_callback'] + "(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout, action);");\r
5451                                 if (returnVal && returnVal['src'])\r
5452                                         tinyMCE.insertImage(returnVal['src'], returnVal['alt'], returnVal['border'], returnVal['hspace'], returnVal['vspace'], returnVal['width'], returnVal['height'], returnVal['align'], returnVal['title'], returnVal['onmouseover'], returnVal['onmouseout']);\r
5453                         } else\r
5454                                 tinyMCE.openWindow(this.insertImageTemplate, {src : src, alt : alt, border : border, hspace : hspace, vspace : vspace, width : width, height : height, align : align, title : title, onmouseover : onmouseover, onmouseout : onmouseout, action : action, inline : "yes"});\r
5455                 break;\r
5456 \r
5457                 case "mceCleanup":\r
5458                         tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);\r
5459                         tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));\r
5460                         this.convertAllRelativeURLs();\r
5461                         tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);\r
5462                         tinyMCE._setEventsEnabled(this.getBody(), false);\r
5463                         this.repaint();\r
5464                         tinyMCE.triggerNodeChange();\r
5465                 break;\r
5466 \r
5467                 case "mceReplaceContent":\r
5468                         this.getWin().focus();\r
5469 \r
5470                         var selectedText = "";\r
5471 \r
5472                         if (tinyMCE.isMSIE) {\r
5473                                 var rng = doc.selection.createRange();\r
5474                                 selectedText = rng.text;\r
5475                         } else\r
5476                                 selectedText = this.getSel().toString();\r
5477 \r
5478                         if (selectedText.length > 0) {\r
5479                                 value = tinyMCE.replaceVar(value, "selection", selectedText);\r
5480                                 tinyMCE.execCommand('mceInsertContent', false, value);\r
5481                         }\r
5482 \r
5483                         tinyMCE.triggerNodeChange();\r
5484                 break;\r
5485 \r
5486                 case "mceSetAttribute":\r
5487                         if (typeof(value) == 'object') {\r
5488                                 var targetElms = (typeof(value['targets']) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value['targets'];\r
5489                                 var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);\r
5490 \r
5491                                 if (targetNode) {\r
5492                                         targetNode.setAttribute(value['name'], value['value']);\r
5493                                         tinyMCE.triggerNodeChange();\r
5494                                 }\r
5495                         }\r
5496                 break;\r
5497 \r
5498                 case "mceSetCSSClass":\r
5499                         this.execCommand("SetStyleInfo", false, {command : "setattrib", name : "class", value : value});\r
5500                 break;\r
5501 \r
5502                 case "mceInsertRawHTML":\r
5503                         var key = 'tiny_mce_marker';\r
5504 \r
5505                         this.execCommand('mceBeginUndoLevel');\r
5506 \r
5507                         // Insert marker key\r
5508                         this.execCommand('mceInsertContent', false, key);\r
5509 \r
5510                         // Store away scroll pos\r
5511                         var scrollX = this.getDoc().body.scrollLeft + this.getDoc().documentElement.scrollLeft;\r
5512                         var scrollY = this.getDoc().body.scrollTop + this.getDoc().documentElement.scrollTop;\r
5513 \r
5514                         // Find marker and replace with RAW HTML\r
5515                         var html = this.getBody().innerHTML;\r
5516                         if ((pos = html.indexOf(key)) != -1)\r
5517                                 tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));\r
5518 \r
5519                         // Restore scoll pos\r
5520                         this.contentWindow.scrollTo(scrollX, scrollY);\r
5521 \r
5522                         this.execCommand('mceEndUndoLevel');\r
5523 \r
5524                         break;\r
5525 \r
5526                 case "mceInsertContent":\r
5527                         var insertHTMLFailed = false;\r
5528                         this.getWin().focus();\r
5529 \r
5530                         if (tinyMCE.isGecko || tinyMCE.isOpera) {\r
5531                                 try {\r
5532                                         // Is plain text or HTML\r
5533                                         if (value.indexOf('<') == -1) {\r
5534                                                 var r = this.getRng();\r
5535                                                 var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));\r
5536                                                 var s = this.getSel();\r
5537                                                 var r2 = r.cloneRange();\r
5538 \r
5539                                                 // Insert text at cursor position\r
5540                                                 s.removeAllRanges();\r
5541                                                 r.deleteContents();\r
5542                                                 r.insertNode(n);\r
5543 \r
5544                                                 // Move the cursor to the end of text\r
5545                                                 r2.selectNode(n);\r
5546                                                 r2.collapse(false);\r
5547                                                 s.removeAllRanges();\r
5548                                                 s.addRange(r2);\r
5549                                         } else {\r
5550                                                 value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);\r
5551                                                 this.getDoc().execCommand('inserthtml', false, value);\r
5552                                                 tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);\r
5553                                         }\r
5554                                 } catch (ex) {\r
5555                                         insertHTMLFailed = true;\r
5556                                 }\r
5557 \r
5558                                 if (!insertHTMLFailed) {\r
5559                                         tinyMCE.triggerNodeChange();\r
5560                                         return;\r
5561                                 }\r
5562                         }\r
5563 \r
5564                         // Ugly hack in Opera due to non working "inserthtml"\r
5565                         if (tinyMCE.isOpera && insertHTMLFailed) {\r
5566                                 this.getDoc().execCommand("insertimage", false, tinyMCE.uniqueURL);\r
5567                                 var ar = tinyMCE.getElementsByAttributeValue(this.getBody(), "img", "src", tinyMCE.uniqueURL);\r
5568                                 ar[0].outerHTML = value;\r
5569                                 return;\r
5570                         }\r
5571 \r
5572                         if (!tinyMCE.isMSIE) {\r
5573                                 var isHTML = value.indexOf('<') != -1;\r
5574                                 var sel = this.getSel();\r
5575                                 var rng = this.getRng();\r
5576 \r
5577                                 if (isHTML) {\r
5578                                         if (tinyMCE.isSafari) {\r
5579                                                 var tmpRng = this.getDoc().createRange();\r
5580 \r
5581                                                 tmpRng.setStart(this.getBody(), 0);\r
5582                                                 tmpRng.setEnd(this.getBody(), 0);\r
5583 \r
5584                                                 value = tmpRng.createContextualFragment(value);\r
5585                                         } else\r
5586                                                 value = rng.createContextualFragment(value);\r
5587                                 } else {\r
5588                                         // Setup text node\r
5589                                         var el = document.createElement("div");\r
5590                                         el.innerHTML = value;\r
5591                                         value = el.firstChild.nodeValue;\r
5592                                         value = doc.createTextNode(value);\r
5593                                 }\r
5594 \r
5595                                 // Insert plain text in Safari\r
5596                                 if (tinyMCE.isSafari && !isHTML) {\r
5597                                         this.execCommand('InsertText', false, value.nodeValue);\r
5598                                         tinyMCE.triggerNodeChange();\r
5599                                         return true;\r
5600                                 } else if (tinyMCE.isSafari && isHTML) {\r
5601                                         rng.deleteContents();\r
5602                                         rng.insertNode(value);\r
5603                                         tinyMCE.triggerNodeChange();\r
5604                                         return true;\r
5605                                 }\r
5606 \r
5607                                 rng.deleteContents();\r
5608 \r
5609                                 // If target node is text do special treatment, (Mozilla 1.3 fix)\r
5610                                 if (rng.startContainer.nodeType == 3) {\r
5611                                         var node = rng.startContainer.splitText(rng.startOffset);\r
5612                                         node.parentNode.insertBefore(value, node); \r
5613                                 } else\r
5614                                         rng.insertNode(value);\r
5615 \r
5616                                 if (!isHTML) {\r
5617                                         // Removes weird selection trails\r
5618                                         sel.selectAllChildren(doc.body);\r
5619                                         sel.removeAllRanges();\r
5620 \r
5621                                         // Move cursor to end of content\r
5622                                         var rng = doc.createRange();\r
5623 \r
5624                                         rng.selectNode(value);\r
5625                                         rng.collapse(false);\r
5626 \r
5627                                         sel.addRange(rng);\r
5628                                 } else\r
5629                                         rng.collapse(false);\r
5630                         } else {\r
5631                                 var rng = doc.selection.createRange();\r
5632                                 var c = value.indexOf('<!--') != -1;\r
5633 \r
5634                                 // Fix comment bug, add tag before comments\r
5635                                 if (c)\r
5636                                         value = tinyMCE.uniqueTag + value;\r
5637 \r
5638                                 if (rng.item)\r
5639                                         rng.item(0).outerHTML = value;\r
5640                                 else\r
5641                                         rng.pasteHTML(value);\r
5642 \r
5643                                 // Remove unique tag\r
5644                                 if (c) {\r
5645                                         var e = this.getDoc().getElementById('mceTMPElement');\r
5646                                         e.parentNode.removeChild(e);\r
5647                                 }\r
5648                         }\r
5649 \r
5650                         tinyMCE.triggerNodeChange();\r
5651                 break;\r
5652 \r
5653                 case "mceStartTyping":\r
5654                         if (tinyMCE.settings['custom_undo_redo'] && this.typingUndoIndex == -1) {\r
5655                                 this.typingUndoIndex = this.undoIndex;\r
5656                                 this.execCommand('mceAddUndoLevel');\r
5657                                 //tinyMCE.debug("mceStartTyping");\r
5658                         }\r
5659                         break;\r
5660 \r
5661                 case "mceEndTyping":\r
5662                         if (tinyMCE.settings['custom_undo_redo'] && this.typingUndoIndex != -1) {\r
5663                                 this.execCommand('mceAddUndoLevel');\r
5664                                 this.typingUndoIndex = -1;\r
5665                                 //tinyMCE.debug("mceEndTyping");\r
5666                         }\r
5667                         break;\r
5668 \r
5669                 case "mceBeginUndoLevel":\r
5670                         this.undoRedo = false;\r
5671                         break;\r
5672 \r
5673                 case "mceEndUndoLevel":\r
5674                         this.undoRedo = true;\r
5675                         this.execCommand('mceAddUndoLevel');\r
5676                         break;\r
5677 \r
5678                 case "mceAddUndoLevel":\r
5679                         if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo) {\r
5680                                 // tinyMCE.debug("add level");\r
5681 \r
5682                                 if (this.typingUndoIndex != -1) {\r
5683                                         this.undoIndex = this.typingUndoIndex;\r
5684                                         // tinyMCE.debug("Override: " + this.undoIndex);\r
5685                                 }\r
5686 \r
5687                                 var newHTML = tinyMCE.trim(this.getBody().innerHTML);\r
5688                                 if (newHTML != this.undoLevels[this.undoIndex]) {\r
5689                                         tinyMCE.executeCallback('onchange_callback', '_onchange', 0, this);\r
5690 \r
5691                                         // Time to compress\r
5692                                         var customUndoLevels = tinyMCE.settings['custom_undo_redo_levels'];\r
5693                                         if (customUndoLevels != -1 && this.undoLevels.length > customUndoLevels) {\r
5694                                                 for (var i=0; i<this.undoLevels.length-1; i++) {\r
5695                                                         //tinyMCE.debug(this.undoLevels[i] + "=" + this.undoLevels[i+1]);\r
5696                                                         this.undoLevels[i] = this.undoLevels[i+1];\r
5697                                                 }\r
5698 \r
5699                                                 this.undoLevels.length--;\r
5700                                                 this.undoIndex--;\r
5701                                         }\r
5702 \r
5703                                         this.undoIndex++;\r
5704                                         this.undoLevels[this.undoIndex] = newHTML;\r
5705                                         this.undoLevels.length = this.undoIndex + 1;\r
5706 \r
5707                                         // tinyMCE.debug("level added" + this.undoIndex);\r
5708                                         tinyMCE.triggerNodeChange(false);\r
5709 \r
5710                                         // tinyMCE.debug(this.undoIndex + "," + (this.undoLevels.length-1));\r
5711                                 }\r
5712                         }\r
5713                         break;\r
5714 \r
5715                 case "Undo":\r
5716                         if (tinyMCE.settings['custom_undo_redo']) {\r
5717                                 tinyMCE.execCommand("mceEndTyping");\r
5718 \r
5719                                 // Do undo\r
5720                                 if (this.undoIndex > 0) {\r
5721                                         this.undoIndex--;\r
5722                                         tinyMCE.setInnerHTML(this.getBody(), this.undoLevels[this.undoIndex]);\r
5723                                         this.repaint();\r
5724                                 }\r
5725 \r
5726                                 // tinyMCE.debug("Undo - undo levels:" + this.undoLevels.length + ", undo index: " + this.undoIndex);\r
5727                                 tinyMCE.triggerNodeChange();\r
5728                         } else\r
5729                                 this.getDoc().execCommand(command, user_interface, value);\r
5730                         break;\r
5731 \r
5732                 case "Redo":\r
5733                         if (tinyMCE.settings['custom_undo_redo']) {\r
5734                                 tinyMCE.execCommand("mceEndTyping");\r
5735 \r
5736                                 if (this.undoIndex < (this.undoLevels.length-1)) {\r
5737                                         this.undoIndex++;\r
5738                                         tinyMCE.setInnerHTML(this.getBody(), this.undoLevels[this.undoIndex]);\r
5739                                         this.repaint();\r
5740                                         // tinyMCE.debug("Redo - undo levels:" + this.undoLevels.length + ", undo index: " + this.undoIndex);\r
5741                                 }\r
5742 \r
5743                                 tinyMCE.triggerNodeChange();\r
5744                         } else\r
5745                                 this.getDoc().execCommand(command, user_interface, value);\r
5746                         break;\r
5747 \r
5748                 case "mceToggleVisualAid":\r
5749                         this.visualAid = !this.visualAid;\r
5750                         tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);\r
5751                         tinyMCE.triggerNodeChange();\r
5752                         break;\r
5753 \r
5754                 case "Indent":\r
5755                         this.getDoc().execCommand(command, user_interface, value);\r
5756                         tinyMCE.triggerNodeChange();\r
5757                         if (tinyMCE.isMSIE) {\r
5758                                 var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");\r
5759                                 do {\r
5760                                         if (n && n.nodeName == "BLOCKQUOTE") {\r
5761                                                 n.removeAttribute("dir");\r
5762                                                 n.removeAttribute("style");\r
5763                                         }\r
5764                                 } while (n != null && (n = n.parentNode) != null);\r
5765                         }\r
5766                         break;\r
5767 \r
5768                 case "removeformat":\r
5769                         var text = this.getSelectedText();\r
5770 \r
5771                         if (tinyMCE.isOpera) {\r
5772                                 this.getDoc().execCommand("RemoveFormat", false, null);\r
5773                                 return;\r
5774                         }\r
5775 \r
5776                         if (tinyMCE.isMSIE) {\r
5777                                 try {\r
5778                                         var rng = doc.selection.createRange();\r
5779                                         rng.execCommand("RemoveFormat", false, null);\r
5780                                 } catch (e) {\r
5781                                         // Do nothing\r
5782                                 }\r
5783 \r
5784                                 this.execCommand("SetStyleInfo", false, {command : "removeformat"});\r
5785                         } else {\r
5786                                 this.getDoc().execCommand(command, user_interface, value);\r
5787 \r
5788                                 this.execCommand("SetStyleInfo", false, {command : "removeformat"});\r
5789                         }\r
5790 \r
5791                         // Remove class\r
5792                         if (text.length == 0)\r
5793                                 this.execCommand("mceSetCSSClass", false, "");\r
5794 \r
5795                         tinyMCE.triggerNodeChange();\r
5796                         break;\r
5797 \r
5798                 default:\r
5799                         this.getDoc().execCommand(command, user_interface, value);\r
5800 \r
5801                         if (tinyMCE.isGecko)\r
5802                                 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);\r
5803                         else\r
5804                                 tinyMCE.triggerNodeChange();\r
5805         }\r
5806 \r
5807         // Add undo level after modification\r
5808         if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")\r
5809                 tinyMCE.execCommand("mceAddUndoLevel");\r
5810 };\r
5811 \r
5812 TinyMCEControl.prototype.queryCommandValue = function(command) {\r
5813         try {\r
5814                 return this.getDoc().queryCommandValue(command);\r
5815         } catch (ex) {\r
5816                 return null;\r
5817         }\r
5818 };\r
5819 \r
5820 TinyMCEControl.prototype.queryCommandState = function(command) {\r
5821         return this.getDoc().queryCommandState(command);\r
5822 };\r
5823 \r
5824 TinyMCEControl.prototype.onAdd = function(replace_element, form_element_name, target_document) {\r
5825         var targetDoc = target_document ? target_document : document;\r
5826 \r
5827         this.targetDoc = targetDoc;\r
5828 \r
5829         tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings['theme'];\r
5830         this.settings['themeurl'] = tinyMCE.themeURL;\r
5831 \r
5832         if (!replace_element) {\r
5833                 alert("Error: Could not find the target element.");\r
5834                 return false;\r
5835         }\r
5836 \r
5837         var templateFunction = tinyMCE._getThemeFunction('_getInsertLinkTemplate');\r
5838         if (eval("typeof(" + templateFunction + ")") != 'undefined')\r
5839                 this.insertLinkTemplate = eval(templateFunction + '(this.settings);');\r
5840 \r
5841         var templateFunction = tinyMCE._getThemeFunction('_getInsertImageTemplate');\r
5842         if (eval("typeof(" + templateFunction + ")") != 'undefined')\r
5843                 this.insertImageTemplate = eval(templateFunction + '(this.settings);');\r
5844 \r
5845         var templateFunction = tinyMCE._getThemeFunction('_getEditorTemplate');\r
5846         if (eval("typeof(" + templateFunction + ")") == 'undefined') {\r
5847                 alert("Error: Could not find the template function: " + templateFunction);\r
5848                 return false;\r
5849         }\r
5850 \r
5851         var editorTemplate = eval(templateFunction + '(this.settings, this.editorId);');\r
5852 \r
5853         var deltaWidth = editorTemplate['delta_width'] ? editorTemplate['delta_width'] : 0;\r
5854         var deltaHeight = editorTemplate['delta_height'] ? editorTemplate['delta_height'] : 0;\r
5855         var html = '<span id="' + this.editorId + '_parent">' + editorTemplate['html'];\r
5856 \r
5857         var templateFunction = tinyMCE._getThemeFunction('_handleNodeChange', true);\r
5858         if (eval("typeof(" + templateFunction + ")") != 'undefined')\r
5859                 this.settings['handleNodeChangeCallback'] = templateFunction;\r
5860 \r
5861         html = tinyMCE.replaceVar(html, "editor_id", this.editorId);\r
5862         this.settings['default_document'] = tinyMCE.baseURL + "/blank.htm";\r
5863 \r
5864         this.settings['old_width'] = this.settings['width'];\r
5865         this.settings['old_height'] = this.settings['height'];\r
5866 \r
5867         // Set default width, height\r
5868         if (this.settings['width'] == -1)\r
5869                 this.settings['width'] = replace_element.offsetWidth;\r
5870 \r
5871         if (this.settings['height'] == -1)\r
5872                 this.settings['height'] = replace_element.offsetHeight;\r
5873 \r
5874         // Try the style width\r
5875         if (this.settings['width'] == 0)\r
5876                 this.settings['width'] = replace_element.style.width;\r
5877 \r
5878         // Try the style height\r
5879         if (this.settings['height'] == 0)\r
5880                 this.settings['height'] = replace_element.style.height; \r
5881 \r
5882         // If no width/height then default to 320x240, better than nothing\r
5883         if (this.settings['width'] == 0)\r
5884                 this.settings['width'] = 320;\r
5885 \r
5886         if (this.settings['height'] == 0)\r
5887                 this.settings['height'] = 240;\r
5888 \r
5889         this.settings['area_width'] = parseInt(this.settings['width']);\r
5890         this.settings['area_height'] = parseInt(this.settings['height']);\r
5891         this.settings['area_width'] += deltaWidth;\r
5892         this.settings['area_height'] += deltaHeight;\r
5893 \r
5894         // Special % handling\r
5895         if (("" + this.settings['width']).indexOf('%') != -1)\r
5896                 this.settings['area_width'] = "100%";\r
5897 \r
5898         if (("" + this.settings['height']).indexOf('%') != -1)\r
5899                 this.settings['area_height'] = "100%";\r
5900 \r
5901         if (("" + replace_element.style.width).indexOf('%') != -1) {\r
5902                 this.settings['width'] = replace_element.style.width;\r
5903                 this.settings['area_width'] = "100%";\r
5904         }\r
5905 \r
5906         if (("" + replace_element.style.height).indexOf('%') != -1) {\r
5907                 this.settings['height'] = replace_element.style.height;\r
5908                 this.settings['area_height'] = "100%";\r
5909         }\r
5910 \r
5911         html = tinyMCE.applyTemplate(html);\r
5912 \r
5913         this.settings['width'] = this.settings['old_width'];\r
5914         this.settings['height'] = this.settings['old_height'];\r
5915 \r
5916         this.visualAid = this.settings['visual'];\r
5917         this.formTargetElementId = form_element_name;\r
5918 \r
5919         // Get replace_element contents\r
5920         if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")\r
5921                 this.startContent = replace_element.value;\r
5922         else\r
5923                 this.startContent = replace_element.innerHTML;\r
5924 \r
5925         // If not text area\r
5926         if (replace_element.nodeName.toLowerCase() != "textarea") {\r
5927                 this.oldTargetElement = replace_element.cloneNode(true);\r
5928 \r
5929                 // Debug mode\r
5930                 if (tinyMCE.settings['debug'])\r
5931                         html += '<textarea wrap="off" id="' + form_element_name + '" name="' + form_element_name + '" cols="100" rows="15"></textarea>';\r
5932                 else\r
5933                         html += '<input type="hidden" type="text" id="' + form_element_name + '" name="' + form_element_name + '" />';\r
5934 \r
5935                 html += '</span>';\r
5936 \r
5937                 // Output HTML and set editable\r
5938                 if (!tinyMCE.isMSIE) {\r
5939                         var rng = replace_element.ownerDocument.createRange();\r
5940                         rng.setStartBefore(replace_element);\r
5941 \r
5942                         var fragment = rng.createContextualFragment(html);\r
5943                         replace_element.parentNode.replaceChild(fragment, replace_element);\r
5944                 } else\r
5945                         replace_element.outerHTML = html;\r
5946         } else {\r
5947                 html += '</span>';\r
5948 \r
5949                 // Just hide the textarea element\r
5950                 this.oldTargetElement = replace_element;\r
5951 \r
5952                 if (!tinyMCE.settings['debug'])\r
5953                         this.oldTargetElement.style.display = "none";\r
5954 \r
5955                 // Output HTML and set editable\r
5956                 if (!tinyMCE.isMSIE) {\r
5957                         var rng = replace_element.ownerDocument.createRange();\r
5958                         rng.setStartBefore(replace_element);\r
5959 \r
5960                         var fragment = rng.createContextualFragment(html);\r
5961 \r
5962                         if (tinyMCE.isGecko)\r
5963                                 tinyMCE.insertAfter(fragment, replace_element);\r
5964                         else\r
5965                                 replace_element.parentNode.insertBefore(fragment, replace_element);\r
5966                 } else\r
5967                         replace_element.insertAdjacentHTML("beforeBegin", html);\r
5968         }\r
5969 \r
5970         // Setup iframe\r
5971         var dynamicIFrame = false;\r
5972         var tElm = targetDoc.getElementById(this.editorId);\r
5973 \r
5974         if (!tinyMCE.isMSIE) {\r
5975                 if (tElm && tElm.nodeName.toLowerCase() == "span") {\r
5976                         tElm = tinyMCE._createIFrame(tElm);\r
5977                         dynamicIFrame = true;\r
5978                 }\r
5979 \r
5980                 this.targetElement = tElm;\r
5981                 this.iframeElement = tElm;\r
5982                 this.contentDocument = tElm.contentDocument;\r
5983                 this.contentWindow = tElm.contentWindow;\r
5984 \r
5985                 //this.getDoc().designMode = "on";\r
5986         } else {\r
5987                 if (tElm && tElm.nodeName.toLowerCase() == "span")\r
5988                         tElm = tinyMCE._createIFrame(tElm);\r
5989                 else\r
5990                         tElm = targetDoc.frames[this.editorId];\r
5991 \r
5992                 this.targetElement = tElm;\r
5993                 this.iframeElement = targetDoc.getElementById(this.editorId);\r
5994 \r
5995                 if (tinyMCE.isOpera) {\r
5996                         this.contentDocument = this.iframeElement.contentDocument;\r
5997                         this.contentWindow = this.iframeElement.contentWindow;\r
5998                         dynamicIFrame = true;\r
5999                 } else {\r
6000                         this.contentDocument = tElm.window.document;\r
6001                         this.contentWindow = tElm.window;\r
6002                 }\r
6003 \r
6004                 this.getDoc().designMode = "on";\r
6005         }\r
6006 \r
6007         // Setup base HTML\r
6008         var doc = this.contentDocument;\r
6009         if (dynamicIFrame) {\r
6010                 var html = tinyMCE.getParam('doctype') + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + tinyMCE.settings['base_href'] + '" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';\r
6011 \r
6012                 try {\r
6013                         if (!this.isHidden())\r
6014                                 this.getDoc().designMode = "on";\r
6015 \r
6016                         doc.open();\r
6017                         doc.write(html);\r
6018                         doc.close();\r
6019                 } catch (e) {\r
6020                         // Failed Mozilla 1.3\r
6021                         this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";\r
6022                 }\r
6023         }\r
6024 \r
6025         // This timeout is needed in MSIE 5.5 for some odd reason\r
6026         // it seems that the document.frames isn't initialized yet?\r
6027         if (tinyMCE.isMSIE)\r
6028                 window.setTimeout("TinyMCE.prototype.addEventHandlers('" + this.editorId + "');", 1);\r
6029 \r
6030         tinyMCE.setupContent(this.editorId, true);\r
6031 \r
6032         return true;\r
6033 };\r
6034 \r
6035 TinyMCEControl.prototype.getFocusElement = function() {\r
6036         if (tinyMCE.isMSIE && !tinyMCE.isOpera) {\r
6037                 var doc = this.getDoc();\r
6038                 var rng = doc.selection.createRange();\r
6039 \r
6040 //              if (rng.collapse)\r
6041 //                      rng.collapse(true);\r
6042 \r
6043                 var elm = rng.item ? rng.item(0) : rng.parentElement();\r
6044         } else {\r
6045                 if (this.isHidden())\r
6046                         return this.getBody();\r
6047 \r
6048                 var sel = this.getSel();\r
6049                 var rng = this.getRng();\r
6050 \r
6051                 var elm = rng.commonAncestorContainer;\r
6052                 //var elm = (sel && sel.anchorNode) ? sel.anchorNode : null;\r
6053 \r
6054                 // Handle selection a image or other control like element such as anchors\r
6055                 if (!rng.collapsed) {\r
6056                         // Is selection small\r
6057                         if (rng.startContainer == rng.endContainer) {\r
6058                                 if (rng.startOffset - rng.endOffset < 2) {\r
6059                                         if (rng.startContainer.hasChildNodes())\r
6060                                                 elm = rng.startContainer.childNodes[rng.startOffset];\r
6061                                 }\r
6062                         }\r
6063                 }\r
6064 \r
6065                 // Get the element parent of the node\r
6066                 elm = tinyMCE.getParentElement(elm);\r
6067 \r
6068                 //if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")\r
6069                 //      elm = tinyMCE.selectedElement;\r
6070         }\r
6071 \r
6072         return elm;\r
6073 };\r
6074 \r
6075 // Global instances\r
6076 var tinyMCE = new TinyMCE();\r
6077 var tinyMCELang = new Array();\r