2 * $RCSfile: tiny_mce_src.js,v $
\r
4 * $Date: 2005/12/02 08:12:07 $
\r
7 * @copyright Copyright © 2004, Moxiecode Systems AB, All rights reserved.
\r
10 function TinyMCE() {
\r
11 this.majorVersion = "2";
\r
12 this.minorVersion = "0";
\r
13 this.releaseDate = "2005-12-01";
\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
24 var ua = navigator.userAgent;
\r
25 this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
\r
26 this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);
\r
27 this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);
\r
28 this.isGecko = ua.indexOf('Gecko') != -1;
\r
29 this.isSafari = ua.indexOf('Safari') != -1;
\r
30 this.isOpera = ua.indexOf('Opera') != -1;
\r
31 this.isMac = ua.indexOf('Mac') != -1;
\r
32 this.isNS7 = ua.indexOf('Netscape/7') != -1;
\r
33 this.isNS71 = ua.indexOf('Netscape/7.1') != -1;
\r
34 this.dialogCounter = 0;
\r
36 // Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those
\r
39 this.isGecko = false;
\r
40 this.isSafari = false;
\r
43 // TinyMCE editor id instance counter
\r
47 TinyMCE.prototype.defParam = function(key, def_val) {
\r
48 this.settings[key] = tinyMCE.getParam(key, def_val);
\r
51 TinyMCE.prototype.init = function(settings) {
\r
54 this.settings = settings;
\r
56 // Check if valid browser has execcommand support
\r
57 if (typeof(document.execCommand) == 'undefined')
\r
60 // Get script base path
\r
61 if (!tinyMCE.baseURL) {
\r
62 var elements = document.getElementsByTagName('script');
\r
64 for (var i=0; i<elements.length; i++) {
\r
65 if (elements[i].src && (elements[i].src.indexOf("tiny_mce.js") != -1 || elements[i].src.indexOf("tiny_mce_src.js") != -1 || elements[i].src.indexOf("tiny_mce_gzip") != -1)) {
\r
66 var src = elements[i].src;
\r
68 tinyMCE.srcMode = (src.indexOf('_src') != -1) ? '_src' : '';
\r
69 src = src.substring(0, src.lastIndexOf('/'));
\r
71 tinyMCE.baseURL = src;
\r
77 // Get document base path
\r
78 this.documentBasePath = document.location.href;
\r
79 if (this.documentBasePath.indexOf('?') != -1)
\r
80 this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));
\r
81 this.documentURL = this.documentBasePath;
\r
82 this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));
\r
84 // If not HTTP absolute
\r
85 if (tinyMCE.baseURL.indexOf('://') == -1 && tinyMCE.baseURL.charAt(0) != '/') {
\r
87 tinyMCE.baseURL = this.documentBasePath + "/" + tinyMCE.baseURL;
\r
90 // Set default values on settings
\r
91 this.defParam("mode", "none");
\r
92 this.defParam("theme", "advanced");
\r
93 this.defParam("plugins", "", true);
\r
94 this.defParam("language", "en");
\r
95 this.defParam("docs_language", this.settings['language']);
\r
96 this.defParam("elements", "");
\r
97 this.defParam("textarea_trigger", "mce_editable");
\r
98 this.defParam("editor_selector", "");
\r
99 this.defParam("editor_deselector", "mceNoEditor");
\r
100 this.defParam("valid_elements", "+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/b[class|style],-em/i[class|style],-strike[class|style],-u[class|style],+p[style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border=0|alt|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],-td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[style|dir|class|align],-h2[style|dir|class|align],-h3[style|dir|class|align],-h4[style|dir|class|align],-h5[style|dir|class|align],-h6[style|dir|class|align],hr[class|style],font[face|size|style|id|class|dir|color]");
\r
101 this.defParam("extended_valid_elements", "");
\r
102 this.defParam("invalid_elements", "");
\r
103 this.defParam("encoding", "");
\r
104 this.defParam("urlconverter_callback", tinyMCE.getParam("urlconvertor_callback", "TinyMCE.prototype.convertURL"));
\r
105 this.defParam("save_callback", "");
\r
106 this.defParam("debug", false);
\r
107 this.defParam("force_br_newlines", false);
\r
108 this.defParam("force_p_newlines", true);
\r
109 this.defParam("add_form_submit_trigger", true);
\r
110 this.defParam("relative_urls", true);
\r
111 this.defParam("remove_script_host", true);
\r
112 this.defParam("focus_alert", true);
\r
113 this.defParam("document_base_url", this.documentURL);
\r
114 this.defParam("visual", true);
\r
115 this.defParam("visual_table_class", "mceVisualAid");
\r
116 this.defParam("setupcontent_callback", "");
\r
117 this.defParam("fix_content_duplication", true);
\r
118 this.defParam("custom_undo_redo", true);
\r
119 this.defParam("custom_undo_redo_levels", -1);
\r
120 this.defParam("custom_undo_redo_keyboard_shortcuts", true);
\r
121 this.defParam("verify_css_classes", false);
\r
122 this.defParam("verify_html", true);
\r
123 this.defParam("apply_source_formatting", false);
\r
124 this.defParam("directionality", "ltr");
\r
125 this.defParam("cleanup_on_startup", false);
\r
126 this.defParam("inline_styles", false);
\r
127 this.defParam("convert_newlines_to_brs", false);
\r
128 this.defParam("auto_reset_designmode", true);
\r
129 this.defParam("entities", "160,nbsp,38,amp,34,quot,162,cent,8364,euro,163,pound,165,yen,169,copy,174,reg,8482,trade,8240,permil,181,micro,183,middot,8226,bull,8230,hellip,8242,prime,8243,Prime,167,sect,182,para,223,szlig,8249,lsaquo,8250,rsaquo,171,laquo,187,raquo,8216,lsquo,8217,rsquo,8220,ldquo,8221,rdquo,8218,sbquo,8222,bdquo,60,lt,62,gt,8804,le,8805,ge,8211,ndash,8212,mdash,175,macr,8254,oline,164,curren,166,brvbar,168,uml,161,iexcl,191,iquest,710,circ,732,tilde,176,deg,8722,minus,177,plusmn,247,divide,8260,frasl,215,times,185,sup1,178,sup2,179,sup3,188,frac14,189,frac12,190,frac34,402,fnof,8747,int,8721,sum,8734,infin,8730,radic,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8712,isin,8713,notin,8715,ni,8719,prod,8743,and,8744,or,172,not,8745,cap,8746,cup,8706,part,8704,forall,8707,exist,8709,empty,8711,nabla,8727,lowast,8733,prop,8736,ang,180,acute,184,cedil,170,ordf,186,ordm,8224,dagger,8225,Dagger,192,Agrave,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,202,Ecirc,203,Euml,204,Igrave,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,212,Ocirc,213,Otilde,214,Ouml,216,Oslash,338,OElig,217,Ugrave,219,Ucirc,220,Uuml,376,Yuml,222,THORN,224,agrave,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,234,ecirc,235,euml,236,igrave,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,244,ocirc,245,otilde,246,ouml,248,oslash,339,oelig,249,ugrave,251,ucirc,252,uuml,254,thorn,255,yuml,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,8501,alefsym,982,piv,8476,real,977,thetasym,978,upsih,8472,weierp,8465,image,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8756,there4,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,173,shy,233,eacute,237,iacute,243,oacute,250,uacute,193,Aacute,225,aacute,201,Eacute,205,Iacute,211,Oacute,218,Uacute,221,Yacute,253,yacute");
\r
130 this.defParam("entity_encoding", "named");
\r
131 this.defParam("cleanup_callback", "");
\r
132 this.defParam("add_unload_trigger", true);
\r
133 this.defParam("ask", false);
\r
134 this.defParam("nowrap", false);
\r
135 this.defParam("auto_resize", false);
\r
136 this.defParam("auto_focus", false);
\r
137 this.defParam("cleanup", true);
\r
138 this.defParam("remove_linebreaks", true);
\r
139 this.defParam("button_tile_map", false);
\r
140 this.defParam("submit_patch", true);
\r
141 this.defParam("browsers", "msie,safari,gecko,opera");
\r
142 this.defParam("dialog_type", "window");
\r
143 this.defParam("accessibility_warnings", true);
\r
144 this.defParam("merge_styles_invalid_parents", "");
\r
145 this.defParam("force_hex_style_colors", true);
\r
146 this.defParam("trim_span_elements", true);
\r
147 this.defParam("convert_fonts_to_spans", false);
\r
148 this.defParam("doctype", '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');
\r
149 this.defParam("font_size_classes", '');
\r
150 this.defParam("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large');
\r
151 this.defParam("event_elements", 'a,img');
\r
152 this.defParam("convert_urls", true);
\r
153 this.defParam("table_inline_editing", false);
\r
154 this.defParam("object_resizing", true);
\r
156 // Browser check IE
\r
157 if (this.isMSIE && this.settings['browsers'].indexOf('msie') == -1)
\r
160 // Browser check Gecko
\r
161 if (this.isGecko && this.settings['browsers'].indexOf('gecko') == -1)
\r
164 // Browser check Safari
\r
165 if (this.isSafari && this.settings['browsers'].indexOf('safari') == -1)
\r
168 // Browser check Opera
\r
169 if (this.isOpera && this.settings['browsers'].indexOf('opera') == -1)
\r
172 // If not super absolute make it so
\r
173 var baseHREF = tinyMCE.settings['document_base_url'];
\r
174 var h = document.location.href;
\r
175 var p = h.indexOf('://');
\r
176 if (p > 0 && document.location.protocol != "file:") {
\r
177 p = h.indexOf('/', p + 3);
\r
178 h = h.substring(0, p);
\r
180 if (baseHREF.indexOf('://') == -1)
\r
181 baseHREF = h + baseHREF;
\r
183 tinyMCE.settings['document_base_url'] = baseHREF;
\r
184 tinyMCE.settings['document_base_prefix'] = h;
\r
187 // Trim away query part
\r
188 if (baseHREF.indexOf('?') != -1)
\r
189 baseHREF = baseHREF.substring(0, baseHREF.indexOf('?'));
\r
191 this.settings['base_href'] = baseHREF.substring(0, baseHREF.lastIndexOf('/')) + "/";
\r
193 theme = this.settings['theme'];
\r
194 this.blockRegExp = new RegExp("^(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|blockquote|center|dl|dir|fieldset|form|noscript|noframes|menu|isindex)$", "i");
\r
195 this.posKeyCodes = new Array(13,45,36,35,33,34,37,38,39,40);
\r
196 this.uniqueURL = 'http://tinymce.moxiecode.cp/mce_temp_url'; // Make unique URL non real URL
\r
197 this.uniqueTag = '<div id="mceTMPElement" style="display: none">TMP</div>';
\r
200 this.settings['theme_href'] = tinyMCE.baseURL + "/themes/" + theme;
\r
202 if (!tinyMCE.isMSIE)
\r
203 this.settings['force_br_newlines'] = false;
\r
205 if (tinyMCE.getParam("content_css", false)) {
\r
206 var cssPath = tinyMCE.getParam("content_css", "");
\r
209 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
\r
210 this.settings['content_css'] = this.documentBasePath + "/" + cssPath;
\r
212 this.settings['content_css'] = cssPath;
\r
214 this.settings['content_css'] = '';
\r
216 if (tinyMCE.getParam("popups_css", false)) {
\r
217 var cssPath = tinyMCE.getParam("popups_css", "");
\r
220 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
\r
221 this.settings['popups_css'] = this.documentBasePath + "/" + cssPath;
\r
223 this.settings['popups_css'] = cssPath;
\r
225 this.settings['popups_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css";
\r
227 if (tinyMCE.getParam("editor_css", false)) {
\r
228 var cssPath = tinyMCE.getParam("editor_css", "");
\r
231 if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
\r
232 this.settings['editor_css'] = this.documentBasePath + "/" + cssPath;
\r
234 this.settings['editor_css'] = cssPath;
\r
236 this.settings['editor_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css";
\r
238 if (tinyMCE.settings['debug']) {
\r
239 var msg = "Debug: \n";
\r
241 msg += "baseURL: " + this.baseURL + "\n";
\r
242 msg += "documentBasePath: " + this.documentBasePath + "\n";
\r
243 msg += "content_css: " + this.settings['content_css'] + "\n";
\r
244 msg += "popups_css: " + this.settings['popups_css'] + "\n";
\r
245 msg += "editor_css: " + this.settings['editor_css'] + "\n";
\r
250 // Init HTML cleanup
\r
251 this._initCleanup();
\r
253 // Only do this once
\r
254 if (this.configs.length == 0) {
\r
255 // Is Safari enabled
\r
256 if (this.isSafari && this.getParam('safari_warning', true))
\r
257 alert("Safari support is very limited and should be considered experimental.\nSo there is no need to even submit bugreports on this early version.\nYou can disable this message by setting: safari_warning option to false");
\r
259 tinyMCE.addEvent(window, "load", TinyMCE.prototype.onLoad);
\r
261 if (tinyMCE.isMSIE) {
\r
262 if (tinyMCE.settings['add_unload_trigger']) {
\r
263 tinyMCE.addEvent(window, "unload", TinyMCE.prototype.unloadHandler);
\r
264 tinyMCE.addEvent(window.document, "beforeunload", TinyMCE.prototype.unloadHandler);
\r
267 if (tinyMCE.settings['add_unload_trigger'])
\r
268 tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);});
\r
272 this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings['theme'] + '/editor_template' + tinyMCE.srcMode + '.js');
\r
273 this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings['language'] + '.js');
\r
274 this.loadCSS(this.settings['editor_css']);
\r
277 var themePlugins = tinyMCE.getParam('plugins', '', true, ',');
\r
278 if (this.settings['plugins'] != '') {
\r
279 for (var i=0; i<themePlugins.length; i++)
\r
280 this.loadScript(tinyMCE.baseURL + '/plugins/' + themePlugins[i] + '/editor_plugin' + tinyMCE.srcMode + '.js');
\r
284 settings['cleanup_entities'] = new Array();
\r
285 var entities = tinyMCE.getParam('entities', '', true, ',');
\r
286 for (var i=0; i<entities.length; i+=2)
\r
287 settings['cleanup_entities']['c' + entities[i]] = entities[i+1];
\r
289 // Save away this config
\r
290 settings['index'] = this.configs.length;
\r
291 this.configs[this.configs.length] = settings;
\r
294 TinyMCE.prototype.loadScript = function(url) {
\r
295 for (var i=0; i<this.loadedFiles.length; i++) {
\r
296 if (this.loadedFiles[i] == url)
\r
300 document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></script>');
\r
302 this.loadedFiles[this.loadedFiles.length] = url;
\r
305 TinyMCE.prototype.loadCSS = function(url) {
\r
306 for (var i=0; i<this.loadedFiles.length; i++) {
\r
307 if (this.loadedFiles[i] == url)
\r
311 document.write('<link href="' + url + '" rel="stylesheet" type="text/css" />');
\r
313 this.loadedFiles[this.loadedFiles.length] = url;
\r
316 TinyMCE.prototype.importCSS = function(doc, css_file) {
\r
317 if (css_file == '')
\r
320 if (typeof(doc.createStyleSheet) == "undefined") {
\r
321 var elm = doc.createElement("link");
\r
323 elm.rel = "stylesheet";
\r
324 elm.href = css_file;
\r
326 if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0)
\r
327 headArr[0].appendChild(elm);
\r
329 var styleSheet = doc.createStyleSheet(css_file);
\r
332 TinyMCE.prototype.confirmAdd = function(e, settings) {
\r
333 var elm = tinyMCE.isMSIE ? event.srcElement : e.target;
\r
334 var elementId = elm.name ? elm.name : elm.id;
\r
336 tinyMCE.settings = settings;
\r
338 if (!elm.getAttribute('mce_noask') && confirm(tinyMCELang['lang_edit_confirm']))
\r
339 tinyMCE.addMCEControl(elm, elementId);
\r
341 elm.setAttribute('mce_noask', 'true');
\r
344 TinyMCE.prototype.updateContent = function(form_element_name) {
\r
345 // Find MCE instance linked to given form element and copy it's value
\r
346 var formElement = document.getElementById(form_element_name);
\r
347 for (var n in tinyMCE.instances) {
\r
348 var inst = tinyMCE.instances[n];
\r
349 if (!tinyMCE.isInstance(inst))
\r
352 inst.switchSettings();
\r
354 if (inst.formElement == formElement) {
\r
355 var doc = inst.getDoc();
\r
357 tinyMCE._setHTML(doc, inst.formElement.value);
\r
359 if (!tinyMCE.isMSIE)
\r
360 doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);
\r
365 TinyMCE.prototype.addMCEControl = function(replace_element, form_element_name, target_document) {
\r
366 var id = "mce_editor_" + tinyMCE.idCounter++;
\r
367 var inst = new TinyMCEControl(tinyMCE.settings);
\r
369 inst.editorId = id;
\r
370 this.instances[id] = inst;
\r
372 inst.onAdd(replace_element, form_element_name, target_document);
\r
375 TinyMCE.prototype.triggerSave = function(skip_cleanup, skip_callback) {
\r
376 // Cleanup and set all form fields
\r
377 for (var n in tinyMCE.instances) {
\r
378 var inst = tinyMCE.instances[n];
\r
379 if (!tinyMCE.isInstance(inst))
\r
382 inst.switchSettings();
\r
384 tinyMCE.settings['preformatted'] = false;
\r
386 // Default to false
\r
387 if (typeof(skip_cleanup) == "undefined")
\r
388 skip_cleanup = false;
\r
390 // Default to false
\r
391 if (typeof(skip_callback) == "undefined")
\r
392 skip_callback = false;
\r
394 tinyMCE._setHTML(inst.getDoc(), inst.getBody().innerHTML);
\r
396 // Remove visual aids when cleanup is disabled
\r
397 if (inst.settings['cleanup'] == false) {
\r
398 tinyMCE.handleVisualAid(inst.getBody(), true, false, inst);
\r
399 tinyMCE._setEventsEnabled(inst.getBody(), true);
\r
402 tinyMCE._customCleanup(inst, "submit_content_dom", inst.contentWindow.document.body);
\r
403 var htm = skip_cleanup ? inst.getBody().innerHTML : tinyMCE._cleanupHTML(inst, inst.getDoc(), this.settings, inst.getBody(), this.visualAid, true);
\r
404 htm = tinyMCE._customCleanup(inst, "submit_content", htm);
\r
406 if (tinyMCE.settings["encoding"] == "xml" || tinyMCE.settings["encoding"] == "html")
\r
407 htm = tinyMCE.convertStringToXML(htm);
\r
409 if (!skip_callback && tinyMCE.settings['save_callback'] != "")
\r
410 var content = eval(tinyMCE.settings['save_callback'] + "(inst.formTargetElementId,htm,inst.getBody());");
\r
412 // Use callback content if available
\r
413 if ((typeof(content) != "undefined") && content != null)
\r
416 // Replace some weird entities (Bug: #1056343)
\r
417 htm = tinyMCE.regexpReplace(htm, "(", "(", "gi");
\r
418 htm = tinyMCE.regexpReplace(htm, ")", ")", "gi");
\r
419 htm = tinyMCE.regexpReplace(htm, ";", ";", "gi");
\r
420 htm = tinyMCE.regexpReplace(htm, """, """, "gi");
\r
421 htm = tinyMCE.regexpReplace(htm, "^", "^", "gi");
\r
423 if (inst.formElement)
\r
424 inst.formElement.value = htm;
\r
428 TinyMCE.prototype._setEventsEnabled = function(node, state) {
\r
429 var events = new Array('onfocus','onblur','onclick','ondblclick',
\r
430 'onmousedown','onmouseup','onmouseover','onmousemove',
\r
431 'onmouseout','onkeypress','onkeydown','onkeydown','onkeyup');
\r
433 var evs = tinyMCE.settings['event_elements'].split(',');
\r
434 for (var y=0; y<evs.length; y++){
\r
435 var elms = node.getElementsByTagName(evs[y]);
\r
436 for (var i=0; i<elms.length; i++) {
\r
439 for (var x=0; x<events.length; x++) {
\r
440 if ((event = tinyMCE.getAttrib(elms[i], events[x])) != '') {
\r
441 event = tinyMCE.cleanupEventStr("" + event);
\r
444 event = "return true;" + event;
\r
446 event = event.replace(/^return true;/gi, '');
\r
448 elms[i].removeAttribute(events[x]);
\r
449 elms[i].setAttribute(events[x], event);
\r
456 TinyMCE.prototype.resetForm = function(form_index) {
\r
457 var formObj = document.forms[form_index];
\r
459 for (var n in tinyMCE.instances) {
\r
460 var inst = tinyMCE.instances[n];
\r
461 if (!tinyMCE.isInstance(inst))
\r
464 inst.switchSettings();
\r
466 for (var i=0; i<formObj.elements.length; i++) {
\r
467 if (inst.formTargetElementId == formObj.elements[i].name)
\r
468 inst.getBody().innerHTML = inst.startContent;
\r
473 TinyMCE.prototype.execInstanceCommand = function(editor_id, command, user_interface, value, focus) {
\r
474 var inst = tinyMCE.getInstanceById(editor_id);
\r
476 if (typeof(focus) == "undefined")
\r
480 inst.contentWindow.focus();
\r
482 // Reset design mode if lost
\r
483 inst.autoResetDesignMode();
\r
485 this.selectedElement = inst.getFocusElement();
\r
486 this.selectedInstance = inst;
\r
487 tinyMCE.execCommand(command, user_interface, value);
\r
489 // Cancel event so it doesn't call onbeforeonunlaod
\r
490 if (tinyMCE.isMSIE && window.event != null)
\r
491 tinyMCE.cancelEvent(window.event);
\r
495 TinyMCE.prototype.execCommand = function(command, user_interface, value) {
\r
497 user_interface = user_interface ? user_interface : false;
\r
498 value = value ? value : null;
\r
500 if (tinyMCE.selectedInstance)
\r
501 tinyMCE.selectedInstance.switchSettings();
\r
505 var template = new Array();
\r
507 template['file'] = 'about.htm';
\r
508 template['width'] = 480;
\r
509 template['height'] = 380;
\r
511 tinyMCE.openWindow(template, {
\r
512 tinymce_version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion,
\r
513 tinymce_releasedate : tinyMCE.releaseDate,
\r
519 var inst = tinyMCE.getInstanceById(value);
\r
521 inst.contentWindow.focus();
\r
524 case "mceAddControl":
\r
525 case "mceAddEditor":
\r
526 tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
\r
529 case "mceAddFrameControl":
\r
530 tinyMCE.addMCEControl(tinyMCE._getElementById(value), value['element'], value['document']);
\r
533 case "mceRemoveControl":
\r
534 case "mceRemoveEditor":
\r
535 tinyMCE.removeMCEControl(value);
\r
538 case "mceResetDesignMode":
\r
539 // Resets the designmode state of the editors in Gecko
\r
540 if (!tinyMCE.isMSIE) {
\r
541 for (var n in tinyMCE.instances) {
\r
542 if (!tinyMCE.isInstance(tinyMCE.instances[n]))
\r
546 tinyMCE.instances[n].getDoc().designMode = "on";
\r
548 // Ignore any errors
\r
556 if (this.selectedInstance) {
\r
557 this.selectedInstance.execCommand(command, user_interface, value);
\r
558 } else if (tinyMCE.settings['focus_alert'])
\r
559 alert(tinyMCELang['lang_focus_alert']);
\r
562 TinyMCE.prototype.eventPatch = function(editor_id) {
\r
563 // Remove odd, error
\r
564 if (typeof(tinyMCE) == "undefined")
\r
567 for (var i=0; i<document.frames.length; i++) {
\r
569 if (document.frames[i].event) {
\r
570 var event = document.frames[i].event;
\r
573 event.target = event.srcElement;
\r
575 TinyMCE.prototype.handleEvent(event);
\r
579 // Ignore error if iframe is pointing to external URL
\r
584 TinyMCE.prototype.unloadHandler = function() {
\r
585 tinyMCE.triggerSave(true, true);
\r
588 TinyMCE.prototype.addEventHandlers = function(editor_id) {
\r
589 if (tinyMCE.isMSIE) {
\r
590 var doc = document.frames[editor_id].document;
\r
593 tinyMCE.addEvent(doc, "keypress", TinyMCE.prototype.eventPatch);
\r
594 tinyMCE.addEvent(doc, "keyup", TinyMCE.prototype.eventPatch);
\r
595 tinyMCE.addEvent(doc, "keydown", TinyMCE.prototype.eventPatch);
\r
596 tinyMCE.addEvent(doc, "mouseup", TinyMCE.prototype.eventPatch);
\r
597 tinyMCE.addEvent(doc, "click", TinyMCE.prototype.eventPatch);
\r
599 var inst = tinyMCE.instances[editor_id];
\r
600 var doc = inst.getDoc();
\r
602 inst.switchSettings();
\r
604 tinyMCE.addEvent(doc, "keypress", tinyMCE.handleEvent);
\r
605 tinyMCE.addEvent(doc, "keydown", tinyMCE.handleEvent);
\r
606 tinyMCE.addEvent(doc, "keyup", tinyMCE.handleEvent);
\r
607 tinyMCE.addEvent(doc, "click", tinyMCE.handleEvent);
\r
608 tinyMCE.addEvent(doc, "mouseup", tinyMCE.handleEvent);
\r
609 tinyMCE.addEvent(doc, "mousedown", tinyMCE.handleEvent);
\r
610 tinyMCE.addEvent(doc, "focus", tinyMCE.handleEvent);
\r
611 tinyMCE.addEvent(doc, "blur", tinyMCE.handleEvent);
\r
613 eval('try { doc.designMode = "On"; } catch(e) {}');
\r
617 TinyMCE.prototype._createIFrame = function(replace_element) {
\r
618 var iframe = document.createElement("iframe");
\r
619 var id = replace_element.getAttribute("id");
\r
622 aw = "" + tinyMCE.settings['area_width'];
\r
623 ah = "" + tinyMCE.settings['area_height'];
\r
625 if (aw.indexOf('%') == -1) {
\r
627 aw = aw < 0 ? 300 : aw;
\r
631 if (ah.indexOf('%') == -1) {
\r
633 ah = ah < 0 ? 240 : ah;
\r
637 iframe.setAttribute("id", id);
\r
638 //iframe.setAttribute("className", "mceEditorArea");
\r
639 iframe.setAttribute("border", "0");
\r
640 iframe.setAttribute("frameBorder", "0");
\r
641 iframe.setAttribute("marginWidth", "0");
\r
642 iframe.setAttribute("marginHeight", "0");
\r
643 iframe.setAttribute("leftMargin", "0");
\r
644 iframe.setAttribute("topMargin", "0");
\r
645 iframe.setAttribute("width", aw);
\r
646 iframe.setAttribute("height", ah);
\r
647 iframe.setAttribute("allowtransparency", "true");
\r
649 if (tinyMCE.settings["auto_resize"])
\r
650 iframe.setAttribute("scrolling", "no");
\r
652 // Must have a src element in MSIE HTTPs breaks aswell as absoute URLs
\r
653 if (tinyMCE.isMSIE && !tinyMCE.isOpera)
\r
654 iframe.setAttribute("src", this.settings['default_document']);
\r
656 iframe.style.width = aw;
\r
657 iframe.style.height = ah;
\r
660 if (tinyMCE.isMSIE && !tinyMCE.isOpera)
\r
661 replace_element.outerHTML = iframe.outerHTML;
\r
663 replace_element.parentNode.replaceChild(iframe, replace_element);
\r
665 if (tinyMCE.isMSIE)
\r
666 return window.frames[id];
\r
671 TinyMCE.prototype.setupContent = function(editor_id) {
\r
672 var inst = tinyMCE.instances[editor_id];
\r
673 var doc = inst.getDoc();
\r
674 var head = doc.getElementsByTagName('head').item(0);
\r
675 var content = inst.startContent;
\r
677 tinyMCE.operaOpacityCounter = 100 * tinyMCE.idCounter;
\r
679 inst.switchSettings();
\r
681 // Not loaded correctly hit it again, Mozilla bug #997860
\r
682 if (!tinyMCE.isMSIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") {
\r
683 // This part will remove the designMode status
\r
684 // Failes first time in Firefox 1.5b2 on Mac
\r
685 try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {}
\r
686 window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000);
\r
691 window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10);
\r
695 // Import theme specific content CSS the user specific
\r
696 tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings['theme'] + "/css/editor_content.css");
\r
697 tinyMCE.importCSS(inst.getDoc(), inst.settings['content_css']);
\r
698 tinyMCE.executeCallback('init_instance_callback', '_initInstance', 0, inst);
\r
700 // Setup span styles
\r
701 if (tinyMCE.getParam("convert_fonts_to_spans"))
\r
702 inst.getDoc().body.setAttribute('id', 'mceSpanFonts');
\r
704 if (tinyMCE.settings['nowrap'])
\r
705 doc.body.style.whiteSpace = "nowrap";
\r
707 doc.body.dir = this.settings['directionality'];
\r
708 doc.editorId = editor_id;
\r
710 // Add on document element in Mozilla
\r
711 if (!tinyMCE.isMSIE)
\r
712 doc.documentElement.editorId = editor_id;
\r
714 // Setup base element
\r
715 var base = doc.createElement("base");
\r
716 base.setAttribute('href', tinyMCE.settings['base_href']);
\r
717 head.appendChild(base);
\r
719 // Replace new line characters to BRs
\r
720 if (tinyMCE.settings['convert_newlines_to_brs']) {
\r
721 content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi");
\r
722 content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi");
\r
723 content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi");
\r
726 // Open closed anchors
\r
727 // content = content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
\r
729 // Call custom cleanup code
\r
730 content = tinyMCE.storeAwayURLs(content);
\r
731 content = tinyMCE._customCleanup(inst, "insert_to_editor", content);
\r
733 if (tinyMCE.isMSIE) {
\r
735 window.setInterval('try{tinyMCE.getCSSClasses(document.frames["' + editor_id + '"].document, "' + editor_id + '");}catch(e){}', 500);
\r
737 if (tinyMCE.settings["force_br_newlines"])
\r
738 document.frames[editor_id].document.styleSheets[0].addRule("p", "margin: 0px;");
\r
740 var body = document.frames[editor_id].document.body;
\r
742 tinyMCE.addEvent(body, "beforepaste", TinyMCE.prototype.eventPatch);
\r
743 tinyMCE.addEvent(body, "beforecut", TinyMCE.prototype.eventPatch);
\r
745 body.editorId = editor_id;
\r
748 content = tinyMCE.cleanupHTMLCode(content);
\r
750 // Fix for bug #958637
\r
751 if (!tinyMCE.isMSIE) {
\r
752 var contentElement = inst.getDoc().createElement("body");
\r
753 var doc = inst.getDoc();
\r
755 contentElement.innerHTML = content;
\r
757 // Remove weridness!
\r
758 if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt'])
\r
759 content = content.replace(new RegExp('<>', 'g'), "");
\r
761 if (tinyMCE.settings['cleanup_on_startup'])
\r
762 tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement));
\r
764 // Convert all strong/em to b/i
\r
765 content = tinyMCE.regexpReplace(content, "<strong", "<b", "gi");
\r
766 content = tinyMCE.regexpReplace(content, "<em(/?)>", "<i$1>", "gi");
\r
767 content = tinyMCE.regexpReplace(content, "<em ", "<i ", "gi");
\r
768 content = tinyMCE.regexpReplace(content, "</strong>", "</b>", "gi");
\r
769 content = tinyMCE.regexpReplace(content, "</em>", "</i>", "gi");
\r
770 tinyMCE.setInnerHTML(inst.getBody(), content);
\r
773 inst.convertAllRelativeURLs();
\r
775 if (tinyMCE.settings['cleanup_on_startup']) {
\r
776 tinyMCE._setHTML(inst.getDoc(), content);
\r
778 // Produces permission denied error in MSIE 5.5
\r
779 eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}');
\r
781 tinyMCE._setHTML(inst.getDoc(), content);
\r
784 // Fix for bug #957681
\r
785 //inst.getDoc().designMode = inst.getDoc().designMode;
\r
787 // Setup element references
\r
788 var parentElm = document.getElementById(inst.editorId + '_parent');
\r
789 if (parentElm.lastChild.nodeName == "INPUT")
\r
790 inst.formElement = tinyMCE.isGecko ? parentElm.firstChild : parentElm.lastChild;
\r
792 inst.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;
\r
794 tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual'], inst);
\r
795 tinyMCE.executeCallback('setupcontent_callback', '_setupContent', 0, editor_id, inst.getBody(), inst.getDoc());
\r
797 // Re-add design mode on mozilla
\r
798 if (!tinyMCE.isMSIE)
\r
799 TinyMCE.prototype.addEventHandlers(editor_id);
\r
801 // Add blur handler
\r
802 if (tinyMCE.isMSIE)
\r
803 tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE.prototype.eventPatch);
\r
805 // Trigger node change, this call locks buttons for tables and so forth
\r
806 tinyMCE.selectedInstance = inst;
\r
807 tinyMCE.selectedElement = inst.contentWindow.document.body;
\r
809 if (!inst.isHidden())
\r
810 tinyMCE.triggerNodeChange(false, true);
\r
812 // Call custom DOM cleanup
\r
813 tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody());
\r
814 tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody());
\r
815 tinyMCE._setEventsEnabled(inst.getBody(), false);
\r
816 tinyMCE.cleanupAnchors(inst.getDoc());
\r
818 if (tinyMCE.getParam("convert_fonts_to_spans"))
\r
819 tinyMCE.convertSpansToFonts(inst.getDoc());
\r
821 inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
\r
822 inst.undoLevels[inst.undoLevels.length] = inst.startContent;
\r
824 tinyMCE.operaOpacityCounter = -1;
\r
827 TinyMCE.prototype.cleanupHTMLCode = function(s) {
\r
828 s = s.replace(/<p \/>/gi, '<p> </p>');
\r
829 s = s.replace(/<p>\s*<\/p>/gi, '<p> </p>');
\r
831 // Open closed tags like <b/> to <b></b>
\r
832 // tinyMCE.debug("f:" + s);
\r
833 s = s.replace(/<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\|>]*?)\/>/gi, '<$1$2$3></$1$2>');
\r
834 // tinyMCE.debug("e:" + s);
\r
836 // Remove trailing space <b > to <b>
\r
837 s = s.replace(new RegExp('\\s+></', 'gi'), '></');
\r
839 // Close tags <img></img> to <img/>
\r
840 s = s.replace(/<(img|br|hr)(.*?)><\/(img|br|hr)>/gi, '<$1$2 />');
\r
842 // Weird MSIE bug, <p><hr /></p> breaks runtime?
\r
843 if (tinyMCE.isMSIE)
\r
844 s = s.replace(/<p><hr \/><\/p>/gi, "<hr>");
\r
846 // Convert relative anchors to absolute URLs ex: #something to file.htm#something
\r
847 s = s.replace(new RegExp('(href=\"?)(\\s*?#)', 'gi'), '$1' + tinyMCE.settings['document_base_url'] + "#");
\r
852 TinyMCE.prototype.storeAwayURLs = function(s) {
\r
853 // Remove all mce_src, mce_href and replace them with new ones
\r
854 s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
\r
855 s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
\r
856 s = s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" mce_src="$1"');
\r
857 s = s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" mce_href="$1"');
\r
862 TinyMCE.prototype.cancelEvent = function(e) {
\r
863 if (tinyMCE.isMSIE) {
\r
864 e.returnValue = false;
\r
865 e.cancelBubble = true;
\r
867 e.preventDefault();
\r
870 TinyMCE.prototype.removeTinyMCEFormElements = function(form_obj) {
\r
871 // Check if form is valid
\r
872 if (typeof(form_obj) == "undefined" || form_obj == null)
\r
875 // If not a form, find the form
\r
876 if (form_obj.nodeName != "FORM") {
\r
878 form_obj = form_obj.form;
\r
880 form_obj = tinyMCE.getParentElement(form_obj, "form");
\r
884 if (form_obj == null)
\r
887 // Disable all UI form elements that TinyMCE created
\r
888 for (var i=0; i<form_obj.elements.length; i++) {
\r
889 var elementId = form_obj.elements[i].name ? form_obj.elements[i].name : form_obj.elements[i].id;
\r
891 if (elementId.indexOf('mce_editor_') == 0)
\r
892 form_obj.elements[i].disabled = true;
\r
896 TinyMCE.prototype.accessibleEventHandler = function(e) {
\r
897 var win = this._win;
\r
898 e = tinyMCE.isMSIE ? win.event : e;
\r
899 var elm = tinyMCE.isMSIE ? e.srcElement : e.target;
\r
901 // Piggyback onchange
\r
902 if (elm.nodeName == "SELECT" && !elm.oldonchange) {
\r
903 elm.oldonchange = elm.onchange;
\r
904 elm.onchange = null;
\r
907 // Execute onchange and remove piggyback
\r
908 if (e.keyCode == 13 || e.keyCode == 32) {
\r
909 elm.onchange = elm.oldonchange;
\r
911 elm.oldonchange = null;
\r
912 tinyMCE.cancelEvent(e);
\r
916 TinyMCE.prototype.addSelectAccessibility = function(e, select, win) {
\r
917 // Add event handlers
\r
918 if (!select._isAccessible) {
\r
919 select.onkeydown = tinyMCE.accessibleEventHandler;
\r
920 select._isAccessible = true;
\r
925 TinyMCE.prototype.handleEvent = function(e) {
\r
926 // Remove odd, error
\r
927 if (typeof(tinyMCE) == "undefined")
\r
930 //tinyMCE.debug(e.type + " " + e.target.nodeName + " " + (e.relatedTarget ? e.relatedTarget.nodeName : ""));
\r
934 if (tinyMCE.selectedInstance)
\r
935 tinyMCE.selectedInstance.execCommand('mceEndTyping');
\r
940 tinyMCE.removeTinyMCEFormElements(tinyMCE.isMSIE ? window.event.srcElement : e.target);
\r
941 tinyMCE.triggerSave();
\r
942 tinyMCE.isNotDirty = true;
\r
946 var formObj = tinyMCE.isMSIE ? window.event.srcElement : e.target;
\r
948 for (var i=0; i<document.forms.length; i++) {
\r
949 if (document.forms[i] == formObj)
\r
950 window.setTimeout('tinyMCE.resetForm(' + i + ');', 10);
\r
956 if (e.target.editorId) {
\r
957 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];
\r
959 if (e.target.ownerDocument.editorId)
\r
960 tinyMCE.selectedInstance = tinyMCE.instances[e.target.ownerDocument.editorId];
\r
963 if (tinyMCE.selectedInstance)
\r
964 tinyMCE.selectedInstance.switchSettings();
\r
966 // Insert space instead of
\r
967 /* if (tinyMCE.isGecko && e.charCode == 32) {
\r
968 if (tinyMCE.selectedInstance._insertSpace()) {
\r
970 e.preventDefault();
\r
975 // Insert P element
\r
976 if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) {
\r
977 // Insert P element instead of BR
\r
978 if (tinyMCE.selectedInstance._insertPara(e)) {
\r
980 tinyMCE.execCommand("mceAddUndoLevel");
\r
981 tinyMCE.cancelEvent(e);
\r
986 // Handle backspace
\r
987 if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
\r
988 // Insert P element instead of BR
\r
989 if (tinyMCE.selectedInstance._handleBackSpace(e.type)) {
\r
991 tinyMCE.execCommand("mceAddUndoLevel");
\r
992 tinyMCE.cancelEvent(e);
\r
997 // Mozilla custom key handling
\r
998 if (tinyMCE.isGecko && (e.ctrlKey && !e.altKey) && tinyMCE.settings['custom_undo_redo']) {
\r
999 if (tinyMCE.settings['custom_undo_redo_keyboard_shortcuts']) {
\r
1000 if (e.charCode == 122) { // Ctrl+Z
\r
1001 tinyMCE.selectedInstance.execCommand("Undo");
\r
1002 tinyMCE.cancelEvent(e);
\r
1006 if (e.charCode == 121) { // Ctrl+Y
\r
1007 tinyMCE.selectedInstance.execCommand("Redo");
\r
1008 tinyMCE.cancelEvent(e);
\r
1013 if (e.charCode == 98) { // Ctrl+B
\r
1014 tinyMCE.selectedInstance.execCommand("Bold");
\r
1015 tinyMCE.cancelEvent(e);
\r
1019 if (e.charCode == 105) { // Ctrl+I
\r
1020 tinyMCE.selectedInstance.execCommand("Italic");
\r
1021 tinyMCE.cancelEvent(e);
\r
1025 if (e.charCode == 117) { // Ctrl+U
\r
1026 tinyMCE.selectedInstance.execCommand("Underline");
\r
1027 tinyMCE.cancelEvent(e);
\r
1032 // Return key pressed
\r
1033 if (tinyMCE.isMSIE && tinyMCE.settings['force_br_newlines'] && e.keyCode == 13) {
\r
1034 if (e.target.editorId)
\r
1035 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];
\r
1037 if (tinyMCE.selectedInstance) {
\r
1038 var sel = tinyMCE.selectedInstance.getDoc().selection;
\r
1039 var rng = sel.createRange();
\r
1041 if (tinyMCE.getParentElement(rng.parentElement(), "li") != null)
\r
1045 e.returnValue = false;
\r
1046 e.cancelBubble = true;
\r
1048 // Insert BR element
\r
1049 rng.pasteHTML("<br />");
\r
1050 rng.collapse(false);
\r
1053 tinyMCE.execCommand("mceAddUndoLevel");
\r
1054 tinyMCE.triggerNodeChange(false);
\r
1059 // Backspace or delete
\r
1060 if (e.keyCode == 8 || e.keyCode == 46) {
\r
1061 tinyMCE.selectedElement = e.target;
\r
1062 tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a");
\r
1063 tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img");
\r
1064 tinyMCE.triggerNodeChange(false);
\r
1072 if (e.target.editorId)
\r
1073 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];
\r
1077 if (tinyMCE.selectedInstance)
\r
1078 tinyMCE.selectedInstance.switchSettings();
\r
1080 var inst = tinyMCE.selectedInstance;
\r
1082 // Handle backspace
\r
1083 if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
\r
1084 // Insert P element instead of BR
\r
1085 if (tinyMCE.selectedInstance._handleBackSpace(e.type)) {
\r
1087 tinyMCE.execCommand("mceAddUndoLevel");
\r
1088 e.preventDefault();
\r
1093 tinyMCE.selectedElement = null;
\r
1094 tinyMCE.selectedNode = null;
\r
1095 var elm = tinyMCE.selectedInstance.getFocusElement();
\r
1096 tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a");
\r
1097 tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img");
\r
1098 tinyMCE.selectedElement = elm;
\r
1100 // Update visualaids on tabs
\r
1101 if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9)
\r
1102 tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
\r
1104 // Fix empty elements on return/enter, check where enter occured
\r
1105 if (tinyMCE.isMSIE && e.type == "keydown" && e.keyCode == 13)
\r
1106 tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement();
\r
1108 // Fix empty elements on return/enter
\r
1109 if (tinyMCE.isMSIE && e.type == "keyup" && e.keyCode == 13) {
\r
1110 var elm = tinyMCE.enterKeyElement;
\r
1112 var re = new RegExp('^HR|IMG|BR$','g'); // Skip these
\r
1113 var dre = new RegExp('^H[1-6]$','g'); // Add double on these
\r
1115 if (!elm.hasChildNodes() && !re.test(elm.nodeName)) {
\r
1116 if (dre.test(elm.nodeName))
\r
1117 elm.innerHTML = " ";
\r
1119 elm.innerHTML = " ";
\r
1124 // Check if it's a position key
\r
1125 var keys = tinyMCE.posKeyCodes;
\r
1126 var posKey = false;
\r
1127 for (var i=0; i<keys.length; i++) {
\r
1128 if (keys[i] == e.keyCode) {
\r
1134 // MSIE custom key handling
\r
1135 if (tinyMCE.isMSIE && tinyMCE.settings['custom_undo_redo']) {
\r
1136 var keys = new Array(8,46); // Backspace,Delete
\r
1137 for (var i=0; i<keys.length; i++) {
\r
1138 if (keys[i] == e.keyCode) {
\r
1139 if (e.type == "keyup")
\r
1140 tinyMCE.triggerNodeChange(false);
\r
1144 if (tinyMCE.settings['custom_undo_redo_keyboard_shortcuts']) {
\r
1145 if (e.keyCode == 90 && (e.ctrlKey && !e.altKey) && e.type == "keydown") { // Ctrl+Z
\r
1146 tinyMCE.selectedInstance.execCommand("Undo");
\r
1147 tinyMCE.triggerNodeChange(false);
\r
1150 if (e.keyCode == 89 && (e.ctrlKey && !e.altKey) && e.type == "keydown") { // Ctrl+Y
\r
1151 tinyMCE.selectedInstance.execCommand("Redo");
\r
1152 tinyMCE.triggerNodeChange(false);
\r
1155 if ((e.keyCode == 90 || e.keyCode == 89) && (e.ctrlKey && !e.altKey)) {
\r
1157 e.returnValue = false;
\r
1158 e.cancelBubble = true;
\r
1164 // If undo/redo key
\r
1165 if ((e.keyCode == 90 || e.keyCode == 89) && (e.ctrlKey && !e.altKey))
\r
1169 if (e.keyCode == 17)
\r
1172 // Handle Undo/Redo when typing content
\r
1174 // Start typing (non position key)
\r
1175 if (!posKey && e.type == "keyup")
\r
1176 tinyMCE.execCommand("mceStartTyping");
\r
1178 // End typing (position key) or some Ctrl event
\r
1179 if (e.type == "keyup" && (posKey || e.ctrlKey))
\r
1180 tinyMCE.execCommand("mceEndTyping");
\r
1182 if (posKey && e.type == "keyup")
\r
1183 tinyMCE.triggerNodeChange(false);
\r
1185 if (tinyMCE.isMSIE && e.ctrlKey)
\r
1186 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
\r
1193 if (tinyMCE.selectedInstance)
\r
1194 tinyMCE.selectedInstance.switchSettings();
\r
1196 // Check instance event trigged on
\r
1197 var targetBody = tinyMCE.getParentElement(e.target, "body");
\r
1198 for (var instanceName in tinyMCE.instances) {
\r
1199 if (!tinyMCE.isInstance(tinyMCE.instances[instanceName]))
\r
1202 var inst = tinyMCE.instances[instanceName];
\r
1204 // Reset design mode if lost (on everything just in case)
\r
1205 inst.autoResetDesignMode();
\r
1207 if (inst.getBody() == targetBody) {
\r
1208 tinyMCE.selectedInstance = inst;
\r
1209 tinyMCE.selectedElement = e.target;
\r
1210 tinyMCE.linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
\r
1211 tinyMCE.imgElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "img");
\r
1216 if (tinyMCE.isSafari) {
\r
1217 tinyMCE.selectedInstance.lastSafariSelection = tinyMCE.selectedInstance.getBookmark();
\r
1218 tinyMCE.selectedInstance.lastSafariSelectedElement = tinyMCE.selectedElement;
\r
1220 var lnk = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
\r
1222 // Patch the darned link
\r
1223 if (lnk && e.type == "mousedown") {
\r
1224 lnk.setAttribute("mce_real_href", lnk.getAttribute("href"));
\r
1225 lnk.setAttribute("href", "javascript:void(0);");
\r
1229 if (lnk && e.type == "click") {
\r
1230 window.setTimeout(function() {
\r
1231 lnk.setAttribute("href", lnk.getAttribute("mce_real_href"));
\r
1232 lnk.removeAttribute("mce_real_href");
\r
1237 // Reset selected node
\r
1238 if (e.type != "focus")
\r
1239 tinyMCE.selectedNode = null;
\r
1241 tinyMCE.triggerNodeChange(false);
\r
1242 tinyMCE.execCommand("mceEndTyping");
\r
1244 if (e.type == "mouseup")
\r
1245 tinyMCE.execCommand("mceAddUndoLevel");
\r
1248 if (!tinyMCE.selectedInstance && e.target.editorId)
\r
1249 tinyMCE.selectedInstance = tinyMCE.instances[e.target.editorId];
\r
1254 }; // end function
\r
1256 TinyMCE.prototype.switchClass = function(element, class_name, lock_state) {
\r
1257 var lockChanged = false;
\r
1259 if (typeof(lock_state) != "undefined" && element != null) {
\r
1260 element.classLock = lock_state;
\r
1261 lockChanged = true;
\r
1264 if (element != null && (lockChanged || !element.classLock)) {
\r
1265 element.oldClassName = element.className;
\r
1266 element.className = class_name;
\r
1270 TinyMCE.prototype.restoreAndSwitchClass = function(element, class_name) {
\r
1271 if (element != null && !element.classLock) {
\r
1272 this.restoreClass(element);
\r
1273 this.switchClass(element, class_name);
\r
1277 TinyMCE.prototype.switchClassSticky = function(element_name, class_name, lock_state) {
\r
1278 var element, lockChanged = false;
\r
1280 // Performance issue
\r
1281 if (!this.stickyClassesLookup[element_name])
\r
1282 this.stickyClassesLookup[element_name] = document.getElementById(element_name);
\r
1284 // element = document.getElementById(element_name);
\r
1285 element = this.stickyClassesLookup[element_name];
\r
1287 if (typeof(lock_state) != "undefined" && element != null) {
\r
1288 element.classLock = lock_state;
\r
1289 lockChanged = true;
\r
1292 if (element != null && (lockChanged || !element.classLock)) {
\r
1293 element.className = class_name;
\r
1294 element.oldClassName = class_name;
\r
1296 // Fix opacity in Opera
\r
1297 if (tinyMCE.isOpera) {
\r
1298 if (class_name == "mceButtonDisabled") {
\r
1301 if (!element.mceOldSrc)
\r
1302 element.mceOldSrc = element.src;
\r
1304 if (this.operaOpacityCounter > -1)
\r
1305 suffix = '?rnd=' + this.operaOpacityCounter++;
\r
1307 element.src = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/images/opacity.png" + suffix;
\r
1308 element.style.backgroundImage = "url('" + element.mceOldSrc + "')";
\r
1310 if (element.mceOldSrc) {
\r
1311 element.src = element.mceOldSrc;
\r
1312 element.parentNode.style.backgroundImage = "";
\r
1313 element.mceOldSrc = null;
\r
1320 TinyMCE.prototype.restoreClass = function(element) {
\r
1321 if (element != null && element.oldClassName && !element.classLock) {
\r
1322 element.className = element.oldClassName;
\r
1323 element.oldClassName = null;
\r
1327 TinyMCE.prototype.setClassLock = function(element, lock_state) {
\r
1328 if (element != null)
\r
1329 element.classLock = lock_state;
\r
1332 TinyMCE.prototype.addEvent = function(obj, name, handler) {
\r
1333 if (tinyMCE.isMSIE) {
\r
1334 obj.attachEvent("on" + name, handler);
\r
1336 obj.addEventListener(name, handler, false);
\r
1339 TinyMCE.prototype.submitPatch = function() {
\r
1340 tinyMCE.removeTinyMCEFormElements(this);
\r
1341 tinyMCE.triggerSave();
\r
1342 this.mceOldSubmit();
\r
1343 tinyMCE.isNotDirty = true;
\r
1346 TinyMCE.prototype.onLoad = function() {
\r
1347 for (var c=0; c<tinyMCE.configs.length; c++) {
\r
1348 tinyMCE.settings = tinyMCE.configs[c];
\r
1350 var selector = tinyMCE.getParam("editor_selector");
\r
1351 var deselector = tinyMCE.getParam("editor_deselector");
\r
1352 var elementRefAr = new Array();
\r
1354 // Add submit triggers
\r
1355 if (document.forms && tinyMCE.settings['add_form_submit_trigger'] && !tinyMCE.submitTriggers) {
\r
1356 for (var i=0; i<document.forms.length; i++) {
\r
1357 var form = document.forms[i];
\r
1359 tinyMCE.addEvent(form, "submit", TinyMCE.prototype.handleEvent);
\r
1360 tinyMCE.addEvent(form, "reset", TinyMCE.prototype.handleEvent);
\r
1361 tinyMCE.submitTriggers = true; // Do it only once
\r
1363 // Patch the form.submit function
\r
1364 if (tinyMCE.settings['submit_patch']) {
\r
1366 form.mceOldSubmit = form.submit;
\r
1367 form.submit = TinyMCE.prototype.submitPatch;
\r
1375 // Add editor instances based on mode
\r
1376 var mode = tinyMCE.settings['mode'];
\r
1379 var elements = tinyMCE.getParam('elements', '', true, ',');
\r
1381 for (var i=0; i<elements.length; i++) {
\r
1382 var element = tinyMCE._getElementById(elements[i]);
\r
1383 var trigger = element ? element.getAttribute(tinyMCE.settings['textarea_trigger']) : "";
\r
1385 if (tinyMCE.getAttrib(element, "class").indexOf(deselector) != -1)
\r
1388 if (trigger == "false")
\r
1391 if (tinyMCE.settings['ask'] && element) {
\r
1392 elementRefAr[elementRefAr.length] = element;
\r
1397 tinyMCE.addMCEControl(element, elements[i]);
\r
1398 else if (tinyMCE.settings['debug'])
\r
1399 alert("Error: Could not find element by id or name: " + elements[i]);
\r
1403 case "specific_textareas":
\r
1405 var nodeList = document.getElementsByTagName("textarea");
\r
1407 for (var i=0; i<nodeList.length; i++) {
\r
1408 var elm = nodeList.item(i);
\r
1409 var trigger = elm.getAttribute(tinyMCE.settings['textarea_trigger']);
\r
1411 if (selector != '' && tinyMCE.getAttrib(elm, "class").indexOf(selector) == -1)
\r
1414 if (selector != '')
\r
1415 trigger = selector != "" ? "true" : "";
\r
1417 if (tinyMCE.getAttrib(elm, "class").indexOf(deselector) != -1)
\r
1420 if ((mode == "specific_textareas" && trigger == "true") || (mode == "textareas" && trigger != "false"))
\r
1421 elementRefAr[elementRefAr.length] = elm;
\r
1426 for (var i=0; i<elementRefAr.length; i++) {
\r
1427 var element = elementRefAr[i];
\r
1428 var elementId = element.name ? element.name : element.id;
\r
1430 if (tinyMCE.settings['ask']) {
\r
1431 // Focus breaks in Mozilla
\r
1432 if (tinyMCE.isGecko) {
\r
1433 var settings = tinyMCE.settings;
\r
1435 tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE.prototype.confirmAdd(e, settings);}, 10);});
\r
1437 var settings = tinyMCE.settings;
\r
1439 tinyMCE.addEvent(element, "focus", function () { TinyMCE.prototype.confirmAdd(null, settings); });
\r
1442 tinyMCE.addMCEControl(element, elementId);
\r
1445 // Handle auto focus
\r
1446 if (tinyMCE.settings['auto_focus']) {
\r
1447 window.setTimeout(function () {
\r
1448 var inst = tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);
\r
1449 inst.selectNode(inst.getBody(), true, true);
\r
1450 inst.contentWindow.focus();
\r
1454 tinyMCE.executeCallback('oninit', '_oninit', 0);
\r
1458 TinyMCE.prototype.removeMCEControl = function(editor_id) {
\r
1459 var inst = tinyMCE.getInstanceById(editor_id);
\r
1462 inst.switchSettings();
\r
1464 editor_id = inst.editorId;
\r
1465 var html = tinyMCE.getContent(editor_id);
\r
1467 // Remove editor instance from instances array
\r
1468 var tmpInstances = new Array();
\r
1469 for (var instanceName in tinyMCE.instances) {
\r
1470 var instance = tinyMCE.instances[instanceName];
\r
1471 if (!tinyMCE.isInstance(instance))
\r
1474 if (instanceName != editor_id)
\r
1475 tmpInstances[instanceName] = instance;
\r
1477 tinyMCE.instances = tmpInstances;
\r
1479 tinyMCE.selectedElement = null;
\r
1480 tinyMCE.selectedInstance = null;
\r
1483 var replaceElement = document.getElementById(editor_id + "_parent");
\r
1484 var oldTargetElement = inst.oldTargetElement;
\r
1485 var targetName = oldTargetElement.nodeName.toLowerCase();
\r
1487 if (targetName == "textarea" || targetName == "input") {
\r
1488 // Just show the old text area
\r
1489 replaceElement.parentNode.removeChild(replaceElement);
\r
1490 oldTargetElement.style.display = "inline";
\r
1491 oldTargetElement.value = html;
\r
1493 oldTargetElement.innerHTML = html;
\r
1495 replaceElement.parentNode.insertBefore(oldTargetElement, replaceElement);
\r
1496 replaceElement.parentNode.removeChild(replaceElement);
\r
1501 TinyMCE.prototype._cleanupElementName = function(element_name, element) {
\r
1504 element_name = element_name.toLowerCase();
\r
1506 // Never include body
\r
1507 if (element_name == "body")
\r
1510 // If verification mode
\r
1511 if (tinyMCE.cleanup_verify_html) {
\r
1512 // Check if invalid element
\r
1513 for (var i=0; i<tinyMCE.cleanup_invalidElements.length; i++) {
\r
1514 if (tinyMCE.cleanup_invalidElements[i] == element_name)
\r
1518 // Check if valid element
\r
1519 var validElement = false;
\r
1520 var elementAttribs = null;
\r
1521 for (var i=0; i<tinyMCE.cleanup_validElements.length && !elementAttribs; i++) {
\r
1522 for (var x=0, n=tinyMCE.cleanup_validElements[i][0].length; x<n; x++) {
\r
1523 var elmMatch = tinyMCE.cleanup_validElements[i][0][x];
\r
1525 if (elmMatch.charAt(0) == '+' || elmMatch.charAt(0) == '-')
\r
1526 elmMatch = elmMatch.substring(1);
\r
1528 // Handle wildcard/regexp
\r
1529 if (elmMatch.match(new RegExp('\\*|\\?|\\+', 'g')) != null) {
\r
1530 elmMatch = elmMatch.replace(new RegExp('\\?', 'g'), '(\\S?)');
\r
1531 elmMatch = elmMatch.replace(new RegExp('\\+', 'g'), '(\\S+)');
\r
1532 elmMatch = elmMatch.replace(new RegExp('\\*', 'g'), '(\\S*)');
\r
1533 elmMatch = "^" + elmMatch + "$";
\r
1534 if (element_name.match(new RegExp(elmMatch, 'g'))) {
\r
1535 elementAttribs = tinyMCE.cleanup_validElements[i];
\r
1536 validElement = true;
\r
1541 // Handle non regexp
\r
1542 if (element_name == elmMatch) {
\r
1543 elementAttribs = tinyMCE.cleanup_validElements[i];
\r
1544 validElement = true;
\r
1545 element_name = elementAttribs[0][0];
\r
1551 if (!validElement)
\r
1555 if (element_name.charAt(0) == '+' || element_name.charAt(0) == '-')
\r
1556 name = element_name.substring(1);
\r
1558 // Special Mozilla stuff
\r
1559 if (!tinyMCE.isMSIE) {
\r
1560 // Fix for bug #958498
\r
1561 if (name == "strong" && !tinyMCE.cleanup_on_save)
\r
1562 element_name = "b";
\r
1563 else if (name == "em" && !tinyMCE.cleanup_on_save)
\r
1564 element_name = "i";
\r
1567 var elmData = new Object();
\r
1569 elmData.element_name = element_name;
\r
1570 elmData.valid_attribs = elementAttribs;
\r
1576 * This function moves CSS styles to/from attributes.
\r
1578 TinyMCE.prototype._moveStyle = function(elm, style, attrib) {
\r
1579 if (tinyMCE.cleanup_inline_styles) {
\r
1580 var val = tinyMCE.getAttrib(elm, attrib);
\r
1586 case "background":
\r
1587 val = "url('" + val + "')";
\r
1590 case "bordercolor":
\r
1591 if (elm.style.borderStyle == '' || elm.style.borderStyle == 'none')
\r
1592 elm.style.borderStyle = 'solid';
\r
1598 if (attrib == "border" && elm.style.borderWidth > 0)
\r
1601 if (val.indexOf('%') == -1)
\r
1607 elm.style.marginTop = val + "px";
\r
1608 elm.style.marginBottom = val + "px";
\r
1609 elm.removeAttribute(attrib);
\r
1613 if (elm.nodeName == "IMG") {
\r
1614 if (tinyMCE.isMSIE)
\r
1615 elm.style.styleFloat = val;
\r
1617 elm.style.cssFloat = val;
\r
1619 elm.style.textAlign = val;
\r
1621 elm.removeAttribute(attrib);
\r
1626 eval('elm.style.' + style + ' = val;');
\r
1627 elm.removeAttribute(attrib);
\r
1634 var val = eval('elm.style.' + style) == '' ? tinyMCE.getAttrib(elm, attrib) : eval('elm.style.' + style);
\r
1635 val = val == null ? '' : '' + val;
\r
1638 // Always move background to style
\r
1639 case "background":
\r
1640 if (val.indexOf('url') == -1 && val != '')
\r
1641 val = "url('" + val + "');";
\r
1644 elm.style.backgroundImage = val;
\r
1645 elm.removeAttribute(attrib);
\r
1652 val = val.replace('px', '');
\r
1656 if (tinyMCE.getAttrib(elm, 'align') == '') {
\r
1657 if (elm.nodeName == "IMG") {
\r
1658 if (tinyMCE.isMSIE && elm.style.styleFloat != '') {
\r
1659 val = elm.style.styleFloat;
\r
1660 style = 'styleFloat';
\r
1661 } else if (tinyMCE.isGecko && elm.style.cssFloat != '') {
\r
1662 val = elm.style.cssFloat;
\r
1663 style = 'cssFloat';
\r
1671 elm.removeAttribute(attrib);
\r
1672 elm.setAttribute(attrib, val);
\r
1673 eval('elm.style.' + style + ' = "";');
\r
1678 TinyMCE.prototype._cleanupAttribute = function(valid_attributes, element_name, attribute_node, element_node) {
\r
1679 var attribName = attribute_node.nodeName.toLowerCase();
\r
1680 var attribValue = attribute_node.nodeValue;
\r
1681 var attribMustBeValue = null;
\r
1682 var verified = false;
\r
1684 // Mozilla attibute, remove them
\r
1685 if (attribName.indexOf('moz_') != -1)
\r
1688 if (!tinyMCE.cleanup_on_save && (attribName == "mce_href" || attribName == "mce_src"))
\r
1689 return {name : attribName, value : attribValue};
\r
1692 if (tinyMCE.cleanup_verify_html && !verified) {
\r
1693 for (var i=1; i<valid_attributes.length; i++) {
\r
1694 var attribMatch = valid_attributes[i][0];
\r
1697 // Build regexp from wildcard
\r
1698 if (attribMatch.match(new RegExp('\\*|\\?|\\+', 'g')) != null) {
\r
1699 attribMatch = attribMatch.replace(new RegExp('\\?', 'g'), '(\\S?)');
\r
1700 attribMatch = attribMatch.replace(new RegExp('\\+', 'g'), '(\\S+)');
\r
1701 attribMatch = attribMatch.replace(new RegExp('\\*', 'g'), '(\\S*)');
\r
1702 attribMatch = "^" + attribMatch + "$";
\r
1703 re = new RegExp(attribMatch, 'g');
\r
1706 if ((re && attribName.match(re) != null) || attribName == attribMatch) {
\r
1708 attribMustBeValue = valid_attributes[i][3];
\r
1718 // Treat some attribs diffrent
\r
1719 switch (attribName) {
\r
1721 if (tinyMCE.isMSIE5 && element_name == "font")
\r
1722 attribValue = element_node.size;
\r
1728 // Old MSIE needs this
\r
1729 if (tinyMCE.isMSIE5)
\r
1730 attribValue = eval("element_node." + attribName);
\r
1734 attribValue = attribValue.toLowerCase();
\r
1737 case "cellspacing":
\r
1738 if (tinyMCE.isMSIE5)
\r
1739 attribValue = element_node.cellSpacing;
\r
1742 case "cellpadding":
\r
1743 if (tinyMCE.isMSIE5)
\r
1744 attribValue = element_node.cellPadding;
\r
1748 if (tinyMCE.isMSIE5 && element_name == "font")
\r
1749 attribValue = element_node.color;
\r
1753 // Remove mceItem classes from anchors
\r
1754 if (tinyMCE.cleanup_on_save && attribValue.indexOf('mceItemAnchor') != -1)
\r
1755 attribValue = attribValue.replace(/mceItem[a-z0-9]+/gi, '');
\r
1757 if (element_name == "table" || element_name == "td") {
\r
1758 // Handle visual aid
\r
1759 if (tinyMCE.cleanup_visual_table_class != "")
\r
1760 attribValue = tinyMCE.getVisualAidClass(attribValue, !tinyMCE.cleanup_on_save);
\r
1763 if (!tinyMCE._verifyClass(element_node) || attribValue == "")
\r
1771 case "ondblclick":
\r
1772 case "onmousedown":
\r
1774 case "onmouseover":
\r
1775 case "onmousemove":
\r
1776 case "onmouseout":
\r
1777 case "onkeypress":
\r
1781 attribValue = tinyMCE.cleanupEventStr("" + attribValue);
\r
1783 if (attribValue.indexOf('return false;') == 0)
\r
1784 attribValue = attribValue.substring(14);
\r
1789 attribValue = tinyMCE.serializeStyle(tinyMCE.parseStyle(tinyMCE.getAttrib(element_node, "style")));
\r
1792 // Convert the URLs of these
\r
1796 attribValue = tinyMCE.getAttrib(element_node, attribName);
\r
1798 // Use mce_href instead
\r
1799 var href = tinyMCE.getAttrib(element_node, "mce_href");
\r
1800 if (attribName == "href" && href != "")
\r
1801 attribValue = href;
\r
1803 // Use mce_src instead
\r
1804 var src = tinyMCE.getAttrib(element_node, "mce_src");
\r
1805 if (attribName == "src" && src != "")
\r
1806 attribValue = src;
\r
1808 // Always use absolute URLs within TinyMCE
\r
1809 if (!tinyMCE.cleanup_on_save)
\r
1810 attribValue = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], attribValue);
\r
1811 else if (tinyMCE.getParam('convert_urls'))
\r
1812 attribValue = eval(tinyMCE.cleanup_urlconverter_callback + "(attribValue, element_node, tinyMCE.cleanup_on_save);");
\r
1819 if (attribValue == "1")
\r
1824 case "_moz-userdefined":
\r
1831 // Not the must be value
\r
1832 if (attribMustBeValue != null) {
\r
1833 var isCorrect = false;
\r
1834 for (var i=0; i<attribMustBeValue.length; i++) {
\r
1835 if (attribValue == attribMustBeValue[i]) {
\r
1845 var attrib = new Object();
\r
1847 attrib.name = attribName;
\r
1848 attrib.value = attribValue;
\r
1853 TinyMCE.prototype.clearArray = function(ar) {
\r
1854 // Since stupid people tend to extend core objects like
\r
1855 // Array with their own crap I needed to make functions that clean away
\r
1856 // this junk so the arrays get clean and nice as they should be
\r
1857 for (var key in ar)
\r
1861 TinyMCE.prototype.isInstance = function(inst) {
\r
1862 return inst != null && typeof(inst) == "object" && inst.isTinyMCEControl;
\r
1865 TinyMCE.prototype.parseStyle = function(str) {
\r
1866 var ar = new Array();
\r
1871 var st = str.split(';');
\r
1873 tinyMCE.clearArray(ar);
\r
1875 for (var i=0; i<st.length; i++) {
\r
1879 var re = new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');
\r
1880 var pa = st[i].replace(re, '$1||$2').split('||');
\r
1881 //tinyMCE.debug(str, pa[0] + "=" + pa[1], st[i].replace(re, '$1||$2'));
\r
1882 if (pa.length == 2)
\r
1883 ar[pa[0].toLowerCase()] = pa[1];
\r
1889 TinyMCE.prototype.compressStyle = function(ar, pr, sf, res) {
\r
1890 var box = new Array();
\r
1892 box[0] = ar[pr + '-top' + sf];
\r
1893 box[1] = ar[pr + '-left' + sf];
\r
1894 box[2] = ar[pr + '-right' + sf];
\r
1895 box[3] = ar[pr + '-bottom' + sf];
\r
1897 for (var i=0; i<box.length; i++) {
\r
1898 if (box[i] == null)
\r
1901 for (var a=0; a<box.length; a++) {
\r
1902 if (box[a] != box[i])
\r
1907 // They are all the same
\r
1909 ar[pr + '-top' + sf] = null;
\r
1910 ar[pr + '-left' + sf] = null;
\r
1911 ar[pr + '-right' + sf] = null;
\r
1912 ar[pr + '-bottom' + sf] = null;
\r
1915 TinyMCE.prototype.serializeStyle = function(ar) {
\r
1919 tinyMCE.compressStyle(ar, "border", "", "border");
\r
1920 tinyMCE.compressStyle(ar, "border", "-width", "border-width");
\r
1921 tinyMCE.compressStyle(ar, "border", "-color", "border-color");
\r
1923 for (var key in ar) {
\r
1924 var val = ar[key];
\r
1925 if (typeof(val) == 'function')
\r
1928 if (val != null && val != '') {
\r
1929 val = '' + val; // Force string
\r
1932 val = val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)", 'gi'), "url('$1')");
\r
1935 if (val.indexOf('url(') != -1 && tinyMCE.getParam('convert_urls')) {
\r
1936 var m = new RegExp("url\\('(.*?)'\\)").exec(val);
\r
1939 val = "url('" + eval(tinyMCE.getParam('urlconverter_callback') + "(m[1], null, true);") + "')";
\r
1942 // Force HEX colors
\r
1943 if (tinyMCE.getParam("force_hex_style_colors"))
\r
1944 val = tinyMCE.convertRGBToHex(val, true);
\r
1946 if (val != "url('')")
\r
1947 str += key.toLowerCase() + ": " + val + "; ";
\r
1951 if (new RegExp('; $').test(str))
\r
1952 str = str.substring(0, str.length - 2);
\r
1957 TinyMCE.prototype.convertRGBToHex = function(s, k) {
\r
1958 if (s.toLowerCase().indexOf('rgb') != -1) {
\r
1959 var re = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
\r
1960 var rgb = s.replace(re, "$1,$2,$3,$4,$5").split(',');
\r
1961 if (rgb.length == 5) {
\r
1962 r = parseInt(rgb[1]).toString(16);
\r
1963 g = parseInt(rgb[2]).toString(16);
\r
1964 b = parseInt(rgb[3]).toString(16);
\r
1966 r = r.length == 1 ? '0' + r : r;
\r
1967 g = g.length == 1 ? '0' + g : g;
\r
1968 b = b.length == 1 ? '0' + b : b;
\r
1970 s = "#" + r + g + b;
\r
1973 s = rgb[0] + s + rgb[4];
\r
1980 TinyMCE.prototype.convertHexToRGB = function(s) {
\r
1981 if (s.indexOf('#') != -1) {
\r
1982 s = s.replace(new RegExp('[^0-9A-F]', 'gi'), '');
\r
1983 return "rgb(" + parseInt(s.substring(0, 2), 16) + "," + parseInt(s.substring(2, 4), 16) + "," + parseInt(s.substring(4, 6), 16) + ")";
\r
1989 TinyMCE.prototype._verifyClass = function(node) {
\r
1990 // Sometimes the class gets set to null, weird Gecko bug?
\r
1991 if (tinyMCE.isGecko) {
\r
1992 var className = node.getAttribute('class');
\r
1998 if (tinyMCE.isMSIE)
\r
1999 var className = node.getAttribute('className');
\r
2001 if (tinyMCE.cleanup_verify_css_classes && tinyMCE.cleanup_on_save) {
\r
2002 var csses = tinyMCE.getCSSClasses();
\r
2003 nonDefinedCSS = true;
\r
2004 for (var c=0; c<csses.length; c++) {
\r
2005 if (csses[c] == className) {
\r
2006 nonDefinedCSS = false;
\r
2011 if (nonDefinedCSS && className.indexOf('mce_') != 0) {
\r
2012 node.removeAttribute('className');
\r
2013 node.removeAttribute('class');
\r
2021 TinyMCE.prototype.cleanupNode = function(node) {
\r
2024 switch (node.nodeType) {
\r
2025 case 1: // Element
\r
2026 var elementData = tinyMCE._cleanupElementName(node.nodeName, node);
\r
2027 var elementName = elementData ? elementData.element_name : null;
\r
2028 var elementValidAttribs = elementData ? elementData.valid_attribs : null;
\r
2029 var elementAttribs = "";
\r
2030 var openTag = false, nonEmptyTag = false;
\r
2032 if (elementName != null && elementName.charAt(0) == '+') {
\r
2033 elementName = elementName.substring(1);
\r
2037 if (elementName != null && elementName.charAt(0) == '-') {
\r
2038 elementName = elementName.substring(1);
\r
2039 nonEmptyTag = true;
\r
2042 // Checking DOM tree for MSIE weirdness!!
\r
2043 if (tinyMCE.isMSIE && tinyMCE.settings['fix_content_duplication']) {
\r
2044 var lookup = tinyMCE.cleanup_elementLookupTable;
\r
2046 for (var i=0; i<lookup.length; i++) {
\r
2047 // Found element reference else were, hmm?
\r
2048 if (lookup[i] == node)
\r
2052 // Add element to lookup table
\r
2053 lookup[lookup.length] = node;
\r
2056 // Element not valid (only render children)
\r
2057 if (!elementName) {
\r
2058 if (node.hasChildNodes()) {
\r
2059 for (var i=0; i<node.childNodes.length; i++)
\r
2060 output += this.cleanupNode(node.childNodes[i]);
\r
2066 if (tinyMCE.cleanup_on_save) {
\r
2067 if (node.nodeName == "A" && node.className == "mceItemAnchor") {
\r
2068 if (node.hasChildNodes()) {
\r
2069 for (var i=0; i<node.childNodes.length; i++)
\r
2070 output += this.cleanupNode(node.childNodes[i]);
\r
2073 return '<a name="' + this.convertStringToXML(node.getAttribute("name")) + '"></a>' + output;
\r
2077 // Remove deprecated attributes
\r
2078 var re = new RegExp("^(TABLE|TD|TR)$");
\r
2079 if (re.test(node.nodeName)) {
\r
2080 // Move attrib to style
\r
2081 if ((node.nodeName != "TABLE" || tinyMCE.cleanup_inline_styles) && (width = tinyMCE.getAttrib(node, "width")) != '') {
\r
2082 node.style.width = width.indexOf('%') != -1 ? width : width.replace(/[^0-9]/gi, '') + "px";
\r
2083 node.removeAttribute("width");
\r
2086 // Is table and not inline
\r
2087 if ((node.nodeName == "TABLE" && !tinyMCE.cleanup_inline_styles) && node.style.width != '') {
\r
2088 tinyMCE.setAttrib(node, "width", node.style.width.replace('px',''));
\r
2089 node.style.width = '';
\r
2092 // Move attrib to style
\r
2093 if ((height = tinyMCE.getAttrib(node, "height")) != '') {
\r
2094 height = "" + height; // Force string
\r
2095 node.style.height = height.indexOf('%') != -1 ? height : height.replace(/[^0-9]/gi, '') + "px";
\r
2096 node.removeAttribute("height");
\r
2100 // Handle inline/outline styles
\r
2101 if (tinyMCE.cleanup_inline_styles) {
\r
2102 var re = new RegExp("^(TABLE|TD|TR|IMG|HR)$");
\r
2103 if (re.test(node.nodeName) && tinyMCE.getAttrib(node, "class").indexOf('mceItem') == -1) {
\r
2104 tinyMCE._moveStyle(node, 'width', 'width');
\r
2105 tinyMCE._moveStyle(node, 'height', 'height');
\r
2106 tinyMCE._moveStyle(node, 'borderWidth', 'border');
\r
2107 tinyMCE._moveStyle(node, '', 'vspace');
\r
2108 tinyMCE._moveStyle(node, '', 'hspace');
\r
2109 tinyMCE._moveStyle(node, 'textAlign', 'align');
\r
2110 tinyMCE._moveStyle(node, 'backgroundColor', 'bgColor');
\r
2111 tinyMCE._moveStyle(node, 'borderColor', 'borderColor');
\r
2112 tinyMCE._moveStyle(node, 'backgroundImage', 'background');
\r
2114 // Refresh element in old MSIE
\r
2115 if (tinyMCE.isMSIE5)
\r
2116 node.outerHTML = node.outerHTML;
\r
2117 } else if (tinyMCE.isBlockElement(node))
\r
2118 tinyMCE._moveStyle(node, 'textAlign', 'align');
\r
2120 if (node.nodeName == "FONT")
\r
2121 tinyMCE._moveStyle(node, 'color', 'color');
\r
2124 // Set attrib data
\r
2125 if (elementValidAttribs) {
\r
2126 for (var a=1; a<elementValidAttribs.length; a++) {
\r
2127 var attribName, attribDefaultValue, attribForceValue, attribValue;
\r
2129 attribName = elementValidAttribs[a][0];
\r
2130 attribDefaultValue = elementValidAttribs[a][1];
\r
2131 attribForceValue = elementValidAttribs[a][2];
\r
2133 if (attribDefaultValue != null || attribForceValue != null) {
\r
2134 var attribValue = node.getAttribute(attribName);
\r
2136 if (node.getAttribute(attribName) == null || node.getAttribute(attribName) == "")
\r
2137 attribValue = attribDefaultValue;
\r
2139 attribValue = attribForceValue ? attribForceValue : attribValue;
\r
2141 // Is to generate id
\r
2142 if (attribValue == "{$uid}")
\r
2143 attribValue = "uid_" + (tinyMCE.cleanup_idCount++);
\r
2145 // Add visual aid class
\r
2146 if (attribName == "class")
\r
2147 attribValue = tinyMCE.getVisualAidClass(attribValue, tinyMCE.cleanup_on_save);
\r
2149 node.setAttribute(attribName, attribValue);
\r
2150 //alert(attribName + "=" + attribValue);
\r
2155 if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && elementName == "style")
\r
2156 return "<style>" + node.innerHTML + "</style>";
\r
2158 // Remove empty tables
\r
2159 if (elementName == "table" && !node.hasChildNodes())
\r
2162 // Handle element attributes
\r
2163 if (node.attributes.length > 0) {
\r
2164 var lastAttrib = "";
\r
2166 for (var i=0; i<node.attributes.length; i++) {
\r
2167 if (node.attributes[i].specified) {
\r
2168 // Is the attrib already processed (removed duplicate attributes in opera TD[align=left])
\r
2169 if (tinyMCE.isOpera) {
\r
2170 if (node.attributes[i].nodeName == lastAttrib)
\r
2173 lastAttrib = node.attributes[i].nodeName;
\r
2176 // tinyMCE.debug(node.nodeName, node.attributes[i].nodeName, node.attributes[i].nodeValue, node.innerHTML);
\r
2177 var attrib = tinyMCE._cleanupAttribute(elementValidAttribs, elementName, node.attributes[i], node);
\r
2178 if (attrib && attrib.value != "")
\r
2179 elementAttribs += " " + attrib.name + "=" + '"' + this.convertStringToXML("" + attrib.value) + '"';
\r
2184 // MSIE table summary fix (MSIE 5.5)
\r
2185 if (tinyMCE.isMSIE && elementName == "table" && node.getAttribute("summary") != null && elementAttribs.indexOf('summary') == -1) {
\r
2186 var summary = tinyMCE.getAttrib(node, 'summary');
\r
2187 if (summary != '')
\r
2188 elementAttribs += " summary=" + '"' + this.convertStringToXML(summary) + '"';
\r
2191 // Handle missing attributes in MSIE 5.5
\r
2192 if (tinyMCE.isMSIE5 && /^(td|img|a)$/.test(elementName)) {
\r
2193 var ma = new Array("scope", "longdesc", "hreflang", "charset", "type");
\r
2195 for (var u=0; u<ma.length; u++) {
\r
2196 if (node.getAttribute(ma[u]) != null) {
\r
2197 var s = tinyMCE.getAttrib(node, ma[u]);
\r
2200 elementAttribs += " " + ma[u] + "=" + '"' + this.convertStringToXML(s) + '"';
\r
2205 // MSIE form element issue
\r
2206 if (tinyMCE.isMSIE && elementName == "input") {
\r
2208 if (!elementAttribs.match(/ type=/g))
\r
2209 elementAttribs += " type=" + '"' + node.type + '"';
\r
2213 if (!elementAttribs.match(/ value=/g))
\r
2214 elementAttribs += " value=" + '"' + node.value + '"';
\r
2218 // Add nbsp to some elements
\r
2219 if ((elementName == "p" || elementName == "td") && (node.innerHTML == "" || node.innerHTML == " "))
\r
2220 return "<" + elementName + elementAttribs + ">" + this.convertStringToXML(String.fromCharCode(160)) + "</" + elementName + ">";
\r
2222 // Is MSIE script element
\r
2223 if (tinyMCE.isMSIE && elementName == "script")
\r
2224 return "<" + elementName + elementAttribs + ">" + node.text + "</" + elementName + ">";
\r
2226 // Clean up children
\r
2227 if (node.hasChildNodes()) {
\r
2228 // If not empty span
\r
2229 if (!(elementName == "span" && elementAttribs == "" && tinyMCE.getParam("trim_span_elements"))) {
\r
2231 if (elementName == "p" && tinyMCE.cleanup_force_br_newlines)
\r
2232 output += "<div" + elementAttribs + ">";
\r
2234 output += "<" + elementName + elementAttribs + ">";
\r
2237 for (var i=0; i<node.childNodes.length; i++)
\r
2238 output += this.cleanupNode(node.childNodes[i]);
\r
2240 // If not empty span
\r
2241 if (!(elementName == "span" && elementAttribs == "" && tinyMCE.getParam("trim_span_elements"))) {
\r
2243 if (elementName == "p" && tinyMCE.cleanup_force_br_newlines)
\r
2244 output += "</div><br />";
\r
2246 output += "</" + elementName + ">";
\r
2249 if (!nonEmptyTag) {
\r
2251 output += "<" + elementName + elementAttribs + "></" + elementName + ">";
\r
2253 output += "<" + elementName + elementAttribs + " />";
\r
2260 // Do not convert script elements
\r
2261 if (node.parentNode.nodeName == "SCRIPT" || node.parentNode.nodeName == "NOSCRIPT" || node.parentNode.nodeName == "STYLE")
\r
2262 return node.nodeValue;
\r
2264 return this.convertStringToXML(node.nodeValue);
\r
2266 case 8: // Comment
\r
2267 return "<!--" + node.nodeValue + "-->";
\r
2269 default: // Unknown
\r
2270 return "[UNKNOWN NODETYPE " + node.nodeType + "]";
\r
2274 TinyMCE.prototype.convertStringToXML = function(html_data) {
\r
2277 for (var i=0; i<html_data.length; i++) {
\r
2278 var chr = html_data.charCodeAt(i);
\r
2280 // Numeric entities
\r
2281 if (tinyMCE.settings['entity_encoding'] == "numeric") {
\r
2283 output += '&#' + chr + ";";
\r
2285 output += String.fromCharCode(chr);
\r
2291 if (tinyMCE.settings['entity_encoding'] == "raw") {
\r
2292 output += String.fromCharCode(chr);
\r
2297 if (typeof(tinyMCE.settings['cleanup_entities']["c" + chr]) != 'undefined' && tinyMCE.settings['cleanup_entities']["c" + chr] != '')
\r
2298 output += '&' + tinyMCE.settings['cleanup_entities']["c" + chr] + ';';
\r
2300 output += '' + String.fromCharCode(chr);
\r
2306 TinyMCE.prototype._getCleanupElementName = function(chunk) {
\r
2309 if (chunk.charAt(0) == '+')
\r
2310 chunk = chunk.substring(1);
\r
2312 if (chunk.charAt(0) == '-')
\r
2313 chunk = chunk.substring(1);
\r
2315 if ((pos = chunk.indexOf('/')) != -1)
\r
2316 chunk = chunk.substring(0, pos);
\r
2318 if ((pos = chunk.indexOf('[')) != -1)
\r
2319 chunk = chunk.substring(0, pos);
\r
2324 TinyMCE.prototype._initCleanup = function() {
\r
2325 // Parse valid elements and attributes
\r
2326 var validElements = tinyMCE.settings["valid_elements"];
\r
2327 validElements = validElements.split(',');
\r
2329 // Handle extended valid elements
\r
2330 var extendedValidElements = tinyMCE.settings["extended_valid_elements"];
\r
2331 extendedValidElements = extendedValidElements.split(',');
\r
2332 for (var i=0; i<extendedValidElements.length; i++) {
\r
2333 var elementName = this._getCleanupElementName(extendedValidElements[i]);
\r
2334 var skipAdd = false;
\r
2336 // Check if it's defined before, if so override that one
\r
2337 for (var x=0; x<validElements.length; x++) {
\r
2338 if (this._getCleanupElementName(validElements[x]) == elementName) {
\r
2339 validElements[x] = extendedValidElements[i];
\r
2346 validElements[validElements.length] = extendedValidElements[i];
\r
2349 for (var i=0; i<validElements.length; i++) {
\r
2350 var item = validElements[i];
\r
2352 item = item.replace('[','|');
\r
2353 item = item.replace(']','');
\r
2355 // Split and convert
\r
2356 var attribs = item.split('|');
\r
2357 for (var x=0; x<attribs.length; x++)
\r
2358 attribs[x] = attribs[x].toLowerCase();
\r
2360 // Handle change elements
\r
2361 attribs[0] = attribs[0].split('/');
\r
2363 // Handle default attribute values
\r
2364 for (var x=1; x<attribs.length; x++) {
\r
2365 var attribName = attribs[x];
\r
2366 var attribDefault = null;
\r
2367 var attribForce = null;
\r
2368 var attribMustBe = null;
\r
2371 if ((pos = attribName.indexOf('=')) != -1) {
\r
2372 attribDefault = attribName.substring(pos+1);
\r
2373 attribName = attribName.substring(0, pos);
\r
2377 if ((pos = attribName.indexOf(':')) != -1) {
\r
2378 attribForce = attribName.substring(pos+1);
\r
2379 attribName = attribName.substring(0, pos);
\r
2383 if ((pos = attribName.indexOf('<')) != -1) {
\r
2384 attribMustBe = attribName.substring(pos+1).split('?');
\r
2385 attribName = attribName.substring(0, pos);
\r
2388 attribs[x] = new Array(attribName, attribDefault, attribForce, attribMustBe);
\r
2391 validElements[i] = attribs;
\r
2394 var invalidElements = tinyMCE.settings['invalid_elements'].split(',');
\r
2395 for (var i=0; i<invalidElements.length; i++)
\r
2396 invalidElements[i] = invalidElements[i].toLowerCase();
\r
2398 // Set these for performance
\r
2399 tinyMCE.settings['cleanup_validElements'] = validElements;
\r
2400 tinyMCE.settings['cleanup_invalidElements'] = invalidElements;
\r
2403 TinyMCE.prototype._cleanupHTML = function(inst, doc, config, element, visual, on_save) {
\r
2404 if (!tinyMCE.settings['cleanup']) {
\r
2405 tinyMCE.handleVisualAid(inst.getBody(), true, false, inst);
\r
2407 var html = element.innerHTML;
\r
2409 // Remove mce_href/mce_src
\r
2410 html = html.replace(new RegExp('(mce_href|mce_src)=".*?"', 'gi'), '');
\r
2411 html = html.replace(/\s+>/gi, '>');
\r
2416 if (on_save && tinyMCE.getParam("convert_fonts_to_spans"))
\r
2417 tinyMCE.convertFontsToSpans(doc);
\r
2419 // Call custom cleanup code
\r
2420 tinyMCE._customCleanup(inst, on_save ? "get_from_editor_dom" : "insert_to_editor_dom", doc.body);
\r
2422 // Move bgcolor to style
\r
2423 var n = doc.getElementsByTagName("font");
\r
2424 for (var i=0; i<n.length; i++) {
\r
2426 if ((c = tinyMCE.getAttrib(n[i], "bgcolor")) != "") {
\r
2427 n[i].style.backgroundColor = c;
\r
2428 tinyMCE.setAttrib(n[i], "bgcolor", "");
\r
2432 // Set these for performance
\r
2433 tinyMCE.cleanup_validElements = tinyMCE.settings['cleanup_validElements'];
\r
2434 tinyMCE.cleanup_invalidElements = tinyMCE.settings['cleanup_invalidElements'];
\r
2435 tinyMCE.cleanup_verify_html = tinyMCE.settings['verify_html'];
\r
2436 tinyMCE.cleanup_force_br_newlines = tinyMCE.settings['force_br_newlines'];
\r
2437 tinyMCE.cleanup_urlconverter_callback = tinyMCE.settings['urlconverter_callback'];
\r
2438 tinyMCE.cleanup_verify_css_classes = tinyMCE.settings['verify_css_classes'];
\r
2439 tinyMCE.cleanup_visual_table_class = tinyMCE.settings['visual_table_class'];
\r
2440 tinyMCE.cleanup_apply_source_formatting = tinyMCE.settings['apply_source_formatting'];
\r
2441 tinyMCE.cleanup_inline_styles = tinyMCE.settings['inline_styles'];
\r
2442 tinyMCE.cleanup_visual_aid = visual;
\r
2443 tinyMCE.cleanup_on_save = on_save;
\r
2444 tinyMCE.cleanup_idCount = 0;
\r
2445 tinyMCE.cleanup_elementLookupTable = new Array();
\r
2447 var startTime = new Date().getTime();
\r
2449 // Cleanup madness that breaks the editor in MSIE
\r
2450 if (tinyMCE.isMSIE) {
\r
2451 // Remove null ids from HR elements, results in runtime error
\r
2452 var nodes = element.getElementsByTagName("hr");
\r
2453 for (var i=0; i<nodes.length; i++) {
\r
2454 if (nodes[i].id == "null")
\r
2455 nodes[i].removeAttribute("id");
\r
2458 tinyMCE.setInnerHTML(element, tinyMCE.regexpReplace(element.innerHTML, '<p>[ \n\r]*<hr.*>[ \n\r]*</p>', '<hr />', 'gi'));
\r
2459 tinyMCE.setInnerHTML(element, tinyMCE.regexpReplace(element.innerHTML, '<!([^-(DOCTYPE)]* )|<!/[^-]*>', '', 'gi'));
\r
2462 var html = this.cleanupNode(element);
\r
2464 if (tinyMCE.settings['debug'])
\r
2465 tinyMCE.debug("Cleanup process executed in: " + (new Date().getTime()-startTime) + " ms.");
\r
2467 // Remove pesky HR paragraphs and other crap
\r
2468 html = tinyMCE.regexpReplace(html, '<p><hr /></p>', '<hr />');
\r
2469 html = tinyMCE.regexpReplace(html, '<p> </p><hr /><p> </p>', '<hr />');
\r
2470 html = tinyMCE.regexpReplace(html, '<td>\\s*<br />\\s*</td>', '<td> </td>');
\r
2471 html = tinyMCE.regexpReplace(html, '<p>\\s*<br />\\s*</p>', '<p> </p>');
\r
2472 html = tinyMCE.regexpReplace(html, '<p>\\s* \\s*<br />\\s* \\s*</p>', '<p> </p>');
\r
2473 html = tinyMCE.regexpReplace(html, '<p>\\s* \\s*<br />\\s*</p>', '<p> </p>');
\r
2474 html = tinyMCE.regexpReplace(html, '<p>\\s*<br />\\s* \\s*</p>', '<p> </p>');
\r
2476 // Remove empty anchors
\r
2477 html = html.replace(new RegExp('<a>(.*?)</a>', 'gi'), '$1');
\r
2479 // Remove some mozilla crap
\r
2480 if (!tinyMCE.isMSIE)
\r
2481 html = html.replace(new RegExp('<o:p _moz-userdefined="" />', 'g'), "");
\r
2483 if (tinyMCE.settings['remove_linebreaks'])
\r
2484 html = html.replace(new RegExp('\r|\n', 'g'), ' ');
\r
2486 if (tinyMCE.getParam('apply_source_formatting')) {
\r
2487 html = html.replace(new RegExp('<(p|div)([^>]*)>', 'g'), "\n<$1$2>\n");
\r
2488 html = html.replace(new RegExp('<\/(p|div)([^>]*)>', 'g'), "\n</$1$2>\n");
\r
2489 html = html.replace(new RegExp('<br />', 'g'), "<br />\n");
\r
2492 if (tinyMCE.settings['force_br_newlines']) {
\r
2493 var re = new RegExp('<p> </p>', 'g');
\r
2494 html = html.replace(re, "<br />");
\r
2497 if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt']) {
\r
2498 // Remove weridness!
\r
2499 var re = new RegExp('<>', 'g');
\r
2500 html = html.replace(re, "");
\r
2503 // Call custom cleanup code
\r
2504 html = tinyMCE._customCleanup(inst, on_save ? "get_from_editor" : "insert_to_editor", html);
\r
2506 // Emtpy node, return empty
\r
2507 var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "").toLowerCase();
\r
2508 if (chk == "<br/>" || chk == "<br>" || chk == "<p> </p>" || chk == "<p> </p>" || chk == "<p></p>")
\r
2511 if (tinyMCE.settings["preformatted"])
\r
2512 return "<pre>" + html + "</pre>";
\r
2517 TinyMCE.prototype.insertLink = function(href, target, title, onclick, style_class) {
\r
2518 tinyMCE.execCommand('mceBeginUndoLevel');
\r
2520 if (this.selectedInstance && this.selectedElement && this.selectedElement.nodeName.toLowerCase() == "img") {
\r
2521 var doc = this.selectedInstance.getDoc();
\r
2522 var linkElement = tinyMCE.getParentElement(this.selectedElement, "a");
\r
2523 var newLink = false;
\r
2525 if (!linkElement) {
\r
2526 linkElement = doc.createElement("a");
\r
2531 var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, linkElement);");
\r
2532 mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
\r
2534 tinyMCE.setAttrib(linkElement, 'href', thref);
\r
2535 tinyMCE.setAttrib(linkElement, 'mce_href', mhref);
\r
2536 tinyMCE.setAttrib(linkElement, 'target', target);
\r
2537 tinyMCE.setAttrib(linkElement, 'title', title);
\r
2538 tinyMCE.setAttrib(linkElement, 'onclick', onclick);
\r
2539 tinyMCE.setAttrib(linkElement, 'class', style_class);
\r
2542 linkElement.appendChild(this.selectedElement.cloneNode(true));
\r
2543 this.selectedElement.parentNode.replaceChild(linkElement, this.selectedElement);
\r
2549 if (!this.linkElement && this.selectedInstance) {
\r
2550 if (tinyMCE.isSafari) {
\r
2551 tinyMCE.execCommand("mceInsertContent", false, '<a href="' + tinyMCE.uniqueURL + '">' + this.selectedInstance.getSelectedHTML() + '</a>');
\r
2553 this.selectedInstance.contentDocument.execCommand("createlink", false, tinyMCE.uniqueURL);
\r
2555 tinyMCE.linkElement = this.getElementByAttributeValue(this.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);
\r
2557 var elementArray = this.getElementsByAttributeValue(this.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);
\r
2559 for (var i=0; i<elementArray.length; i++) {
\r
2561 var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, elementArray[i]);");
\r
2562 mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
\r
2564 tinyMCE.setAttrib(elementArray[i], 'href', thref);
\r
2565 tinyMCE.setAttrib(elementArray[i], 'mce_href', mhref);
\r
2566 tinyMCE.setAttrib(elementArray[i], 'target', target);
\r
2567 tinyMCE.setAttrib(elementArray[i], 'title', title);
\r
2568 tinyMCE.setAttrib(elementArray[i], 'onclick', onclick);
\r
2569 tinyMCE.setAttrib(elementArray[i], 'class', style_class);
\r
2572 tinyMCE.linkElement = elementArray[0];
\r
2575 if (this.linkElement) {
\r
2577 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, this.linkElement);");
\r
2578 mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
\r
2580 tinyMCE.setAttrib(this.linkElement, 'href', href);
\r
2581 tinyMCE.setAttrib(this.linkElement, 'mce_href', mhref);
\r
2582 tinyMCE.setAttrib(this.linkElement, 'target', target);
\r
2583 tinyMCE.setAttrib(this.linkElement, 'title', title);
\r
2584 tinyMCE.setAttrib(this.linkElement, 'onclick', onclick);
\r
2585 tinyMCE.setAttrib(this.linkElement, 'class', style_class);
\r
2588 tinyMCE.execCommand('mceEndUndoLevel');
\r
2591 TinyMCE.prototype.insertImage = function(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout) {
\r
2592 tinyMCE.execCommand('mceBeginUndoLevel');
\r
2597 if (!this.imgElement && tinyMCE.isSafari) {
\r
2600 html += '<img src="' + src + '" alt="' + alt + '"';
\r
2601 html += ' border="' + border + '" hspace="' + hspace + '"';
\r
2602 html += ' vspace="' + vspace + '" width="' + width + '"';
\r
2603 html += ' height="' + height + '" align="' + align + '" title="' + title + '" onmouseover="' + onmouseover + '" onmouseout="' + onmouseout + '" />';
\r
2605 tinyMCE.execCommand("mceInsertContent", false, html);
\r
2607 if (!this.imgElement && this.selectedInstance) {
\r
2608 if (tinyMCE.isSafari)
\r
2609 tinyMCE.execCommand("mceInsertContent", false, '<img src="' + tinyMCE.uniqueURL + '" />');
\r
2611 this.selectedInstance.contentDocument.execCommand("insertimage", false, tinyMCE.uniqueURL);
\r
2613 tinyMCE.imgElement = this.getElementByAttributeValue(this.selectedInstance.contentDocument.body, "img", "src", tinyMCE.uniqueURL);
\r
2617 if (this.imgElement) {
\r
2618 var needsRepaint = false;
\r
2621 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, tinyMCE.imgElement);");
\r
2623 if (tinyMCE.getParam('convert_urls'))
\r
2626 if (onmouseover && onmouseover != "")
\r
2627 onmouseover = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, tinyMCE.imgElement);") + "';";
\r
2629 if (onmouseout && onmouseout != "")
\r
2630 onmouseout = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, tinyMCE.imgElement);") + "';";
\r
2632 // Use alt as title if it's undefined
\r
2633 if (typeof(title) == "undefined")
\r
2636 if (width != this.imgElement.getAttribute("width") || height != this.imgElement.getAttribute("height") || align != this.imgElement.getAttribute("align"))
\r
2637 needsRepaint = true;
\r
2639 tinyMCE.setAttrib(this.imgElement, 'src', src);
\r
2640 tinyMCE.setAttrib(this.imgElement, 'mce_src', msrc);
\r
2641 tinyMCE.setAttrib(this.imgElement, 'alt', alt);
\r
2642 tinyMCE.setAttrib(this.imgElement, 'title', title);
\r
2643 tinyMCE.setAttrib(this.imgElement, 'align', align);
\r
2644 tinyMCE.setAttrib(this.imgElement, 'border', border, true);
\r
2645 tinyMCE.setAttrib(this.imgElement, 'hspace', hspace, true);
\r
2646 tinyMCE.setAttrib(this.imgElement, 'vspace', vspace, true);
\r
2647 tinyMCE.setAttrib(this.imgElement, 'width', width, true);
\r
2648 tinyMCE.setAttrib(this.imgElement, 'height', height, true);
\r
2649 tinyMCE.setAttrib(this.imgElement, 'onmouseover', onmouseover);
\r
2650 tinyMCE.setAttrib(this.imgElement, 'onmouseout', onmouseout);
\r
2652 // Fix for bug #989846 - Image resize bug
\r
2653 if (width && width != "")
\r
2654 this.imgElement.style.pixelWidth = width;
\r
2656 if (height && height != "")
\r
2657 this.imgElement.style.pixelHeight = height;
\r
2660 tinyMCE.selectedInstance.repaint();
\r
2663 tinyMCE.execCommand('mceEndUndoLevel');
\r
2666 TinyMCE.prototype.getElementByAttributeValue = function(node, element_name, attrib, value) {
\r
2667 var elements = this.getElementsByAttributeValue(node, element_name, attrib, value);
\r
2668 if (elements.length == 0)
\r
2671 return elements[0];
\r
2674 TinyMCE.prototype.getElementsByAttributeValue = function(node, element_name, attrib, value) {
\r
2675 var elements = new Array();
\r
2677 if (node && node.nodeName.toLowerCase() == element_name) {
\r
2678 if (node.getAttribute(attrib) && node.getAttribute(attrib).indexOf(value) != -1)
\r
2679 elements[elements.length] = node;
\r
2682 if (node && node.hasChildNodes()) {
\r
2683 for (var x=0, n=node.childNodes.length; x<n; x++) {
\r
2684 var childElements = this.getElementsByAttributeValue(node.childNodes[x], element_name, attrib, value);
\r
2685 for (var i=0, m=childElements.length; i<m; i++)
\r
2686 elements[elements.length] = childElements[i];
\r
2693 TinyMCE.prototype.isBlockElement = function(node) {
\r
2694 return node != null && node.nodeType == 1 && this.blockRegExp.test(node.nodeName);
\r
2697 TinyMCE.prototype.getParentBlockElement = function(node) {
\r
2698 // Search up the tree for block element
\r
2700 if (this.blockRegExp.test(node.nodeName))
\r
2703 node = node.parentNode;
\r
2709 TinyMCE.prototype.getNodeTree = function(node, node_array, type, node_name) {
\r
2710 if (typeof(type) == "undefined" || node.nodeType == type && (typeof(node_name) == "undefined" || node.nodeName == node_name))
\r
2711 node_array[node_array.length] = node;
\r
2713 if (node.hasChildNodes()) {
\r
2714 for (var i=0; i<node.childNodes.length; i++)
\r
2715 tinyMCE.getNodeTree(node.childNodes[i], node_array, type, node_name);
\r
2718 return node_array;
\r
2721 TinyMCE.prototype.getParentElement = function(node, names, attrib_name, attrib_value) {
\r
2722 if (typeof(names) == "undefined") {
\r
2723 if (node.nodeType == 1)
\r
2726 // Find parent node that is a element
\r
2727 while ((node = node.parentNode) != null && node.nodeType != 1) ;
\r
2732 var namesAr = names.split(',');
\r
2738 for (var i=0; i<namesAr.length; i++) {
\r
2739 if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() || names == "*") {
\r
2740 if (typeof(attrib_name) == "undefined")
\r
2742 else if (node.getAttribute(attrib_name)) {
\r
2743 if (typeof(attrib_value) == "undefined") {
\r
2744 if (node.getAttribute(attrib_name) != "")
\r
2746 } else if (node.getAttribute(attrib_name) == attrib_value)
\r
2751 } while ((node = node.parentNode) != null);
\r
2756 TinyMCE.prototype.convertURL = function(url, node, on_save) {
\r
2757 var prot = document.location.protocol;
\r
2758 var host = document.location.hostname;
\r
2759 var port = document.location.port;
\r
2761 // Pass through file protocol
\r
2762 if (prot == "file:")
\r
2765 // Something is wrong, remove weirdness
\r
2766 url = tinyMCE.regexpReplace(url, '(http|https):///', '/');
\r
2768 // Mailto link or anchor (Pass through)
\r
2769 if (url.indexOf('mailto:') != -1 || url.indexOf('javascript:') != -1 || tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0) == "#")
\r
2772 // Fix relative/Mozilla
\r
2773 if (!tinyMCE.isMSIE && !on_save && url.indexOf("://") == -1 && url.charAt(0) != '/')
\r
2774 return tinyMCE.settings['base_href'] + url;
\r
2776 // Handle relative URLs
\r
2777 if (on_save && tinyMCE.getParam('relative_urls')) {
\r
2778 var curl = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
\r
2779 if (curl.charAt(0) == '/')
\r
2780 curl = tinyMCE.settings['document_base_prefix'] + curl;
\r
2782 var urlParts = tinyMCE.parseURL(curl);
\r
2783 var tmpUrlParts = tinyMCE.parseURL(tinyMCE.settings['document_base_url']);
\r
2786 if (urlParts['host'] == tmpUrlParts['host'] && (urlParts['port'] == tmpUrlParts['port']))
\r
2787 return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'], curl);
\r
2790 // Handle absolute URLs
\r
2791 if (!tinyMCE.getParam('relative_urls')) {
\r
2792 var urlParts = tinyMCE.parseURL(url);
\r
2793 var baseUrlParts = tinyMCE.parseURL(tinyMCE.settings['base_href']);
\r
2795 // Force absolute URLs from relative URLs
\r
2796 url = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
\r
2798 // If anchor and path is the same page
\r
2799 if (urlParts['anchor'] && urlParts['path'] == baseUrlParts['path'])
\r
2800 return "#" + urlParts['anchor'];
\r
2803 // Remove current domain
\r
2804 if (tinyMCE.getParam('remove_script_host')) {
\r
2805 var start = "", portPart = "";
\r
2808 portPart = ":" + port;
\r
2810 start = prot + "//" + host + portPart + "/";
\r
2812 if (url.indexOf(start) == 0)
\r
2813 url = url.substring(start.length-1);
\r
2820 * Parses a URL in to its diffrent components.
\r
2822 TinyMCE.prototype.parseURL = function(url_str) {
\r
2823 var urlParts = new Array();
\r
2828 // Parse protocol part
\r
2829 pos = url_str.indexOf('://');
\r
2831 urlParts['protocol'] = url_str.substring(0, pos);
\r
2832 lastPos = pos + 3;
\r
2835 // Find port or path start
\r
2836 for (var i=lastPos; i<url_str.length; i++) {
\r
2837 var chr = url_str.charAt(i);
\r
2848 urlParts['host'] = url_str.substring(lastPos, pos);
\r
2851 urlParts['port'] = "";
\r
2853 if (url_str.charAt(pos) == ':') {
\r
2854 pos = url_str.indexOf('/', lastPos);
\r
2855 urlParts['port'] = url_str.substring(lastPos+1, pos);
\r
2860 pos = url_str.indexOf('?', lastPos);
\r
2863 pos = url_str.indexOf('#', lastPos);
\r
2866 pos = url_str.length;
\r
2868 urlParts['path'] = url_str.substring(lastPos, pos);
\r
2872 if (url_str.charAt(pos) == '?') {
\r
2873 pos = url_str.indexOf('#');
\r
2874 pos = (pos == -1) ? url_str.length : pos;
\r
2875 urlParts['query'] = url_str.substring(lastPos+1, pos);
\r
2880 if (url_str.charAt(pos) == '#') {
\r
2881 pos = url_str.length;
\r
2882 urlParts['anchor'] = url_str.substring(lastPos+1, pos);
\r
2889 TinyMCE.prototype.serializeURL = function(up) {
\r
2892 if (up['protocol'])
\r
2893 url += up['protocol'] + "://";
\r
2896 url += up['host'];
\r
2899 url += ":" + up['port'];
\r
2902 url += up['path'];
\r
2905 url += "?" + up['query'];
\r
2908 url += "#" + up['anchor'];
\r
2914 * Converts an absolute path to relative path.
\r
2916 TinyMCE.prototype.convertAbsoluteURLToRelativeURL = function(base_url, url_to_relative) {
\r
2917 var baseURL = this.parseURL(base_url);
\r
2918 var targetURL = this.parseURL(url_to_relative);
\r
2921 var breakPoint = 0;
\r
2923 var forceSlash = false;
\r
2925 if (targetURL.path == "")
\r
2926 targetURL.path = "/";
\r
2928 forceSlash = true;
\r
2930 // Crop away last path part
\r
2931 base_url = baseURL.path.substring(0, baseURL.path.lastIndexOf('/'));
\r
2932 strTok1 = base_url.split('/');
\r
2933 strTok2 = targetURL.path.split('/');
\r
2935 if (strTok1.length >= strTok2.length) {
\r
2936 for (var i=0; i<strTok1.length; i++) {
\r
2937 if (i >= strTok2.length || strTok1[i] != strTok2[i]) {
\r
2938 breakPoint = i + 1;
\r
2944 if (strTok1.length < strTok2.length) {
\r
2945 for (var i=0; i<strTok2.length; i++) {
\r
2946 if (i >= strTok1.length || strTok1[i] != strTok2[i]) {
\r
2947 breakPoint = i + 1;
\r
2953 if (breakPoint == 1)
\r
2954 return targetURL.path;
\r
2956 for (var i=0; i<(strTok1.length-(breakPoint-1)); i++)
\r
2959 for (var i=breakPoint-1; i<strTok2.length; i++) {
\r
2960 if (i != (breakPoint-1))
\r
2961 outPath += "/" + strTok2[i];
\r
2963 outPath += strTok2[i];
\r
2966 targetURL.protocol = null;
\r
2967 targetURL.host = null;
\r
2968 targetURL.port = null;
\r
2969 targetURL.path = outPath == "" && forceSlash ? "/" : outPath;
\r
2971 // Remove document prefix from local anchors
\r
2972 var fileName = baseURL.path;
\r
2975 if ((pos = fileName.lastIndexOf('/')) != -1)
\r
2976 fileName = fileName.substring(pos + 1);
\r
2978 // Is local anchor
\r
2979 if (fileName == targetURL.path && targetURL.anchor != "")
\r
2980 targetURL.path = "";
\r
2982 return this.serializeURL(targetURL);
\r
2985 TinyMCE.prototype.convertRelativeToAbsoluteURL = function(base_url, relative_url) {
\r
2986 var baseURL = TinyMCE.prototype.parseURL(base_url);
\r
2987 var relURL = TinyMCE.prototype.parseURL(relative_url);
\r
2989 if (relative_url == "" || relative_url.charAt(0) == '/' || relative_url.indexOf('://') != -1 || relative_url.indexOf('mailto:') != -1 || relative_url.indexOf('javascript:') != -1)
\r
2990 return relative_url;
\r
2993 baseURLParts = baseURL['path'].split('/');
\r
2994 relURLParts = relURL['path'].split('/');
\r
2996 // Remove empty chunks
\r
2997 var newBaseURLParts = new Array();
\r
2998 for (var i=baseURLParts.length-1; i>=0; i--) {
\r
2999 if (baseURLParts[i].length == 0)
\r
3002 newBaseURLParts[newBaseURLParts.length] = baseURLParts[i];
\r
3004 baseURLParts = newBaseURLParts.reverse();
\r
3006 // Merge relURLParts chunks
\r
3007 var newRelURLParts = new Array();
\r
3009 for (var i=relURLParts.length-1; i>=0; i--) {
\r
3010 if (relURLParts[i].length == 0 || relURLParts[i] == ".")
\r
3013 if (relURLParts[i] == '..') {
\r
3018 if (numBack > 0) {
\r
3023 newRelURLParts[newRelURLParts.length] = relURLParts[i];
\r
3026 relURLParts = newRelURLParts.reverse();
\r
3028 // Remove end from absolute path
\r
3029 var len = baseURLParts.length-numBack;
\r
3030 var absPath = (len <= 0 ? "" : "/") + baseURLParts.slice(0, len).join('/') + "/" + relURLParts.join('/');
\r
3031 var start = "", end = "";
\r
3033 // Build output URL
\r
3034 relURL.protocol = baseURL.protocol;
\r
3035 relURL.host = baseURL.host;
\r
3036 relURL.port = baseURL.port;
\r
3038 // Re-add trailing slash if it's removed
\r
3039 if (relURL.path.charAt(relURL.path.length-1) == "/")
\r
3042 relURL.path = absPath;
\r
3044 return TinyMCE.prototype.serializeURL(relURL);
\r
3047 TinyMCE.prototype.getParam = function(name, default_value, strip_whitespace, split_chr) {
\r
3048 var value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
\r
3050 // Fix bool values
\r
3051 if (value == "true" || value == "false")
\r
3052 return (value == "true");
\r
3054 if (strip_whitespace)
\r
3055 value = tinyMCE.regexpReplace(value, "[ \t\r\n]", "");
\r
3057 if (typeof(split_chr) != "undefined" && split_chr != null) {
\r
3058 value = value.split(split_chr);
\r
3059 var outArray = new Array();
\r
3061 for (var i=0; i<value.length; i++) {
\r
3062 if (value[i] && value[i] != "")
\r
3063 outArray[outArray.length] = value[i];
\r
3072 TinyMCE.prototype.getLang = function(name, default_value, parse_entities) {
\r
3073 var value = (typeof(tinyMCELang[name]) == "undefined") ? default_value : tinyMCELang[name];
\r
3075 if (parse_entities)
\r
3076 value = tinyMCE.entityDecode(value);
\r
3081 TinyMCE.prototype.entityDecode = function(s) {
\r
3082 var e = document.createElement("div");
\r
3084 return e.innerHTML;
\r
3087 TinyMCE.prototype.addToLang = function(prefix, ar) {
\r
3088 for (var key in ar) {
\r
3089 if (typeof(ar[key]) == 'function')
\r
3092 tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = ar[key];
\r
3095 // for (var key in ar)
\r
3096 // tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = "|" + ar[key] + "|";
\r
3099 TinyMCE.prototype.replaceVar = function(replace_haystack, replace_var, replace_str) {
\r
3100 var re = new RegExp('{\\\$' + replace_var + '}', 'g');
\r
3101 return replace_haystack.replace(re, replace_str);
\r
3104 TinyMCE.prototype.replaceVars = function(replace_haystack, replace_vars) {
\r
3105 for (var key in replace_vars) {
\r
3106 var value = replace_vars[key];
\r
3107 if (typeof(value) == 'function')
\r
3110 replace_haystack = tinyMCE.replaceVar(replace_haystack, key, value);
\r
3113 return replace_haystack;
\r
3116 TinyMCE.prototype.triggerNodeChange = function(focus, setup_content) {
\r
3117 if (tinyMCE.settings['handleNodeChangeCallback']) {
\r
3118 if (tinyMCE.selectedInstance) {
\r
3119 var inst = tinyMCE.selectedInstance;
\r
3120 var editorId = inst.editorId;
\r
3121 var elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement();
\r
3122 var undoIndex = -1;
\r
3123 var undoLevels = -1;
\r
3124 var anySelection = false;
\r
3125 var selectedText = inst.getSelectedText();
\r
3127 inst.switchSettings();
\r
3129 if (tinyMCE.settings["auto_resize"]) {
\r
3130 var doc = inst.getDoc();
\r
3132 inst.iframeElement.style.width = doc.body.offsetWidth + "px";
\r
3133 inst.iframeElement.style.height = doc.body.offsetHeight + "px";
\r
3136 if (tinyMCE.selectedElement)
\r
3137 anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (selectedText && selectedText.length > 0);
\r
3139 if (tinyMCE.settings['custom_undo_redo']) {
\r
3140 undoIndex = inst.undoIndex;
\r
3141 undoLevels = inst.undoLevels.length;
\r
3144 tinyMCE.executeCallback('handleNodeChangeCallback', '_handleNodeChange', 0, editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content);
\r
3148 if (this.selectedInstance && (typeof(focus) == "undefined" || focus))
\r
3149 this.selectedInstance.contentWindow.focus();
\r
3152 TinyMCE.prototype._customCleanup = function(inst, type, content) {
\r
3153 // Call custom cleanup
\r
3154 var customCleanup = tinyMCE.settings['cleanup_callback'];
\r
3155 if (customCleanup != "" && eval("typeof(" + customCleanup + ")") != "undefined")
\r
3156 content = eval(customCleanup + "(type, content, inst);");
\r
3158 // Trigger plugin cleanups
\r
3159 var plugins = tinyMCE.getParam('plugins', '', true, ',');
\r
3160 for (var i=0; i<plugins.length; i++) {
\r
3161 if (eval("typeof(TinyMCE_" + plugins[i] + "_cleanup)") != "undefined")
\r
3162 content = eval("TinyMCE_" + plugins[i] + "_cleanup(type, content, inst);");
\r
3168 TinyMCE.prototype.getContent = function(editor_id) {
\r
3169 if (typeof(editor_id) != "undefined")
\r
3170 tinyMCE.selectedInstance = tinyMCE.getInstanceById(editor_id);
\r
3172 if (tinyMCE.selectedInstance) {
\r
3173 var old = this.selectedInstance.getBody().innerHTML;
\r
3174 var html = tinyMCE._cleanupHTML(this.selectedInstance, this.selectedInstance.getDoc(), tinyMCE.settings, this.selectedInstance.getBody(), false, true);
\r
3175 tinyMCE.setInnerHTML(this.selectedInstance.getBody(), old);
\r
3182 TinyMCE.prototype.setContent = function(html_content) {
\r
3183 if (tinyMCE.selectedInstance) {
\r
3184 tinyMCE.selectedInstance.execCommand('mceSetContent', false, html_content);
\r
3185 tinyMCE.selectedInstance.repaint();
\r
3189 TinyMCE.prototype.importThemeLanguagePack = function(name) {
\r
3190 if (typeof(name) == "undefined")
\r
3191 name = tinyMCE.settings['theme'];
\r
3193 tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings['language'] + '.js');
\r
3196 TinyMCE.prototype.importPluginLanguagePack = function(name, valid_languages) {
\r
3199 valid_languages = valid_languages.split(',');
\r
3200 for (var i=0; i<valid_languages.length; i++) {
\r
3201 if (tinyMCE.settings['language'] == valid_languages[i])
\r
3202 lang = tinyMCE.settings['language'];
\r
3205 tinyMCE.loadScript(tinyMCE.baseURL + '/plugins/' + name + '/langs/' + lang + '.js');
\r
3209 * Adds themeurl, settings and lang to HTML code.
\r
3211 TinyMCE.prototype.applyTemplate = function(html, args) {
\r
3212 html = tinyMCE.replaceVar(html, "themeurl", tinyMCE.themeURL);
\r
3214 if (typeof(args) != "undefined")
\r
3215 html = tinyMCE.replaceVars(html, args);
\r
3217 html = tinyMCE.replaceVars(html, tinyMCE.settings);
\r
3218 html = tinyMCE.replaceVars(html, tinyMCELang);
\r
3223 TinyMCE.prototype.openWindow = function(template, args) {
\r
3224 var html, width, height, x, y, resizable, scrollbars, url;
\r
3226 args['mce_template_file'] = template['file'];
\r
3227 args['mce_width'] = template['width'];
\r
3228 args['mce_height'] = template['height'];
\r
3229 tinyMCE.windowArgs = args;
\r
3231 html = template['html'];
\r
3232 if (!(width = parseInt(template['width'])))
\r
3235 if (!(height = parseInt(template['height'])))
\r
3238 // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
\r
3239 if (tinyMCE.isMSIE)
\r
3244 x = parseInt(screen.width / 2.0) - (width / 2.0);
\r
3245 y = parseInt(screen.height / 2.0) - (height / 2.0);
\r
3247 resizable = (args && args['resizable']) ? args['resizable'] : "no";
\r
3248 scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";
\r
3250 if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)
\r
3251 url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];
\r
3253 url = template['file'];
\r
3255 // Replace all args as variables in URL
\r
3256 for (var name in args) {
\r
3257 if (typeof(args[name]) == 'function')
\r
3260 url = tinyMCE.replaceVar(url, name, escape(args[name]));
\r
3264 html = tinyMCE.replaceVar(html, "css", this.settings['popups_css']);
\r
3265 html = tinyMCE.applyTemplate(html, args);
\r
3267 var win = window.open("", "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=yes,minimizable=" + resizable + ",modal=yes,width=" + width + ",height=" + height + ",resizable=" + resizable);
\r
3268 if (win == null) {
\r
3269 alert(tinyMCELang['lang_popup_blocked']);
\r
3273 win.document.write(html);
\r
3274 win.document.close();
\r
3275 win.resizeTo(width, height);
\r
3278 if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && resizable != 'yes' && tinyMCE.settings["dialog_type"] == "modal") {
\r
3279 var features = "resizable:" + resizable
\r
3281 + scrollbars + ";status:yes;center:yes;help:no;dialogWidth:"
\r
3282 + width + "px;dialogHeight:" + height + "px;";
\r
3284 window.showModalDialog(url, window, features);
\r
3286 var modal = (resizable == "yes") ? "no" : "yes";
\r
3288 if (tinyMCE.isGecko && tinyMCE.isMac)
\r
3291 if (template['close_previous'] != "no")
\r
3292 try {tinyMCE.lastWindow.close();} catch (ex) {}
\r
3294 var win = window.open(url, "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable);
\r
3295 if (win == null) {
\r
3296 alert(tinyMCELang['lang_popup_blocked']);
\r
3300 if (template['close_previous'] != "no")
\r
3301 tinyMCE.lastWindow = win;
\r
3303 eval('try { win.resizeTo(width, height); } catch(e) { }');
\r
3305 // Make it bigger if statusbar is forced
\r
3306 if (tinyMCE.isGecko) {
\r
3307 if (win.document.defaultView.statusbar.visible)
\r
3308 win.resizeBy(0, tinyMCE.isMac ? 10 : 24);
\r
3316 TinyMCE.prototype.closeWindow = function(win) {
\r
3320 TinyMCE.prototype.getVisualAidClass = function(class_name, state) {
\r
3321 var aidClass = tinyMCE.settings['visual_table_class'];
\r
3323 if (typeof(state) == "undefined")
\r
3324 state = tinyMCE.settings['visual'];
\r
3327 var classNames = new Array();
\r
3328 var ar = class_name.split(' ');
\r
3329 for (var i=0; i<ar.length; i++) {
\r
3330 if (ar[i] == aidClass)
\r
3334 classNames[classNames.length] = ar[i];
\r
3338 classNames[classNames.length] = aidClass;
\r
3341 var className = "";
\r
3342 for (var i=0; i<classNames.length; i++) {
\r
3346 className += classNames[i];
\r
3352 TinyMCE.prototype.handleVisualAid = function(el, deep, state, inst) {
\r
3356 var tableElement = null;
\r
3358 switch (el.nodeName) {
\r
3360 var oldW = el.style.width;
\r
3361 var oldH = el.style.height;
\r
3362 var bo = tinyMCE.getAttrib(el, "border");
\r
3364 bo = bo == "" || bo == "0" ? true : false;
\r
3366 tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo));
\r
3368 el.style.width = oldW;
\r
3369 el.style.height = oldH;
\r
3371 for (var y=0; y<el.rows.length; y++) {
\r
3372 for (var x=0; x<el.rows[y].cells.length; x++) {
\r
3373 var cn = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x], "class"), state && bo);
\r
3374 tinyMCE.setAttrib(el.rows[y].cells[x], "class", cn);
\r
3381 var anchorName = tinyMCE.getAttrib(el, "name");
\r
3383 if (anchorName != '' && state) {
\r
3384 el.title = anchorName;
\r
3385 el.className = 'mceItemAnchor';
\r
3386 } else if (anchorName != '' && !state)
\r
3387 el.className = '';
\r
3392 if (deep && el.hasChildNodes()) {
\r
3393 for (var i=0; i<el.childNodes.length; i++)
\r
3394 tinyMCE.handleVisualAid(el.childNodes[i], deep, state, inst);
\r
3398 TinyMCE.prototype.getAttrib = function(elm, name, default_value) {
\r
3399 if (typeof(default_value) == "undefined")
\r
3400 default_value = "";
\r
3403 if (!elm || elm.nodeType != 1)
\r
3404 return default_value;
\r
3406 var v = elm.getAttribute(name);
\r
3408 // Try className for class attrib
\r
3409 if (name == "class" && !v)
\r
3410 v = elm.className;
\r
3412 // Workaround for a issue with Firefox 1.5rc2+
\r
3413 if (tinyMCE.isGecko && name == "src" && elm.src != null && elm.src != "")
\r
3416 // Workaround for a issue with Firefox 1.5rc2+
\r
3417 if (tinyMCE.isGecko && name == "href" && elm.href != null && elm.href != "")
\r
3420 if (name == "style" && !tinyMCE.isOpera)
\r
3421 v = elm.style.cssText;
\r
3423 return (v && v != "") ? v : default_value;
\r
3426 TinyMCE.prototype.setAttrib = function(element, name, value, fix_value) {
\r
3427 if (typeof(value) == "number" && value != null)
\r
3428 value = "" + value;
\r
3431 if (value == null)
\r
3434 var re = new RegExp('[^0-9%]', 'g');
\r
3435 value = value.replace(re, '');
\r
3438 if (name == "style")
\r
3439 element.style.cssText = value;
\r
3441 if (name == "class")
\r
3442 element.className = value;
\r
3444 if (value != null && value != "" && value != -1)
\r
3445 element.setAttribute(name, value);
\r
3447 element.removeAttribute(name);
\r
3450 TinyMCE.prototype.setStyleAttrib = function(elm, name, value) {
\r
3451 eval('elm.style.' + name + '=value;');
\r
3453 // Style attrib deleted
\r
3454 if (tinyMCE.isMSIE && value == null || value == '') {
\r
3455 var str = tinyMCE.serializeStyle(tinyMCE.parseStyle(elm.style.cssText));
\r
3456 elm.style.cssText = str;
\r
3457 elm.setAttribute("style", str);
\r
3461 TinyMCE.prototype.convertSpansToFonts = function(doc) {
\r
3462 var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
\r
3464 var h = doc.body.innerHTML;
\r
3465 h = h.replace(/<span/gi, '<font');
\r
3466 h = h.replace(/<\/span/gi, '</font');
\r
3467 doc.body.innerHTML = h;
\r
3469 var s = doc.getElementsByTagName("font");
\r
3470 for (var i=0; i<s.length; i++) {
\r
3471 var size = tinyMCE.trim(s[i].style.fontSize).toLowerCase();
\r
3474 for (var x=0; x<sizes.length; x++) {
\r
3475 if (sizes[x] == size) {
\r
3482 tinyMCE.setAttrib(s[i], 'size', fSize);
\r
3483 s[i].style.fontSize = '';
\r
3486 var fFace = s[i].style.fontFamily;
\r
3487 if (fFace != null && fFace != "") {
\r
3488 tinyMCE.setAttrib(s[i], 'face', fFace);
\r
3489 s[i].style.fontFamily = '';
\r
3492 var fColor = s[i].style.color;
\r
3493 if (fColor != null && fColor != "") {
\r
3494 tinyMCE.setAttrib(s[i], 'color', tinyMCE.convertRGBToHex(fColor));
\r
3495 s[i].style.color = '';
\r
3500 TinyMCE.prototype.convertFontsToSpans = function(doc) {
\r
3501 var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
\r
3503 var h = doc.body.innerHTML;
\r
3504 h = h.replace(/<font/gi, '<span');
\r
3505 h = h.replace(/<\/font/gi, '</span');
\r
3506 doc.body.innerHTML = h;
\r
3508 var fsClasses = tinyMCE.getParam('font_size_classes');
\r
3509 if (fsClasses != '')
\r
3510 fsClasses = fsClasses.replace(/\s+/, '').split(',');
\r
3514 var s = doc.getElementsByTagName("span");
\r
3515 for (var i=0; i<s.length; i++) {
\r
3516 var fSize, fFace, fColor;
\r
3518 fSize = tinyMCE.getAttrib(s[i], 'size');
\r
3519 fFace = tinyMCE.getAttrib(s[i], 'face');
\r
3520 fColor = tinyMCE.getAttrib(s[i], 'color');
\r
3522 if (fSize != "") {
\r
3523 fSize = parseInt(fSize);
\r
3525 if (fSize > 0 && fSize < 8) {
\r
3526 if (fsClasses != null)
\r
3527 tinyMCE.setAttrib(s[i], 'class', fsClasses[fSize-1]);
\r
3529 s[i].style.fontSize = sizes[fSize-1];
\r
3532 s[i].removeAttribute('size');
\r
3535 if (fFace != "") {
\r
3536 s[i].style.fontFamily = fFace;
\r
3537 s[i].removeAttribute('face');
\r
3540 if (fColor != "") {
\r
3541 s[i].style.color = fColor;
\r
3542 s[i].removeAttribute('color');
\r
3548 TinyMCE.prototype.applyClassesToFonts = function(doc, size) {
\r
3549 var f = doc.getElementsByTagName("font");
\r
3550 for (var i=0; i<f.length; i++) {
\r
3551 var s = tinyMCE.getAttrib(f[i], "size");
\r
3554 tinyMCE.setAttrib(f[i], 'class', "mceItemFont" + s);
\r
3557 if (typeof(size) != "undefined") {
\r
3560 for (var x=0; x<doc.styleSheets.length; x++) {
\r
3561 for (var i=0; i<doc.styleSheets[x].rules.length; i++) {
\r
3562 if (doc.styleSheets[x].rules[i].selectorText == '#mceSpanFonts .mceItemFont' + size) {
\r
3563 css = doc.styleSheets[x].rules[i].style.cssText;
\r
3572 if (doc.styleSheets[0].rules[0].selectorText == "FONT")
\r
3573 doc.styleSheets[0].removeRule(0);
\r
3575 doc.styleSheets[0].addRule("FONT", css, 0);
\r
3580 TinyMCE.prototype.setInnerHTML = function(e, h) {
\r
3581 if (tinyMCE.isMSIE && !tinyMCE.isOpera) {
\r
3582 e.innerHTML = tinyMCE.uniqueTag + h;
\r
3583 e.firstChild.removeNode(true);
\r
3585 h = this.fixGeckoBaseHREFBug(1, e, h);
\r
3587 this.fixGeckoBaseHREFBug(2, e, h);
\r
3591 TinyMCE.prototype.fixGeckoBaseHREFBug = function(m, e, h) {
\r
3592 if (tinyMCE.isGecko) {
\r
3594 h = h.replace(/\ssrc=/gi, " xsrc=");
\r
3595 h = h.replace(/\shref=/gi, " xhref=");
\r
3599 if (h.indexOf(' xsrc') != -1) {
\r
3600 var n = e.getElementsByTagName("img");
\r
3601 for (var i=0; i<n.length; i++) {
\r
3602 var xsrc = tinyMCE.getAttrib(n[i], "xsrc");
\r
3605 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
\r
3606 n[i].removeAttribute("xsrc");
\r
3610 // Select image form fields
\r
3611 var n = e.getElementsByTagName("select");
\r
3612 for (var i=0; i<n.length; i++) {
\r
3613 var xsrc = tinyMCE.getAttrib(n[i], "xsrc");
\r
3616 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
\r
3617 n[i].removeAttribute("xsrc");
\r
3622 var n = e.getElementsByTagName("iframe");
\r
3623 for (var i=0; i<n.length; i++) {
\r
3624 var xsrc = tinyMCE.getAttrib(n[i], "xsrc");
\r
3627 n[i].src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
\r
3628 n[i].removeAttribute("xsrc");
\r
3633 if (h.indexOf(' xhref') != -1) {
\r
3634 var n = e.getElementsByTagName("a");
\r
3635 for (var i=0; i<n.length; i++) {
\r
3636 var xhref = tinyMCE.getAttrib(n[i], "xhref");
\r
3638 if (xhref != "") {
\r
3639 n[i].href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xhref);
\r
3640 n[i].removeAttribute("xhref");
\r
3650 TinyMCE.prototype.getOuterHTML = function(e) {
\r
3651 if (tinyMCE.isMSIE)
\r
3652 return e.outerHTML;
\r
3654 var d = e.ownerDocument.createElement("body");
\r
3656 return d.innerHTML;
\r
3659 TinyMCE.prototype.setOuterHTML = function(doc, e, h) {
\r
3660 if (tinyMCE.isMSIE) {
\r
3665 var d = e.ownerDocument.createElement("body");
\r
3667 e.parentNode.replaceChild(d.firstChild, e);
\r
3670 TinyMCE.prototype.insertAfter = function(nc, rc){
\r
3671 if (rc.nextSibling)
\r
3672 rc.parentNode.insertBefore(nc, rc.nextSibling);
\r
3674 rc.parentNode.appendChild(nc);
\r
3677 TinyMCE.prototype.cleanupAnchors = function(doc) {
\r
3678 var an = doc.getElementsByTagName("a");
\r
3680 for (var i=0; i<an.length; i++) {
\r
3681 if (tinyMCE.getAttrib(an[i], "name") != "") {
\r
3682 var cn = an[i].childNodes;
\r
3683 for (var x=cn.length-1; x>=0; x--)
\r
3684 tinyMCE.insertAfter(cn[x], an[i]);
\r
3689 TinyMCE.prototype._setHTML = function(doc, html_content) {
\r
3690 // Force closed anchors open
\r
3691 //html_content = html_content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
\r
3693 html_content = tinyMCE.cleanupHTMLCode(html_content);
\r
3695 // Try innerHTML if it fails use pasteHTML in MSIE
\r
3697 tinyMCE.setInnerHTML(doc.body, html_content);
\r
3700 doc.body.createTextRange().pasteHTML(html_content);
\r
3703 // Content duplication bug fix
\r
3704 if (tinyMCE.isMSIE && tinyMCE.settings['fix_content_duplication']) {
\r
3705 // Remove P elements in P elements
\r
3706 var paras = doc.getElementsByTagName("P");
\r
3707 for (var i=0; i<paras.length; i++) {
\r
3708 var node = paras[i];
\r
3709 while ((node = node.parentNode) != null) {
\r
3710 if (node.nodeName == "P")
\r
3711 node.outerHTML = node.innerHTML;
\r
3715 // Content duplication bug fix (Seems to be word crap)
\r
3716 var html = doc.body.innerHTML;
\r
3718 if (html.indexOf('="mso') != -1) {
\r
3719 for (var i=0; i<doc.body.all.length; i++) {
\r
3720 var el = doc.body.all[i];
\r
3721 el.removeAttribute("className","",0);
\r
3722 el.removeAttribute("style","",0);
\r
3725 html = doc.body.innerHTML;
\r
3726 html = tinyMCE.regexpReplace(html, "<o:p><\/o:p>", "<br />");
\r
3727 html = tinyMCE.regexpReplace(html, "<o:p> <\/o:p>", "");
\r
3728 html = tinyMCE.regexpReplace(html, "<st1:.*?>", "");
\r
3729 html = tinyMCE.regexpReplace(html, "<p><\/p>", "");
\r
3730 html = tinyMCE.regexpReplace(html, "<p><\/p>\r\n<p><\/p>", "");
\r
3731 html = tinyMCE.regexpReplace(html, "<p> <\/p>", "<br />");
\r
3732 html = tinyMCE.regexpReplace(html, "<p>\s*(<p>\s*)?", "<p>");
\r
3733 html = tinyMCE.regexpReplace(html, "<\/p>\s*(<\/p>\s*)?", "</p>");
\r
3736 // Always set the htmlText output
\r
3737 tinyMCE.setInnerHTML(doc.body, html);
\r
3740 tinyMCE.cleanupAnchors(doc);
\r
3742 if (tinyMCE.getParam("convert_fonts_to_spans"))
\r
3743 tinyMCE.convertSpansToFonts(doc);
\r
3746 TinyMCE.prototype.getImageSrc = function(str) {
\r
3752 if ((pos = str.indexOf('this.src=')) != -1) {
\r
3753 var src = str.substring(pos + 10);
\r
3755 src = src.substring(0, src.indexOf('\''));
\r
3763 TinyMCE.prototype._getElementById = function(element_id) {
\r
3764 var elm = document.getElementById(element_id);
\r
3766 // Check for element in forms
\r
3767 for (var j=0; j<document.forms.length; j++) {
\r
3768 for (var k=0; k<document.forms[j].elements.length; k++) {
\r
3769 if (document.forms[j].elements[k].name == element_id) {
\r
3770 elm = document.forms[j].elements[k];
\r
3780 TinyMCE.prototype.getEditorId = function(form_element) {
\r
3781 var inst = this.getInstanceById(form_element);
\r
3785 return inst.editorId;
\r
3788 TinyMCE.prototype.getInstanceById = function(editor_id) {
\r
3789 var inst = this.instances[editor_id];
\r
3791 for (var n in tinyMCE.instances) {
\r
3792 var instance = tinyMCE.instances[n];
\r
3793 if (!tinyMCE.isInstance(instance))
\r
3796 if (instance.formTargetElementId == editor_id) {
\r
3806 TinyMCE.prototype.queryInstanceCommandValue = function(editor_id, command) {
\r
3807 var inst = tinyMCE.getInstanceById(editor_id);
\r
3809 return inst.queryCommandValue(command);
\r
3814 TinyMCE.prototype.queryInstanceCommandState = function(editor_id, command) {
\r
3815 var inst = tinyMCE.getInstanceById(editor_id);
\r
3817 return inst.queryCommandState(command);
\r
3822 TinyMCE.prototype.setWindowArg = function(name, value) {
\r
3823 this.windowArgs[name] = value;
\r
3826 TinyMCE.prototype.getWindowArg = function(name, default_value) {
\r
3827 return (typeof(this.windowArgs[name]) == "undefined") ? default_value : this.windowArgs[name];
\r
3830 TinyMCE.prototype.getCSSClasses = function(editor_id, doc) {
\r
3831 var output = new Array();
\r
3833 // Is cached, use that
\r
3834 if (typeof(tinyMCE.cssClasses) != "undefined")
\r
3835 return tinyMCE.cssClasses;
\r
3837 if (typeof(editor_id) == "undefined" && typeof(doc) == "undefined") {
\r
3840 for (var instanceName in tinyMCE.instances) {
\r
3841 instance = tinyMCE.instances[instanceName];
\r
3842 if (!tinyMCE.isInstance(instance))
\r
3848 doc = instance.getDoc();
\r
3851 if (typeof(doc) == "undefined") {
\r
3852 var instance = tinyMCE.getInstanceById(editor_id);
\r
3853 doc = instance.getDoc();
\r
3857 var styles = tinyMCE.isMSIE ? doc.styleSheets : doc.styleSheets;
\r
3859 if (styles && styles.length > 0) {
\r
3860 for (var x=0; x<styles.length; x++) {
\r
3863 // Just ignore any errors
\r
3864 eval("try {var csses = tinyMCE.isMSIE ? doc.styleSheets(" + x + ").rules : doc.styleSheets[" + x + "].cssRules;} catch(e) {}");
\r
3866 return new Array();
\r
3868 for (var i=0; i<csses.length; i++) {
\r
3869 var selectorText = csses[i].selectorText;
\r
3871 // Can be multiple rules per selector
\r
3872 if (selectorText) {
\r
3873 var rules = selectorText.split(',');
\r
3874 for (var c=0; c<rules.length; c++) {
\r
3876 if (rules[c].indexOf(' ') != -1 || rules[c].indexOf(':') != -1 || rules[c].indexOf('mceItem') != -1)
\r
3879 if (rules[c] == "." + tinyMCE.settings['visual_table_class'])
\r
3883 if (rules[c].indexOf('.') != -1) {
\r
3884 //alert(rules[c].substring(rules[c].indexOf('.')));
\r
3885 output[output.length] = rules[c].substring(rules[c].indexOf('.')+1);
\r
3895 if (output.length > 0)
\r
3896 tinyMCE.cssClasses = output;
\r
3901 TinyMCE.prototype.regexpReplace = function(in_str, reg_exp, replace_str, opts) {
\r
3902 if (in_str == null)
\r
3905 if (typeof(opts) == "undefined")
\r
3908 var re = new RegExp(reg_exp, opts);
\r
3909 return in_str.replace(re, replace_str);
\r
3912 TinyMCE.prototype.trim = function(str) {
\r
3913 return str.replace(/^\s*|\s*$/g, "");
\r
3916 TinyMCE.prototype.cleanupEventStr = function(str) {
\r
3918 str = str.replace('function anonymous()\n{\n', '');
\r
3919 str = str.replace('\n}', '');
\r
3920 str = str.replace(/^return true;/gi, ''); // Remove event blocker
\r
3925 TinyMCE.prototype.getAbsPosition = function(node) {
\r
3926 var pos = new Object();
\r
3928 pos.absLeft = pos.absTop = 0;
\r
3930 var parentNode = node;
\r
3931 while (parentNode) {
\r
3932 pos.absLeft += parentNode.offsetLeft;
\r
3933 pos.absTop += parentNode.offsetTop;
\r
3935 parentNode = parentNode.offsetParent;
\r
3941 TinyMCE.prototype.getControlHTML = function(control_name) {
\r
3942 var themePlugins = tinyMCE.getParam('plugins', '', true, ',');
\r
3943 var templateFunction;
\r
3945 // Is it defined in any plugins
\r
3946 for (var i=themePlugins.length; i>=0; i--) {
\r
3947 templateFunction = 'TinyMCE_' + themePlugins[i] + "_getControlHTML";
\r
3948 if (eval("typeof(" + templateFunction + ")") != 'undefined') {
\r
3949 var html = eval(templateFunction + "('" + control_name + "');");
\r
3951 return tinyMCE.replaceVar(html, "pluginurl", tinyMCE.baseURL + "/plugins/" + themePlugins[i]);
\r
3955 return eval('TinyMCE_' + tinyMCE.settings['theme'] + "_getControlHTML" + "('" + control_name + "');");
\r
3958 TinyMCE.prototype._themeExecCommand = function(editor_id, element, command, user_interface, value) {
\r
3959 var themePlugins = tinyMCE.getParam('plugins', '', true, ',');
\r
3960 var templateFunction;
\r
3962 // Is it defined in any plugins
\r
3963 for (var i=themePlugins.length; i>=0; i--) {
\r
3964 templateFunction = 'TinyMCE_' + themePlugins[i] + "_execCommand";
\r
3965 if (eval("typeof(" + templateFunction + ")") != 'undefined') {
\r
3966 if (eval(templateFunction + "(editor_id, element, command, user_interface, value);"))
\r
3972 templateFunction = 'TinyMCE_' + tinyMCE.settings['theme'] + "_execCommand";
\r
3973 if (eval("typeof(" + templateFunction + ")") != 'undefined')
\r
3974 return eval(templateFunction + "(editor_id, element, command, user_interface, value);");
\r
3980 TinyMCE.prototype._getThemeFunction = function(suffix, skip_plugins) {
\r
3982 return 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;
\r
3984 var themePlugins = tinyMCE.getParam('plugins', '', true, ',');
\r
3985 var templateFunction;
\r
3987 // Is it defined in any plugins
\r
3988 for (var i=themePlugins.length; i>=0; i--) {
\r
3989 templateFunction = 'TinyMCE_' + themePlugins[i] + suffix;
\r
3990 if (eval("typeof(" + templateFunction + ")") != 'undefined')
\r
3991 return templateFunction;
\r
3994 return 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;
\r
3998 TinyMCE.prototype.isFunc = function(func_name) {
\r
3999 if (func_name == null || func_name == "")
\r
4002 return eval("typeof(" + func_name + ")") != "undefined";
\r
4005 TinyMCE.prototype.exec = function(func_name, args) {
\r
4006 var str = func_name + '(';
\r
4008 // Add all arguments
\r
4009 for (var i=3; i<args.length; i++) {
\r
4010 str += 'args[' + i + ']';
\r
4012 if (i < args.length-1)
\r
4021 TinyMCE.prototype.executeCallback = function(param, suffix, mode) {
\r
4025 var state = false;
\r
4027 // Execute each plugin callback
\r
4028 var plugins = tinyMCE.getParam('plugins', '', true, ',');
\r
4029 for (var i=0; i<plugins.length; i++) {
\r
4030 var func = "TinyMCE_" + plugins[i] + suffix;
\r
4031 if (tinyMCE.isFunc(func)) {
\r
4032 tinyMCE.exec(func, this.executeCallback.arguments);
\r
4037 // Execute theme callback
\r
4038 var func = 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;
\r
4039 if (tinyMCE.isFunc(func)) {
\r
4040 tinyMCE.exec(func, this.executeCallback.arguments);
\r
4044 // Execute settings callback
\r
4045 var func = tinyMCE.getParam(param, '');
\r
4046 if (tinyMCE.isFunc(func)) {
\r
4047 tinyMCE.exec(func, this.executeCallback.arguments);
\r
4055 // Execute each plugin callback
\r
4056 var plugins = tinyMCE.getParam('plugins', '', true, ',');
\r
4057 for (var i=0; i<plugins.length; i++) {
\r
4058 var func = "TinyMCE_" + plugins[i] + suffix;
\r
4059 if (tinyMCE.isFunc(func)) {
\r
4060 if (tinyMCE.exec(func, this.executeCallback.arguments))
\r
4065 // Execute theme callback
\r
4066 var func = 'TinyMCE_' + tinyMCE.settings['theme'] + suffix;
\r
4067 if (tinyMCE.isFunc(func)) {
\r
4068 if (tinyMCE.exec(func, this.executeCallback.arguments))
\r
4072 // Execute settings callback
\r
4073 var func = tinyMCE.getParam(param, '');
\r
4074 if (tinyMCE.isFunc(func)) {
\r
4075 if (tinyMCE.exec(func, this.executeCallback.arguments))
\r
4083 TinyMCE.prototype.debug = function() {
\r
4086 var elm = document.getElementById("tinymce_debug");
\r
4088 var debugDiv = document.createElement("div");
\r
4089 debugDiv.setAttribute("className", "debugger");
\r
4090 debugDiv.className = "debugger";
\r
4091 debugDiv.innerHTML = '\
\r
4093 <textarea id="tinymce_debug" style="width: 100%; height: 300px" wrap="nowrap"></textarea>';
\r
4095 document.body.appendChild(debugDiv);
\r
4096 elm = document.getElementById("tinymce_debug");
\r
4099 var args = this.debug.arguments;
\r
4100 for (var i=0; i<args.length; i++) {
\r
4102 if (i<args.length-1)
\r
4106 elm.value += msg + "\n";
\r
4110 function TinyMCEControl(settings) {
\r
4112 this.undoLevels = new Array();
\r
4113 this.undoIndex = 0;
\r
4114 this.typingUndoIndex = -1;
\r
4115 this.undoRedo = true;
\r
4116 this.isTinyMCEControl = true;
\r
4118 // Default settings
\r
4119 this.settings = settings;
\r
4120 this.settings['theme'] = tinyMCE.getParam("theme", "default");
\r
4121 this.settings['width'] = tinyMCE.getParam("width", -1);
\r
4122 this.settings['height'] = tinyMCE.getParam("height", -1);
\r
4125 TinyMCEControl.prototype.repaint = function() {
\r
4126 if (tinyMCE.isMSIE && !tinyMCE.isOpera)
\r
4129 // Ugly mozilla hack to remove ghost resize handles
\r
4131 this.getBody().style.display = 'none';
\r
4132 this.getDoc().execCommand('selectall', false, null);
\r
4133 this.getSel().collapseToStart();
\r
4134 this.getBody().style.display = 'block';
\r
4136 // Could I care less!!
\r
4140 TinyMCEControl.prototype.switchSettings = function() {
\r
4141 if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings['index']) {
\r
4142 tinyMCE.settings = this.settings;
\r
4143 tinyMCE.currentConfig = this.settings['index'];
\r
4147 TinyMCEControl.prototype.convertAllRelativeURLs = function() {
\r
4148 var body = this.getBody();
\r
4150 // Convert all image URL:s to absolute URL
\r
4151 var elms = body.getElementsByTagName("img");
\r
4152 for (var i=0; i<elms.length; i++) {
\r
4153 var src = tinyMCE.getAttrib(elms[i], 'src');
\r
4155 var msrc = tinyMCE.getAttrib(elms[i], 'mce_src');
\r
4160 src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
\r
4161 elms[i].setAttribute("src", src);
\r
4165 // Convert all link URL:s to absolute URL
\r
4166 var elms = body.getElementsByTagName("a");
\r
4167 for (var i=0; i<elms.length; i++) {
\r
4168 var href = tinyMCE.getAttrib(elms[i], 'href');
\r
4170 var mhref = tinyMCE.getAttrib(elms[i], 'mce_href');
\r
4174 if (href && href != "") {
\r
4175 href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], href);
\r
4176 elms[i].setAttribute("href", href);
\r
4181 TinyMCEControl.prototype.getSelectedHTML = function() {
\r
4182 if (tinyMCE.isSafari) {
\r
4183 // Not realy perfect!!
\r
4185 return this.getRng().toString();
\r
4188 var elm = document.createElement("body");
\r
4190 if (tinyMCE.isGecko)
\r
4191 elm.appendChild(this.getRng().cloneContents());
\r
4193 elm.innerHTML = this.getRng().htmlText;
\r
4195 return tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, elm, this.visualAid);
\r
4198 TinyMCEControl.prototype.getBookmark = function() {
\r
4199 var rng = this.getRng();
\r
4201 if (tinyMCE.isSafari)
\r
4204 if (tinyMCE.isMSIE)
\r
4207 if (tinyMCE.isGecko)
\r
4208 return rng.cloneRange();
\r
4213 TinyMCEControl.prototype.moveToBookmark = function(bookmark) {
\r
4214 if (tinyMCE.isSafari) {
\r
4215 var sel = this.getSel().realSelection;
\r
4217 sel.setBaseAndExtent(bookmark.startContainer, bookmark.startOffset, bookmark.endContainer, bookmark.endOffset);
\r
4222 if (tinyMCE.isMSIE)
\r
4223 return bookmark.select();
\r
4225 if (tinyMCE.isGecko) {
\r
4226 var rng = this.getDoc().createRange();
\r
4227 var sel = this.getSel();
\r
4229 rng.setStart(bookmark.startContainer, bookmark.startOffset);
\r
4230 rng.setEnd(bookmark.endContainer, bookmark.endOffset);
\r
4232 sel.removeAllRanges();
\r
4233 sel.addRange(rng);
\r
4241 TinyMCEControl.prototype.getSelectedText = function() {
\r
4242 if (tinyMCE.isMSIE) {
\r
4243 var doc = this.getDoc();
\r
4245 if (doc.selection.type == "Text") {
\r
4246 var rng = doc.selection.createRange();
\r
4247 selectedText = rng.text;
\r
4249 selectedText = '';
\r
4251 var sel = this.getSel();
\r
4253 if (sel && sel.toString)
\r
4254 selectedText = sel.toString();
\r
4256 selectedText = '';
\r
4259 return selectedText;
\r
4262 TinyMCEControl.prototype.selectNode = function(node, collapse, select_text_node, to_start) {
\r
4266 if (typeof(collapse) == "undefined")
\r
4269 if (typeof(select_text_node) == "undefined")
\r
4270 select_text_node = false;
\r
4272 if (typeof(to_start) == "undefined")
\r
4275 if (tinyMCE.isMSIE) {
\r
4276 var rng = this.getBody().createTextRange();
\r
4279 rng.moveToElementText(node);
\r
4282 rng.collapse(to_start);
\r
4286 // Throws illigal agrument in MSIE some times
\r
4289 var sel = this.getSel();
\r
4294 if (tinyMCE.isSafari) {
\r
4295 sel.realSelection.setBaseAndExtent(node, 0, node, node.innerText.length);
\r
4299 sel.realSelection.collapseToStart();
\r
4301 sel.realSelection.collapseToEnd();
\r
4304 this.scrollToNode(node);
\r
4309 var rng = this.getDoc().createRange();
\r
4311 if (select_text_node) {
\r
4312 // Find first textnode in tree
\r
4313 var nodes = tinyMCE.getNodeTree(node, new Array(), 3);
\r
4314 if (nodes.length > 0)
\r
4315 rng.selectNodeContents(nodes[0]);
\r
4317 rng.selectNodeContents(node);
\r
4319 rng.selectNode(node);
\r
4322 // Special treatment of textnode collapse
\r
4323 if (!to_start && node.nodeType == 3) {
\r
4324 rng.setStart(node, node.nodeValue.length);
\r
4325 rng.setEnd(node, node.nodeValue.length);
\r
4327 rng.collapse(to_start);
\r
4330 sel.removeAllRanges();
\r
4331 sel.addRange(rng);
\r
4334 this.scrollToNode(node);
\r
4336 // Set selected element
\r
4337 tinyMCE.selectedElement = null;
\r
4338 if (node.nodeType == 1)
\r
4339 tinyMCE.selectedElement = node;
\r
4342 TinyMCEControl.prototype.scrollToNode = function(node) {
\r
4343 // Scroll to node position
\r
4344 var pos = tinyMCE.getAbsPosition(node);
\r
4345 var doc = this.getDoc();
\r
4346 var scrollX = doc.body.scrollLeft + doc.documentElement.scrollLeft;
\r
4347 var scrollY = doc.body.scrollTop + doc.documentElement.scrollTop;
\r
4348 var height = tinyMCE.isMSIE ? document.getElementById(this.editorId).style.pixelHeight : this.targetElement.clientHeight;
\r
4350 // Only scroll if out of visible area
\r
4351 if (!tinyMCE.settings['auto_resize'] && !(pos.absTop > scrollY && pos.absTop < (scrollY - 25 + height)))
\r
4352 this.contentWindow.scrollTo(pos.absLeft, pos.absTop - height + 25);
\r
4355 TinyMCEControl.prototype.getBody = function() {
\r
4356 return this.getDoc().body;
\r
4359 TinyMCEControl.prototype.getDoc = function() {
\r
4360 return this.contentWindow.document;
\r
4363 TinyMCEControl.prototype.getWin = function() {
\r
4364 return this.contentWindow;
\r
4367 TinyMCEControl.prototype.getSel = function() {
\r
4368 if (tinyMCE.isMSIE && !tinyMCE.isOpera)
\r
4369 return this.getDoc().selection;
\r
4371 var sel = this.contentWindow.getSelection();
\r
4373 // Fake getRangeAt
\r
4374 if (tinyMCE.isSafari && !sel.getRangeAt) {
\r
4375 var newSel = new Object();
\r
4376 var doc = this.getDoc();
\r
4378 function getRangeAt(idx) {
\r
4379 var rng = new Object();
\r
4381 rng.startContainer = this.focusNode;
\r
4382 rng.endContainer = this.anchorNode;
\r
4383 rng.commonAncestorContainer = this.focusNode;
\r
4384 rng.createContextualFragment = function (html) {
\r
4385 // Seems to be a tag
\r
4386 if (html.charAt(0) == '<') {
\r
4387 var elm = doc.createElement("div");
\r
4389 elm.innerHTML = html;
\r
4391 return elm.firstChild;
\r
4394 return doc.createTextNode("UNSUPPORTED, DUE TO LIMITATIONS IN SAFARI!");
\r
4397 rng.deleteContents = function () {
\r
4398 doc.execCommand("Delete", false, "");
\r
4404 // Patch selection
\r
4406 newSel.focusNode = sel.baseNode;
\r
4407 newSel.focusOffset = sel.baseOffset;
\r
4408 newSel.anchorNode = sel.extentNode;
\r
4409 newSel.anchorOffset = sel.extentOffset;
\r
4410 newSel.getRangeAt = getRangeAt;
\r
4411 newSel.text = "" + sel;
\r
4412 newSel.realSelection = sel;
\r
4414 newSel.toString = function () {return this.text;};
\r
4422 TinyMCEControl.prototype.getRng = function() {
\r
4423 var sel = this.getSel();
\r
4427 if (tinyMCE.isMSIE && !tinyMCE.isOpera)
\r
4428 return sel.createRange();
\r
4430 if (tinyMCE.isSafari) {
\r
4431 var rng = this.getDoc().createRange();
\r
4432 var sel = this.getSel().realSelection;
\r
4434 rng.setStart(sel.baseNode, sel.baseOffset);
\r
4435 rng.setEnd(sel.extentNode, sel.extentOffset);
\r
4440 return this.getSel().getRangeAt(0);
\r
4443 TinyMCEControl.prototype._insertPara = function(e) {
\r
4444 function isEmpty(para) {
\r
4445 function isEmptyHTML(html) {
\r
4446 return html.replace(new RegExp('[ \t\r\n]+', 'g'), '').toLowerCase() == "";
\r
4449 // Check for images
\r
4450 if (para.getElementsByTagName("img").length > 0)
\r
4453 // Check for tables
\r
4454 if (para.getElementsByTagName("table").length > 0)
\r
4458 if (para.getElementsByTagName("hr").length > 0)
\r
4461 // Check all textnodes
\r
4462 var nodes = tinyMCE.getNodeTree(para, new Array(), 3);
\r
4463 for (var i=0; i<nodes.length; i++) {
\r
4464 if (!isEmptyHTML(nodes[i].nodeValue))
\r
4468 // No images, no tables, no hrs, no text content then it's empty
\r
4472 var doc = this.getDoc();
\r
4473 var sel = this.getSel();
\r
4474 var win = this.contentWindow;
\r
4475 var rng = sel.getRangeAt(0);
\r
4476 var body = doc.body;
\r
4477 var rootElm = doc.documentElement;
\r
4479 var blockName = "P";
\r
4481 // tinyMCE.debug(body.innerHTML);
\r
4483 // debug(e.target, sel.anchorNode.nodeName, sel.focusNode.nodeName, rng.startContainer, rng.endContainer, rng.commonAncestorContainer, sel.anchorOffset, sel.focusOffset, rng.toString());
\r
4485 // Setup before range
\r
4486 var rngBefore = doc.createRange();
\r
4487 rngBefore.setStart(sel.anchorNode, sel.anchorOffset);
\r
4488 rngBefore.collapse(true);
\r
4490 // Setup after range
\r
4491 var rngAfter = doc.createRange();
\r
4492 rngAfter.setStart(sel.focusNode, sel.focusOffset);
\r
4493 rngAfter.collapse(true);
\r
4495 // Setup start/end points
\r
4496 var direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;
\r
4497 var startNode = direct ? sel.anchorNode : sel.focusNode;
\r
4498 var startOffset = direct ? sel.anchorOffset : sel.focusOffset;
\r
4499 var endNode = direct ? sel.focusNode : sel.anchorNode;
\r
4500 var endOffset = direct ? sel.focusOffset : sel.anchorOffset;
\r
4502 startNode = startNode.nodeName == "BODY" ? startNode.firstChild : startNode;
\r
4503 endNode = endNode.nodeName == "BODY" ? endNode.firstChild : endNode;
\r
4505 // tinyMCE.debug(startNode, endNode);
\r
4507 // Get block elements
\r
4508 var startBlock = tinyMCE.getParentBlockElement(startNode);
\r
4509 var endBlock = tinyMCE.getParentBlockElement(endNode);
\r
4511 // Use current block name
\r
4512 if (startBlock != null) {
\r
4513 blockName = startBlock.nodeName;
\r
4516 if (blockName == "TD" || blockName == "TABLE" || (blockName == "DIV" && new RegExp('left|right', 'gi').test(startBlock.style.cssFloat)))
\r
4520 // Within a list use normal behaviour
\r
4521 if (tinyMCE.getParentElement(startBlock, "OL,UL") != null)
\r
4524 // Within a table create new paragraphs
\r
4525 if ((startBlock != null && startBlock.nodeName == "TABLE") || (endBlock != null && endBlock.nodeName == "TABLE"))
\r
4526 startBlock = endBlock = null;
\r
4528 // Setup new paragraphs
\r
4529 var paraBefore = (startBlock != null && startBlock.nodeName == blockName) ? startBlock.cloneNode(false) : doc.createElement(blockName);
\r
4530 var paraAfter = (endBlock != null && endBlock.nodeName == blockName) ? endBlock.cloneNode(false) : doc.createElement(blockName);
\r
4532 // Is header, then force paragraph under
\r
4533 if (/^(H[1-6])$/.test(blockName))
\r
4534 paraAfter = doc.createElement("p");
\r
4536 // Setup chop nodes
\r
4537 var startChop = startNode;
\r
4538 var endChop = endNode;
\r
4540 // Get startChop node
\r
4543 if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
\r
4547 } while ((node = node.previousSibling ? node.previousSibling : node.parentNode));
\r
4549 // Get endChop node
\r
4552 if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
\r
4556 } while ((node = node.nextSibling ? node.nextSibling : node.parentNode));
\r
4558 // Fix when only a image is within the TD
\r
4559 if (startChop.nodeName == "TD")
\r
4560 startChop = startChop.firstChild;
\r
4562 if (endChop.nodeName == "TD")
\r
4563 endChop = endChop.lastChild;
\r
4565 // If not in a block element
\r
4566 if (startBlock == null) {
\r
4567 // Delete selection
\r
4568 rng.deleteContents();
\r
4569 sel.removeAllRanges();
\r
4571 if (startChop != rootElm && endChop != rootElm) {
\r
4572 // Insert paragraph before
\r
4573 rngBefore = rng.cloneRange();
\r
4575 if (startChop == body)
\r
4576 rngBefore.setStart(startChop, 0);
\r
4578 rngBefore.setStartBefore(startChop);
\r
4580 paraBefore.appendChild(rngBefore.cloneContents());
\r
4582 // Insert paragraph after
\r
4583 if (endChop.parentNode.nodeName == blockName)
\r
4584 endChop = endChop.parentNode;
\r
4586 // If not after image
\r
4587 //if (rng.startContainer.nodeName != "BODY" && rng.endContainer.nodeName != "BODY")
\r
4588 rng.setEndAfter(endChop);
\r
4590 if (endChop.nodeName != "#text" && endChop.nodeName != "BODY")
\r
4591 rngBefore.setEndAfter(endChop);
\r
4593 var contents = rng.cloneContents();
\r
4594 if (contents.firstChild && (contents.firstChild.nodeName == blockName || contents.firstChild.nodeName == "BODY"))
\r
4595 paraAfter.innerHTML = contents.firstChild.innerHTML;
\r
4597 paraAfter.appendChild(contents);
\r
4599 // Check if it's a empty paragraph
\r
4600 if (isEmpty(paraBefore))
\r
4601 paraBefore.innerHTML = " ";
\r
4603 // Check if it's a empty paragraph
\r
4604 if (isEmpty(paraAfter))
\r
4605 paraAfter.innerHTML = " ";
\r
4607 // Delete old contents
\r
4608 rng.deleteContents();
\r
4609 rngAfter.deleteContents();
\r
4610 rngBefore.deleteContents();
\r
4612 // Insert new paragraphs
\r
4613 paraAfter.normalize();
\r
4614 rngBefore.insertNode(paraAfter);
\r
4615 paraBefore.normalize();
\r
4616 rngBefore.insertNode(paraBefore);
\r
4618 // tinyMCE.debug("1: ", paraBefore.innerHTML, paraAfter.innerHTML);
\r
4620 body.innerHTML = "<" + blockName + "> </" + blockName + "><" + blockName + "> </" + blockName + ">";
\r
4621 paraAfter = body.childNodes[1];
\r
4624 this.selectNode(paraAfter, true, true);
\r
4629 // Place first part within new paragraph
\r
4630 if (startChop.nodeName == blockName)
\r
4631 rngBefore.setStart(startChop, 0);
\r
4633 rngBefore.setStartBefore(startChop);
\r
4635 rngBefore.setEnd(startNode, startOffset);
\r
4636 paraBefore.appendChild(rngBefore.cloneContents());
\r
4638 // Place secound part within new paragraph
\r
4639 rngAfter.setEndAfter(endChop);
\r
4640 rngAfter.setStart(endNode, endOffset);
\r
4641 var contents = rngAfter.cloneContents();
\r
4643 if (contents.firstChild && contents.firstChild.nodeName == blockName) {
\r
4644 /* var nodes = contents.firstChild.childNodes;
\r
4645 for (var i=0; i<nodes.length; i++) {
\r
4646 //tinyMCE.debug(nodes[i].nodeName);
\r
4647 if (nodes[i].nodeName != "BODY")
\r
4648 paraAfter.appendChild(nodes[i]);
\r
4651 paraAfter.innerHTML = contents.firstChild.innerHTML;
\r
4653 paraAfter.appendChild(contents);
\r
4655 // Check if it's a empty paragraph
\r
4656 if (isEmpty(paraBefore))
\r
4657 paraBefore.innerHTML = " ";
\r
4659 // Check if it's a empty paragraph
\r
4660 if (isEmpty(paraAfter))
\r
4661 paraAfter.innerHTML = " ";
\r
4663 // Create a range around everything
\r
4664 var rng = doc.createRange();
\r
4666 if (!startChop.previousSibling && startChop.parentNode.nodeName.toUpperCase() == blockName) {
\r
4667 rng.setStartBefore(startChop.parentNode);
\r
4669 if (rngBefore.startContainer.nodeName.toUpperCase() == blockName && rngBefore.startOffset == 0)
\r
4670 rng.setStartBefore(rngBefore.startContainer);
\r
4672 rng.setStart(rngBefore.startContainer, rngBefore.startOffset);
\r
4675 if (!endChop.nextSibling && endChop.parentNode.nodeName.toUpperCase() == blockName)
\r
4676 rng.setEndAfter(endChop.parentNode);
\r
4678 rng.setEnd(rngAfter.endContainer, rngAfter.endOffset);
\r
4680 // Delete all contents and insert new paragraphs
\r
4681 rng.deleteContents();
\r
4682 rng.insertNode(paraAfter);
\r
4683 rng.insertNode(paraBefore);
\r
4684 //tinyMCE.debug("2", paraBefore.innerHTML, paraAfter.innerHTML);
\r
4687 paraAfter.normalize();
\r
4688 paraBefore.normalize();
\r
4690 this.selectNode(paraAfter, true, true);
\r
4695 TinyMCEControl.prototype._handleBackSpace = function(evt_type) {
\r
4696 var doc = this.getDoc();
\r
4697 var sel = this.getSel();
\r
4701 var rng = sel.getRangeAt(0);
\r
4702 var node = rng.startContainer;
\r
4703 var elm = node.nodeType == 3 ? node.parentNode : node;
\r
4708 // Empty node, wrap contents in paragraph
\r
4709 if (elm && elm.nodeName == "") {
\r
4710 var para = doc.createElement("p");
\r
4712 while (elm.firstChild)
\r
4713 para.appendChild(elm.firstChild);
\r
4715 elm.parentNode.insertBefore(para, elm);
\r
4716 elm.parentNode.removeChild(elm);
\r
4718 var rng = rng.cloneRange();
\r
4719 rng.setStartBefore(node.nextSibling);
\r
4720 rng.setEndAfter(node.nextSibling);
\r
4721 rng.extractContents();
\r
4723 this.selectNode(node.nextSibling, true, true);
\r
4726 // Remove empty paragraphs
\r
4727 var para = tinyMCE.getParentBlockElement(node);
\r
4728 if (para != null && para.nodeName.toLowerCase() == 'p' && evt_type == "keypress") {
\r
4729 var htm = para.innerHTML;
\r
4730 var block = tinyMCE.getParentBlockElement(node);
\r
4732 // Empty node, we do the killing!!
\r
4733 if (htm == "" || htm == " " || block.nodeName.toLowerCase() == "li") {
\r
4734 var prevElm = para.previousSibling;
\r
4736 while (prevElm != null && prevElm.nodeType != 1)
\r
4737 prevElm = prevElm.previousSibling;
\r
4739 if (prevElm == null)
\r
4742 // Get previous elements last text node
\r
4743 var nodes = tinyMCE.getNodeTree(prevElm, new Array(), 3);
\r
4744 var lastTextNode = nodes.length == 0 ? null : nodes[nodes.length-1];
\r
4746 // Select the last text node and move curstor to end
\r
4747 if (lastTextNode != null)
\r
4748 this.selectNode(lastTextNode, true, false, false);
\r
4750 // Remove the empty paragrapsh
\r
4751 para.parentNode.removeChild(para);
\r
4753 //debug("within p element" + para.innerHTML);
\r
4754 //showHTML(this.getBody().innerHTML);
\r
4759 // Remove BR elements
\r
4760 /* while (node != null && (node = node.nextSibling) != null) {
\r
4761 if (node.nodeName.toLowerCase() == 'br')
\r
4762 node.parentNode.removeChild(node);
\r
4763 else if (node.nodeType == 1) // Break at other element
\r
4767 //showHTML(this.getBody().innerHTML);
\r
4772 TinyMCEControl.prototype._insertSpace = function() {
\r
4776 TinyMCEControl.prototype.autoResetDesignMode = function() {
\r
4777 // Add fix for tab/style.display none/block problems in Gecko
\r
4778 if (!tinyMCE.isMSIE && tinyMCE.settings['auto_reset_designmode'] && this.isHidden())
\r
4779 eval('try { this.getDoc().designMode = "On"; } catch(e) {}');
\r
4782 TinyMCEControl.prototype.isHidden = function() {
\r
4783 if (tinyMCE.isMSIE)
\r
4786 var sel = this.getSel();
\r
4788 // Weird, wheres that cursor selection?
\r
4789 return (!sel || !sel.rangeCount || sel.rangeCount == 0);
\r
4792 TinyMCEControl.prototype.isDirty = function() {
\r
4793 // Is content modified and not in a submit procedure
\r
4794 return this.startContent != tinyMCE.trim(this.getBody().innerHTML) && !tinyMCE.isNotDirty;
\r
4797 TinyMCEControl.prototype._mergeElements = function(scmd, pa, ch, override) {
\r
4798 if (scmd == "removeformat") {
\r
4799 pa.className = "";
\r
4800 pa.style.cssText = "";
\r
4801 ch.className = "";
\r
4802 ch.style.cssText = "";
\r
4806 var st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));
\r
4807 var stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));
\r
4808 var className = tinyMCE.getAttrib(pa, "class");
\r
4810 className += " " + tinyMCE.getAttrib(ch, "class");
\r
4813 for (var n in st) {
\r
4814 if (typeof(st[n]) == 'function')
\r
4820 for (var n in stc) {
\r
4821 if (typeof(stc[n]) == 'function')
\r
4828 tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));
\r
4829 tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));
\r
4830 ch.className = "";
\r
4831 ch.style.cssText = "";
\r
4832 ch.removeAttribute("class");
\r
4833 ch.removeAttribute("style");
\r
4836 TinyMCEControl.prototype.setUseCSS = function(b) {
\r
4837 var doc = this.getDoc();
\r
4838 try {doc.execCommand("useCSS", false, !b);} catch (ex) {}
\r
4839 try {doc.execCommand("styleWithCSS", false, b);} catch (ex) {}
\r
4841 if (!tinyMCE.getParam("table_inline_editing"))
\r
4842 try {doc.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}
\r
4844 if (!tinyMCE.getParam("object_resizing"))
\r
4845 try {doc.execCommand('enableObjectResizing', false, "false");} catch (ex) {}
\r
4848 TinyMCEControl.prototype.execCommand = function(command, user_interface, value) {
\r
4849 var doc = this.getDoc();
\r
4850 var win = this.getWin();
\r
4851 var focusElm = this.getFocusElement();
\r
4853 if (this.lastSafariSelection && !new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command)) {
\r
4854 this.moveToBookmark(this.lastSafariSelection);
\r
4855 tinyMCE.selectedElement = this.lastSafariSelectedElement;
\r
4859 if (!tinyMCE.isMSIE && !this.useCSS) {
\r
4860 this.setUseCSS(false);
\r
4861 this.useCSS = true;
\r
4864 //debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);
\r
4865 this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks
\r
4867 // Call theme execcommand
\r
4868 if (tinyMCE._themeExecCommand(this.editorId, this.getBody(), command, user_interface, value))
\r
4871 // Fix align on images
\r
4872 if (focusElm && focusElm.nodeName == "IMG") {
\r
4873 var align = focusElm.getAttribute('align');
\r
4874 var img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;
\r
4876 switch (command) {
\r
4877 case "JustifyLeft":
\r
4878 if (align == 'left')
\r
4879 img.removeAttribute('align');
\r
4881 img.setAttribute('align', 'left');
\r
4884 var div = focusElm.parentNode;
\r
4885 if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
\r
4886 div.parentNode.replaceChild(img, div);
\r
4888 this.selectNode(img);
\r
4890 tinyMCE.triggerNodeChange();
\r
4893 case "JustifyCenter":
\r
4894 img.removeAttribute('align');
\r
4897 var div = tinyMCE.getParentElement(focusElm, "div");
\r
4898 if (div && div.style.textAlign == "center") {
\r
4900 if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
\r
4901 div.parentNode.replaceChild(img, div);
\r
4904 var div = this.getDoc().createElement("div");
\r
4905 div.style.textAlign = 'center';
\r
4906 div.appendChild(img);
\r
4907 focusElm.parentNode.replaceChild(div, focusElm);
\r
4910 this.selectNode(img);
\r
4912 tinyMCE.triggerNodeChange();
\r
4915 case "JustifyRight":
\r
4916 if (align == 'right')
\r
4917 img.removeAttribute('align');
\r
4919 img.setAttribute('align', 'right');
\r
4922 var div = focusElm.parentNode;
\r
4923 if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
\r
4924 div.parentNode.replaceChild(img, div);
\r
4926 this.selectNode(img);
\r
4928 tinyMCE.triggerNodeChange();
\r
4933 if (tinyMCE.settings['force_br_newlines']) {
\r
4934 var alignValue = "";
\r
4936 if (doc.selection.type != "Control") {
\r
4937 switch (command) {
\r
4938 case "JustifyLeft":
\r
4939 alignValue = "left";
\r
4942 case "JustifyCenter":
\r
4943 alignValue = "center";
\r
4946 case "JustifyFull":
\r
4947 alignValue = "justify";
\r
4950 case "JustifyRight":
\r
4951 alignValue = "right";
\r
4955 if (alignValue != "") {
\r
4956 var rng = doc.selection.createRange();
\r
4958 if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)
\r
4959 divElm.setAttribute("align", alignValue);
\r
4960 else if (rng.pasteHTML && rng.htmlText.length > 0)
\r
4961 rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");
\r
4963 tinyMCE.triggerNodeChange();
\r
4969 switch (command) {
\r
4970 case "mceRepaint":
\r
4974 case "mceStoreSelection":
\r
4975 this.selectionBookmark = this.getBookmark();
\r
4978 case "mceRestoreSelection":
\r
4979 this.moveToBookmark(this.selectionBookmark);
\r
4982 case "InsertUnorderedList":
\r
4983 case "InsertOrderedList":
\r
4984 var tag = (command == "InsertUnorderedList") ? "ul" : "ol";
\r
4986 if (tinyMCE.isSafari)
\r
4987 this.execCommand("mceInsertContent", false, "<" + tag + "><li> </li><" + tag + ">");
\r
4989 this.getDoc().execCommand(command, user_interface, value);
\r
4991 tinyMCE.triggerNodeChange();
\r
4994 case "Strikethrough":
\r
4995 if (tinyMCE.isSafari)
\r
4996 this.execCommand("mceInsertContent", false, "<strike>" + this.getSelectedHTML() + "</strike>");
\r
4998 this.getDoc().execCommand(command, user_interface, value);
\r
5000 tinyMCE.triggerNodeChange();
\r
5003 case "mceSelectNode":
\r
5004 this.selectNode(value);
\r
5005 tinyMCE.triggerNodeChange();
\r
5006 tinyMCE.selectedNode = value;
\r
5009 case "FormatBlock":
\r
5010 if (value == null || value == "") {
\r
5011 var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address");
\r
5014 this.execCommand("mceRemoveNode", false, elm);
\r
5016 this.getDoc().execCommand("FormatBlock", false, value);
\r
5018 tinyMCE.triggerNodeChange();
\r
5022 case "mceRemoveNode":
\r
5024 value = tinyMCE.getParentElement(this.getFocusElement());
\r
5026 if (tinyMCE.isMSIE) {
\r
5027 value.outerHTML = value.innerHTML;
\r
5029 var rng = value.ownerDocument.createRange();
\r
5030 rng.setStartBefore(value);
\r
5031 rng.setEndAfter(value);
\r
5032 rng.deleteContents();
\r
5033 rng.insertNode(rng.createContextualFragment(value.innerHTML));
\r
5036 tinyMCE.triggerNodeChange();
\r
5040 case "mceSelectNodeDepth":
\r
5041 var parentNode = this.getFocusElement();
\r
5042 for (var i=0; parentNode; i++) {
\r
5043 if (parentNode.nodeName.toLowerCase() == "body")
\r
5046 if (parentNode.nodeName.toLowerCase() == "#text") {
\r
5048 parentNode = parentNode.parentNode;
\r
5053 this.selectNode(parentNode, false);
\r
5054 tinyMCE.triggerNodeChange();
\r
5055 tinyMCE.selectedNode = parentNode;
\r
5059 parentNode = parentNode.parentNode;
\r
5064 case "SetStyleInfo":
\r
5065 var rng = this.getRng();
\r
5066 var sel = this.getSel();
\r
5067 var scmd = value['command'];
\r
5068 var sname = value['name'];
\r
5069 var svalue = value['value'] == null ? '' : value['value'];
\r
5070 //var svalue = value['value'] == null ? '' : value['value'];
\r
5071 var wrapper = value['wrapper'] ? value['wrapper'] : "span";
\r
5072 var parentElm = null;
\r
5073 var invalidRe = new RegExp("^BODY|HTML$", "g");
\r
5074 var invalidParentsRe = tinyMCE.settings['merge_styles_invalid_parents'] != '' ? new RegExp(tinyMCE.settings['merge_styles_invalid_parents'], "gi") : null;
\r
5076 // Whole element selected check
\r
5077 if (tinyMCE.isMSIE) {
\r
5080 parentElm = rng.item(0);
\r
5082 var pelm = rng.parentElement();
\r
5083 var prng = doc.selection.createRange();
\r
5084 prng.moveToElementText(pelm);
\r
5086 if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {
\r
5087 if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))
\r
5092 var felm = this.getFocusElement();
\r
5093 if (sel.isCollapsed || (/td|tr|tbody|table/ig.test(felm.nodeName) && sel.anchorNode == felm.parentNode))
\r
5097 // Whole element selected
\r
5098 if (parentElm && !invalidRe.test(parentElm.nodeName)) {
\r
5099 if (scmd == "setstyle")
\r
5100 tinyMCE.setStyleAttrib(parentElm, sname, svalue);
\r
5102 if (scmd == "setattrib")
\r
5103 tinyMCE.setAttrib(parentElm, sname, svalue);
\r
5105 if (scmd == "removeformat") {
\r
5106 parentElm.style.cssText = '';
\r
5107 tinyMCE.setAttrib(parentElm, 'class', '');
\r
5110 // Remove style/attribs from all children
\r
5111 var ch = tinyMCE.getNodeTree(parentElm, new Array(), 1);
\r
5112 for (var z=0; z<ch.length; z++) {
\r
5113 if (ch[z] == parentElm)
\r
5116 if (scmd == "setstyle")
\r
5117 tinyMCE.setStyleAttrib(ch[z], sname, '');
\r
5119 if (scmd == "setattrib")
\r
5120 tinyMCE.setAttrib(ch[z], sname, '');
\r
5122 if (scmd == "removeformat") {
\r
5123 ch[z].style.cssText = '';
\r
5124 tinyMCE.setAttrib(ch[z], 'class', '');
\r
5128 doc.execCommand("fontname", false, "#mce_temp_font#");
\r
5129 var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");
\r
5131 // Change them all
\r
5132 for (var x=0; x<elementArray.length; x++) {
\r
5133 elm = elementArray[x];
\r
5135 var spanElm = doc.createElement(wrapper);
\r
5137 if (scmd == "setstyle")
\r
5138 tinyMCE.setStyleAttrib(spanElm, sname, svalue);
\r
5140 if (scmd == "setattrib")
\r
5141 tinyMCE.setAttrib(spanElm, sname, svalue);
\r
5143 if (scmd == "removeformat") {
\r
5144 spanElm.style.cssText = '';
\r
5145 tinyMCE.setAttrib(spanElm, 'class', '');
\r
5148 if (elm.hasChildNodes()) {
\r
5149 for (var i=0; i<elm.childNodes.length; i++)
\r
5150 spanElm.appendChild(elm.childNodes[i].cloneNode(true));
\r
5153 spanElm.setAttribute("mce_new", "true");
\r
5154 elm.parentNode.replaceChild(spanElm, elm);
\r
5156 // Remove style/attribs from all children
\r
5157 var ch = tinyMCE.getNodeTree(spanElm, new Array(), 1);
\r
5158 for (var z=0; z<ch.length; z++) {
\r
5159 if (ch[z] == spanElm)
\r
5162 if (scmd == "setstyle")
\r
5163 tinyMCE.setStyleAttrib(ch[z], sname, '');
\r
5165 if (scmd == "setattrib")
\r
5166 tinyMCE.setAttrib(ch[z], sname, '');
\r
5168 if (scmd == "removeformat") {
\r
5169 ch[z].style.cssText = '';
\r
5170 tinyMCE.setAttrib(ch[z], 'class', '');
\r
5177 // Cleaup wrappers
\r
5178 var nodes = doc.getElementsByTagName(wrapper);
\r
5179 for (var i=nodes.length-1; i>=0; i--) {
\r
5180 var elm = nodes[i];
\r
5181 var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";
\r
5183 elm.removeAttribute("mce_new");
\r
5185 // Is only child a element
\r
5186 if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {
\r
5187 //tinyMCE.debug("merge1" + isNew);
\r
5188 this._mergeElements(scmd, elm, elm.childNodes[0], isNew);
\r
5192 // Is I the only child
\r
5193 if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {
\r
5194 //tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);
\r
5195 if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))
\r
5196 this._mergeElements(scmd, elm.parentNode, elm, false);
\r
5200 // Remove empty wrappers
\r
5201 var nodes = doc.getElementsByTagName(wrapper);
\r
5202 for (var i=nodes.length-1; i>=0; i--) {
\r
5203 var elm = nodes[i];
\r
5204 var isEmpty = true;
\r
5206 // Check if it has any attribs
\r
5207 var tmp = doc.createElement("body");
\r
5208 tmp.appendChild(elm.cloneNode(false));
\r
5210 // Is empty span, remove it
\r
5211 tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');
\r
5212 //tinyMCE.debug(tmp.innerHTML);
\r
5213 if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {
\r
5214 for (var x=0; x<elm.childNodes.length; x++) {
\r
5215 if (elm.parentNode != null)
\r
5216 elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);
\r
5219 elm.parentNode.removeChild(elm);
\r
5223 // Re add the visual aids
\r
5224 if (scmd == "removeformat")
\r
5225 tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
\r
5227 tinyMCE.triggerNodeChange();
\r
5232 if (value == null) {
\r
5233 var s = this.getSel();
\r
5235 // Find font and select it
\r
5236 if (tinyMCE.isGecko && s.isCollapsed) {
\r
5237 var f = tinyMCE.getParentElement(this.getFocusElement(), "font");
\r
5240 this.selectNode(f, false);
\r
5244 this.getDoc().execCommand("RemoveFormat", false, null);
\r
5246 // Collapse range if font was found
\r
5247 if (f != null && tinyMCE.isGecko) {
\r
5248 var r = this.getRng().cloneRange();
\r
5250 s.removeAllRanges();
\r
5254 this.getDoc().execCommand('FontName', false, value);
\r
5256 if (tinyMCE.isGecko)
\r
5257 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
\r
5262 this.getDoc().execCommand('FontSize', false, value);
\r
5264 if (tinyMCE.isGecko)
\r
5265 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
\r
5270 this.getDoc().execCommand('forecolor', false, value);
\r
5273 case "HiliteColor":
\r
5274 if (tinyMCE.isGecko) {
\r
5275 this.setUseCSS(true);
\r
5276 this.getDoc().execCommand('hilitecolor', false, value);
\r
5277 this.setUseCSS(false);
\r
5279 this.getDoc().execCommand('BackColor', false, value);
\r
5285 var cmdFailed = false;
\r
5287 // Try executing command
\r
5288 eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');
\r
5290 if (tinyMCE.isOpera && cmdFailed)
\r
5291 alert('Currently not supported by your browser, use keyboard shortcuts instead.');
\r
5293 // Alert error in gecko if command failed
\r
5294 if (tinyMCE.isGecko && cmdFailed) {
\r
5295 // Confirm more info
\r
5296 if (confirm(tinyMCE.getLang('lang_clipboard_msg')))
\r
5297 window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');
\r
5301 tinyMCE.triggerNodeChange();
\r
5304 case "mceSetContent":
\r
5308 // Call custom cleanup code
\r
5309 value = tinyMCE.storeAwayURLs(value);
\r
5310 value = tinyMCE._customCleanup(this, "insert_to_editor", value);
\r
5311 tinyMCE._setHTML(doc, value);
\r
5312 tinyMCE.setInnerHTML(doc.body, tinyMCE._cleanupHTML(this, doc, tinyMCE.settings, doc.body));
\r
5313 this.convertAllRelativeURLs();
\r
5314 tinyMCE.handleVisualAid(doc.body, true, this.visualAid, this);
\r
5315 tinyMCE._setEventsEnabled(doc.body, false);
\r
5319 var selectedText = "";
\r
5321 if (tinyMCE.isMSIE) {
\r
5322 var rng = doc.selection.createRange();
\r
5323 selectedText = rng.text;
\r
5325 selectedText = this.getSel().toString();
\r
5327 if (!tinyMCE.linkElement) {
\r
5328 if ((tinyMCE.selectedElement.nodeName.toLowerCase() != "img") && (selectedText.length <= 0))
\r
5332 var href = "", target = "", title = "", onclick = "", action = "insert", style_class = "";
\r
5334 if (tinyMCE.selectedElement.nodeName.toLowerCase() == "a")
\r
5335 tinyMCE.linkElement = tinyMCE.selectedElement;
\r
5337 // Is anchor not a link
\r
5338 if (tinyMCE.linkElement != null && tinyMCE.getAttrib(tinyMCE.linkElement, 'href') == "")
\r
5339 tinyMCE.linkElement = null;
\r
5341 if (tinyMCE.linkElement) {
\r
5342 href = tinyMCE.getAttrib(tinyMCE.linkElement, 'href');
\r
5343 target = tinyMCE.getAttrib(tinyMCE.linkElement, 'target');
\r
5344 title = tinyMCE.getAttrib(tinyMCE.linkElement, 'title');
\r
5345 onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
\r
5346 style_class = tinyMCE.getAttrib(tinyMCE.linkElement, 'class');
\r
5348 // Try old onclick to if copy/pasted content
\r
5349 if (onclick == "")
\r
5350 onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
\r
5352 onclick = tinyMCE.cleanupEventStr(onclick);
\r
5354 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
\r
5356 // Use mce_href if defined
\r
5357 mceRealHref = tinyMCE.getAttrib(tinyMCE.linkElement, 'mce_href');
\r
5358 if (mceRealHref != "") {
\r
5359 href = mceRealHref;
\r
5361 if (tinyMCE.getParam('convert_urls'))
\r
5362 href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
\r
5365 action = "update";
\r
5368 if (this.settings['insertlink_callback']) {
\r
5369 var returnVal = eval(this.settings['insertlink_callback'] + "(href, target, title, onclick, action, style_class);");
\r
5370 if (returnVal && returnVal['href'])
\r
5371 tinyMCE.insertLink(returnVal['href'], returnVal['target'], returnVal['title'], returnVal['onclick'], returnVal['style_class']);
\r
5373 tinyMCE.openWindow(this.insertLinkTemplate, {href : href, target : target, title : title, onclick : onclick, action : action, className : style_class, inline : "yes"});
\r
5378 var src = "", alt = "", border = "", hspace = "", vspace = "", width = "", height = "", align = "";
\r
5379 var title = "", onmouseover = "", onmouseout = "", action = "insert";
\r
5380 var img = tinyMCE.imgElement;
\r
5382 if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img") {
\r
5383 img = tinyMCE.selectedElement;
\r
5384 tinyMCE.imgElement = img;
\r
5388 // Is it a internal MCE visual aid image, then skip this one.
\r
5389 if (tinyMCE.getAttrib(img, 'name').indexOf('mce_') == 0)
\r
5392 src = tinyMCE.getAttrib(img, 'src');
\r
5393 alt = tinyMCE.getAttrib(img, 'alt');
\r
5395 // Try polling out the title
\r
5397 alt = tinyMCE.getAttrib(img, 'title');
\r
5399 // Fix width/height attributes if the styles is specified
\r
5400 if (tinyMCE.isGecko) {
\r
5401 var w = img.style.width;
\r
5402 if (w != null && w != "")
\r
5403 img.setAttribute("width", w);
\r
5405 var h = img.style.height;
\r
5406 if (h != null && h != "")
\r
5407 img.setAttribute("height", h);
\r
5410 border = tinyMCE.getAttrib(img, 'border');
\r
5411 hspace = tinyMCE.getAttrib(img, 'hspace');
\r
5412 vspace = tinyMCE.getAttrib(img, 'vspace');
\r
5413 width = tinyMCE.getAttrib(img, 'width');
\r
5414 height = tinyMCE.getAttrib(img, 'height');
\r
5415 align = tinyMCE.getAttrib(img, 'align');
\r
5416 onmouseover = tinyMCE.getAttrib(img, 'onmouseover');
\r
5417 onmouseout = tinyMCE.getAttrib(img, 'onmouseout');
\r
5418 title = tinyMCE.getAttrib(img, 'title');
\r
5420 // Is realy specified?
\r
5421 if (tinyMCE.isMSIE) {
\r
5422 width = img.attributes['width'].specified ? width : "";
\r
5423 height = img.attributes['height'].specified ? height : "";
\r
5426 onmouseover = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseover));
\r
5427 onmouseout = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseout));
\r
5429 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
\r
5431 // Use mce_src if defined
\r
5432 mceRealSrc = tinyMCE.getAttrib(img, 'mce_src');
\r
5433 if (mceRealSrc != "") {
\r
5436 if (tinyMCE.getParam('convert_urls'))
\r
5437 src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
\r
5440 if (onmouseover != "")
\r
5441 onmouseover = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, img, true);");
\r
5443 if (onmouseout != "")
\r
5444 onmouseout = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, img, true);");
\r
5446 action = "update";
\r
5449 if (this.settings['insertimage_callback']) {
\r
5450 var returnVal = eval(this.settings['insertimage_callback'] + "(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout, action);");
\r
5451 if (returnVal && returnVal['src'])
\r
5452 tinyMCE.insertImage(returnVal['src'], returnVal['alt'], returnVal['border'], returnVal['hspace'], returnVal['vspace'], returnVal['width'], returnVal['height'], returnVal['align'], returnVal['title'], returnVal['onmouseover'], returnVal['onmouseout']);
\r
5454 tinyMCE.openWindow(this.insertImageTemplate, {src : src, alt : alt, border : border, hspace : hspace, vspace : vspace, width : width, height : height, align : align, title : title, onmouseover : onmouseover, onmouseout : onmouseout, action : action, inline : "yes"});
\r
5457 case "mceCleanup":
\r
5458 tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);
\r
5459 tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));
\r
5460 this.convertAllRelativeURLs();
\r
5461 tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
\r
5462 tinyMCE._setEventsEnabled(this.getBody(), false);
\r
5464 tinyMCE.triggerNodeChange();
\r
5467 case "mceReplaceContent":
\r
5468 this.getWin().focus();
\r
5470 var selectedText = "";
\r
5472 if (tinyMCE.isMSIE) {
\r
5473 var rng = doc.selection.createRange();
\r
5474 selectedText = rng.text;
\r
5476 selectedText = this.getSel().toString();
\r
5478 if (selectedText.length > 0) {
\r
5479 value = tinyMCE.replaceVar(value, "selection", selectedText);
\r
5480 tinyMCE.execCommand('mceInsertContent', false, value);
\r
5483 tinyMCE.triggerNodeChange();
\r
5486 case "mceSetAttribute":
\r
5487 if (typeof(value) == 'object') {
\r
5488 var targetElms = (typeof(value['targets']) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value['targets'];
\r
5489 var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);
\r
5492 targetNode.setAttribute(value['name'], value['value']);
\r
5493 tinyMCE.triggerNodeChange();
\r
5498 case "mceSetCSSClass":
\r
5499 this.execCommand("SetStyleInfo", false, {command : "setattrib", name : "class", value : value});
\r
5502 case "mceInsertRawHTML":
\r
5503 var key = 'tiny_mce_marker';
\r
5505 this.execCommand('mceBeginUndoLevel');
\r
5507 // Insert marker key
\r
5508 this.execCommand('mceInsertContent', false, key);
\r
5510 // Store away scroll pos
\r
5511 var scrollX = this.getDoc().body.scrollLeft + this.getDoc().documentElement.scrollLeft;
\r
5512 var scrollY = this.getDoc().body.scrollTop + this.getDoc().documentElement.scrollTop;
\r
5514 // Find marker and replace with RAW HTML
\r
5515 var html = this.getBody().innerHTML;
\r
5516 if ((pos = html.indexOf(key)) != -1)
\r
5517 tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));
\r
5519 // Restore scoll pos
\r
5520 this.contentWindow.scrollTo(scrollX, scrollY);
\r
5522 this.execCommand('mceEndUndoLevel');
\r
5526 case "mceInsertContent":
\r
5527 var insertHTMLFailed = false;
\r
5528 this.getWin().focus();
\r
5530 if (tinyMCE.isGecko || tinyMCE.isOpera) {
\r
5532 // Is plain text or HTML
\r
5533 if (value.indexOf('<') == -1) {
\r
5534 var r = this.getRng();
\r
5535 var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));
\r
5536 var s = this.getSel();
\r
5537 var r2 = r.cloneRange();
\r
5539 // Insert text at cursor position
\r
5540 s.removeAllRanges();
\r
5541 r.deleteContents();
\r
5544 // Move the cursor to the end of text
\r
5546 r2.collapse(false);
\r
5547 s.removeAllRanges();
\r
5550 value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);
\r
5551 this.getDoc().execCommand('inserthtml', false, value);
\r
5552 tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
\r
5555 insertHTMLFailed = true;
\r
5558 if (!insertHTMLFailed) {
\r
5559 tinyMCE.triggerNodeChange();
\r
5564 // Ugly hack in Opera due to non working "inserthtml"
\r
5565 if (tinyMCE.isOpera && insertHTMLFailed) {
\r
5566 this.getDoc().execCommand("insertimage", false, tinyMCE.uniqueURL);
\r
5567 var ar = tinyMCE.getElementsByAttributeValue(this.getBody(), "img", "src", tinyMCE.uniqueURL);
\r
5568 ar[0].outerHTML = value;
\r
5572 if (!tinyMCE.isMSIE) {
\r
5573 var isHTML = value.indexOf('<') != -1;
\r
5574 var sel = this.getSel();
\r
5575 var rng = this.getRng();
\r
5578 if (tinyMCE.isSafari) {
\r
5579 var tmpRng = this.getDoc().createRange();
\r
5581 tmpRng.setStart(this.getBody(), 0);
\r
5582 tmpRng.setEnd(this.getBody(), 0);
\r
5584 value = tmpRng.createContextualFragment(value);
\r
5586 value = rng.createContextualFragment(value);
\r
5588 // Setup text node
\r
5589 var el = document.createElement("div");
\r
5590 el.innerHTML = value;
\r
5591 value = el.firstChild.nodeValue;
\r
5592 value = doc.createTextNode(value);
\r
5595 // Insert plain text in Safari
\r
5596 if (tinyMCE.isSafari && !isHTML) {
\r
5597 this.execCommand('InsertText', false, value.nodeValue);
\r
5598 tinyMCE.triggerNodeChange();
\r
5600 } else if (tinyMCE.isSafari && isHTML) {
\r
5601 rng.deleteContents();
\r
5602 rng.insertNode(value);
\r
5603 tinyMCE.triggerNodeChange();
\r
5607 rng.deleteContents();
\r
5609 // If target node is text do special treatment, (Mozilla 1.3 fix)
\r
5610 if (rng.startContainer.nodeType == 3) {
\r
5611 var node = rng.startContainer.splitText(rng.startOffset);
\r
5612 node.parentNode.insertBefore(value, node);
\r
5614 rng.insertNode(value);
\r
5617 // Removes weird selection trails
\r
5618 sel.selectAllChildren(doc.body);
\r
5619 sel.removeAllRanges();
\r
5621 // Move cursor to end of content
\r
5622 var rng = doc.createRange();
\r
5624 rng.selectNode(value);
\r
5625 rng.collapse(false);
\r
5627 sel.addRange(rng);
\r
5629 rng.collapse(false);
\r
5631 var rng = doc.selection.createRange();
\r
5632 var c = value.indexOf('<!--') != -1;
\r
5634 // Fix comment bug, add tag before comments
\r
5636 value = tinyMCE.uniqueTag + value;
\r
5639 rng.item(0).outerHTML = value;
\r
5641 rng.pasteHTML(value);
\r
5643 // Remove unique tag
\r
5645 var e = this.getDoc().getElementById('mceTMPElement');
\r
5646 e.parentNode.removeChild(e);
\r
5650 tinyMCE.triggerNodeChange();
\r
5653 case "mceStartTyping":
\r
5654 if (tinyMCE.settings['custom_undo_redo'] && this.typingUndoIndex == -1) {
\r
5655 this.typingUndoIndex = this.undoIndex;
\r
5656 this.execCommand('mceAddUndoLevel');
\r
5657 //tinyMCE.debug("mceStartTyping");
\r
5661 case "mceEndTyping":
\r
5662 if (tinyMCE.settings['custom_undo_redo'] && this.typingUndoIndex != -1) {
\r
5663 this.execCommand('mceAddUndoLevel');
\r
5664 this.typingUndoIndex = -1;
\r
5665 //tinyMCE.debug("mceEndTyping");
\r
5669 case "mceBeginUndoLevel":
\r
5670 this.undoRedo = false;
\r
5673 case "mceEndUndoLevel":
\r
5674 this.undoRedo = true;
\r
5675 this.execCommand('mceAddUndoLevel');
\r
5678 case "mceAddUndoLevel":
\r
5679 if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo) {
\r
5680 // tinyMCE.debug("add level");
\r
5682 if (this.typingUndoIndex != -1) {
\r
5683 this.undoIndex = this.typingUndoIndex;
\r
5684 // tinyMCE.debug("Override: " + this.undoIndex);
\r
5687 var newHTML = tinyMCE.trim(this.getBody().innerHTML);
\r
5688 if (newHTML != this.undoLevels[this.undoIndex]) {
\r
5689 tinyMCE.executeCallback('onchange_callback', '_onchange', 0, this);
\r
5691 // Time to compress
\r
5692 var customUndoLevels = tinyMCE.settings['custom_undo_redo_levels'];
\r
5693 if (customUndoLevels != -1 && this.undoLevels.length > customUndoLevels) {
\r
5694 for (var i=0; i<this.undoLevels.length-1; i++) {
\r
5695 //tinyMCE.debug(this.undoLevels[i] + "=" + this.undoLevels[i+1]);
\r
5696 this.undoLevels[i] = this.undoLevels[i+1];
\r
5699 this.undoLevels.length--;
\r
5704 this.undoLevels[this.undoIndex] = newHTML;
\r
5705 this.undoLevels.length = this.undoIndex + 1;
\r
5707 // tinyMCE.debug("level added" + this.undoIndex);
\r
5708 tinyMCE.triggerNodeChange(false);
\r
5710 // tinyMCE.debug(this.undoIndex + "," + (this.undoLevels.length-1));
\r
5716 if (tinyMCE.settings['custom_undo_redo']) {
\r
5717 tinyMCE.execCommand("mceEndTyping");
\r
5720 if (this.undoIndex > 0) {
\r
5722 tinyMCE.setInnerHTML(this.getBody(), this.undoLevels[this.undoIndex]);
\r
5726 // tinyMCE.debug("Undo - undo levels:" + this.undoLevels.length + ", undo index: " + this.undoIndex);
\r
5727 tinyMCE.triggerNodeChange();
\r
5729 this.getDoc().execCommand(command, user_interface, value);
\r
5733 if (tinyMCE.settings['custom_undo_redo']) {
\r
5734 tinyMCE.execCommand("mceEndTyping");
\r
5736 if (this.undoIndex < (this.undoLevels.length-1)) {
\r
5738 tinyMCE.setInnerHTML(this.getBody(), this.undoLevels[this.undoIndex]);
\r
5740 // tinyMCE.debug("Redo - undo levels:" + this.undoLevels.length + ", undo index: " + this.undoIndex);
\r
5743 tinyMCE.triggerNodeChange();
\r
5745 this.getDoc().execCommand(command, user_interface, value);
\r
5748 case "mceToggleVisualAid":
\r
5749 this.visualAid = !this.visualAid;
\r
5750 tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
\r
5751 tinyMCE.triggerNodeChange();
\r
5755 this.getDoc().execCommand(command, user_interface, value);
\r
5756 tinyMCE.triggerNodeChange();
\r
5757 if (tinyMCE.isMSIE) {
\r
5758 var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");
\r
5760 if (n && n.nodeName == "BLOCKQUOTE") {
\r
5761 n.removeAttribute("dir");
\r
5762 n.removeAttribute("style");
\r
5764 } while (n != null && (n = n.parentNode) != null);
\r
5768 case "removeformat":
\r
5769 var text = this.getSelectedText();
\r
5771 if (tinyMCE.isOpera) {
\r
5772 this.getDoc().execCommand("RemoveFormat", false, null);
\r
5776 if (tinyMCE.isMSIE) {
\r
5778 var rng = doc.selection.createRange();
\r
5779 rng.execCommand("RemoveFormat", false, null);
\r
5784 this.execCommand("SetStyleInfo", false, {command : "removeformat"});
\r
5786 this.getDoc().execCommand(command, user_interface, value);
\r
5788 this.execCommand("SetStyleInfo", false, {command : "removeformat"});
\r
5792 if (text.length == 0)
\r
5793 this.execCommand("mceSetCSSClass", false, "");
\r
5795 tinyMCE.triggerNodeChange();
\r
5799 this.getDoc().execCommand(command, user_interface, value);
\r
5801 if (tinyMCE.isGecko)
\r
5802 window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
\r
5804 tinyMCE.triggerNodeChange();
\r
5807 // Add undo level after modification
\r
5808 if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")
\r
5809 tinyMCE.execCommand("mceAddUndoLevel");
\r
5812 TinyMCEControl.prototype.queryCommandValue = function(command) {
\r
5814 return this.getDoc().queryCommandValue(command);
\r
5820 TinyMCEControl.prototype.queryCommandState = function(command) {
\r
5821 return this.getDoc().queryCommandState(command);
\r
5824 TinyMCEControl.prototype.onAdd = function(replace_element, form_element_name, target_document) {
\r
5825 var targetDoc = target_document ? target_document : document;
\r
5827 this.targetDoc = targetDoc;
\r
5829 tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings['theme'];
\r
5830 this.settings['themeurl'] = tinyMCE.themeURL;
\r
5832 if (!replace_element) {
\r
5833 alert("Error: Could not find the target element.");
\r
5837 var templateFunction = tinyMCE._getThemeFunction('_getInsertLinkTemplate');
\r
5838 if (eval("typeof(" + templateFunction + ")") != 'undefined')
\r
5839 this.insertLinkTemplate = eval(templateFunction + '(this.settings);');
\r
5841 var templateFunction = tinyMCE._getThemeFunction('_getInsertImageTemplate');
\r
5842 if (eval("typeof(" + templateFunction + ")") != 'undefined')
\r
5843 this.insertImageTemplate = eval(templateFunction + '(this.settings);');
\r
5845 var templateFunction = tinyMCE._getThemeFunction('_getEditorTemplate');
\r
5846 if (eval("typeof(" + templateFunction + ")") == 'undefined') {
\r
5847 alert("Error: Could not find the template function: " + templateFunction);
\r
5851 var editorTemplate = eval(templateFunction + '(this.settings, this.editorId);');
\r
5853 var deltaWidth = editorTemplate['delta_width'] ? editorTemplate['delta_width'] : 0;
\r
5854 var deltaHeight = editorTemplate['delta_height'] ? editorTemplate['delta_height'] : 0;
\r
5855 var html = '<span id="' + this.editorId + '_parent">' + editorTemplate['html'];
\r
5857 var templateFunction = tinyMCE._getThemeFunction('_handleNodeChange', true);
\r
5858 if (eval("typeof(" + templateFunction + ")") != 'undefined')
\r
5859 this.settings['handleNodeChangeCallback'] = templateFunction;
\r
5861 html = tinyMCE.replaceVar(html, "editor_id", this.editorId);
\r
5862 this.settings['default_document'] = tinyMCE.baseURL + "/blank.htm";
\r
5864 this.settings['old_width'] = this.settings['width'];
\r
5865 this.settings['old_height'] = this.settings['height'];
\r
5867 // Set default width, height
\r
5868 if (this.settings['width'] == -1)
\r
5869 this.settings['width'] = replace_element.offsetWidth;
\r
5871 if (this.settings['height'] == -1)
\r
5872 this.settings['height'] = replace_element.offsetHeight;
\r
5874 // Try the style width
\r
5875 if (this.settings['width'] == 0)
\r
5876 this.settings['width'] = replace_element.style.width;
\r
5878 // Try the style height
\r
5879 if (this.settings['height'] == 0)
\r
5880 this.settings['height'] = replace_element.style.height;
\r
5882 // If no width/height then default to 320x240, better than nothing
\r
5883 if (this.settings['width'] == 0)
\r
5884 this.settings['width'] = 320;
\r
5886 if (this.settings['height'] == 0)
\r
5887 this.settings['height'] = 240;
\r
5889 this.settings['area_width'] = parseInt(this.settings['width']);
\r
5890 this.settings['area_height'] = parseInt(this.settings['height']);
\r
5891 this.settings['area_width'] += deltaWidth;
\r
5892 this.settings['area_height'] += deltaHeight;
\r
5894 // Special % handling
\r
5895 if (("" + this.settings['width']).indexOf('%') != -1)
\r
5896 this.settings['area_width'] = "100%";
\r
5898 if (("" + this.settings['height']).indexOf('%') != -1)
\r
5899 this.settings['area_height'] = "100%";
\r
5901 if (("" + replace_element.style.width).indexOf('%') != -1) {
\r
5902 this.settings['width'] = replace_element.style.width;
\r
5903 this.settings['area_width'] = "100%";
\r
5906 if (("" + replace_element.style.height).indexOf('%') != -1) {
\r
5907 this.settings['height'] = replace_element.style.height;
\r
5908 this.settings['area_height'] = "100%";
\r
5911 html = tinyMCE.applyTemplate(html);
\r
5913 this.settings['width'] = this.settings['old_width'];
\r
5914 this.settings['height'] = this.settings['old_height'];
\r
5916 this.visualAid = this.settings['visual'];
\r
5917 this.formTargetElementId = form_element_name;
\r
5919 // Get replace_element contents
\r
5920 if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")
\r
5921 this.startContent = replace_element.value;
\r
5923 this.startContent = replace_element.innerHTML;
\r
5925 // If not text area
\r
5926 if (replace_element.nodeName.toLowerCase() != "textarea") {
\r
5927 this.oldTargetElement = replace_element.cloneNode(true);
\r
5930 if (tinyMCE.settings['debug'])
\r
5931 html += '<textarea wrap="off" id="' + form_element_name + '" name="' + form_element_name + '" cols="100" rows="15"></textarea>';
\r
5933 html += '<input type="hidden" type="text" id="' + form_element_name + '" name="' + form_element_name + '" />';
\r
5935 html += '</span>';
\r
5937 // Output HTML and set editable
\r
5938 if (!tinyMCE.isMSIE) {
\r
5939 var rng = replace_element.ownerDocument.createRange();
\r
5940 rng.setStartBefore(replace_element);
\r
5942 var fragment = rng.createContextualFragment(html);
\r
5943 replace_element.parentNode.replaceChild(fragment, replace_element);
\r
5945 replace_element.outerHTML = html;
\r
5947 html += '</span>';
\r
5949 // Just hide the textarea element
\r
5950 this.oldTargetElement = replace_element;
\r
5952 if (!tinyMCE.settings['debug'])
\r
5953 this.oldTargetElement.style.display = "none";
\r
5955 // Output HTML and set editable
\r
5956 if (!tinyMCE.isMSIE) {
\r
5957 var rng = replace_element.ownerDocument.createRange();
\r
5958 rng.setStartBefore(replace_element);
\r
5960 var fragment = rng.createContextualFragment(html);
\r
5962 if (tinyMCE.isGecko)
\r
5963 tinyMCE.insertAfter(fragment, replace_element);
\r
5965 replace_element.parentNode.insertBefore(fragment, replace_element);
\r
5967 replace_element.insertAdjacentHTML("beforeBegin", html);
\r
5971 var dynamicIFrame = false;
\r
5972 var tElm = targetDoc.getElementById(this.editorId);
\r
5974 if (!tinyMCE.isMSIE) {
\r
5975 if (tElm && tElm.nodeName.toLowerCase() == "span") {
\r
5976 tElm = tinyMCE._createIFrame(tElm);
\r
5977 dynamicIFrame = true;
\r
5980 this.targetElement = tElm;
\r
5981 this.iframeElement = tElm;
\r
5982 this.contentDocument = tElm.contentDocument;
\r
5983 this.contentWindow = tElm.contentWindow;
\r
5985 //this.getDoc().designMode = "on";
\r
5987 if (tElm && tElm.nodeName.toLowerCase() == "span")
\r
5988 tElm = tinyMCE._createIFrame(tElm);
\r
5990 tElm = targetDoc.frames[this.editorId];
\r
5992 this.targetElement = tElm;
\r
5993 this.iframeElement = targetDoc.getElementById(this.editorId);
\r
5995 if (tinyMCE.isOpera) {
\r
5996 this.contentDocument = this.iframeElement.contentDocument;
\r
5997 this.contentWindow = this.iframeElement.contentWindow;
\r
5998 dynamicIFrame = true;
\r
6000 this.contentDocument = tElm.window.document;
\r
6001 this.contentWindow = tElm.window;
\r
6004 this.getDoc().designMode = "on";
\r
6007 // Setup base HTML
\r
6008 var doc = this.contentDocument;
\r
6009 if (dynamicIFrame) {
\r
6010 var html = tinyMCE.getParam('doctype') + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + tinyMCE.settings['base_href'] + '" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';
\r
6013 if (!this.isHidden())
\r
6014 this.getDoc().designMode = "on";
\r
6020 // Failed Mozilla 1.3
\r
6021 this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";
\r
6025 // This timeout is needed in MSIE 5.5 for some odd reason
\r
6026 // it seems that the document.frames isn't initialized yet?
\r
6027 if (tinyMCE.isMSIE)
\r
6028 window.setTimeout("TinyMCE.prototype.addEventHandlers('" + this.editorId + "');", 1);
\r
6030 tinyMCE.setupContent(this.editorId, true);
\r
6035 TinyMCEControl.prototype.getFocusElement = function() {
\r
6036 if (tinyMCE.isMSIE && !tinyMCE.isOpera) {
\r
6037 var doc = this.getDoc();
\r
6038 var rng = doc.selection.createRange();
\r
6040 // if (rng.collapse)
\r
6041 // rng.collapse(true);
\r
6043 var elm = rng.item ? rng.item(0) : rng.parentElement();
\r
6045 if (this.isHidden())
\r
6046 return this.getBody();
\r
6048 var sel = this.getSel();
\r
6049 var rng = this.getRng();
\r
6051 var elm = rng.commonAncestorContainer;
\r
6052 //var elm = (sel && sel.anchorNode) ? sel.anchorNode : null;
\r
6054 // Handle selection a image or other control like element such as anchors
\r
6055 if (!rng.collapsed) {
\r
6056 // Is selection small
\r
6057 if (rng.startContainer == rng.endContainer) {
\r
6058 if (rng.startOffset - rng.endOffset < 2) {
\r
6059 if (rng.startContainer.hasChildNodes())
\r
6060 elm = rng.startContainer.childNodes[rng.startOffset];
\r
6065 // Get the element parent of the node
\r
6066 elm = tinyMCE.getParentElement(elm);
\r
6068 //if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")
\r
6069 // elm = tinyMCE.selectedElement;
\r
6075 // Global instances
\r
6076 var tinyMCE = new TinyMCE();
\r
6077 var tinyMCELang = new Array();
\r