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