Browse code

tinyMCE '2' is now 2.1.2 - Seems tinyMCE '2' was actually 3.0.9 (my fault for not checking), so '2' is now 2.1.2, and '3' is now 3.4.8... eFiction 3.4.3 used tinyMCE 2.1.0, and 3.5 upgraded that to 3.0.9.

Clarissa Walker authored on 2026/07/28 07:20:33
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,1878 @@
1
+/**
2
+ * $Id$
3
+ *
4
+ * @author Moxiecode
5
+ * @copyright Copyright � 2004-2007, Moxiecode Systems AB, All rights reserved.
6
+ */
7
+
8
+/**
9
+ * This is the TinyMCE editor control instance class. A instance of this class will is made for each
10
+ * converted text area.
11
+ *
12
+ * @constructor
13
+ * @param {Array} settings Name/Value array of instance specific configuration settings.
14
+ */
15
+function TinyMCE_Control(settings) {
16
+	var t, i, tos, fu, p, x, fn, fu, pn, s = settings;
17
+
18
+	this.undoRedoLevel = true;
19
+	this.isTinyMCE_Control = true;
20
+
21
+	// Default settings
22
+	this.enabled = true;
23
+	this.settings = s;
24
+	this.settings.theme = tinyMCE.getParam("theme", "default");
25
+	this.settings.width = tinyMCE.getParam("width", -1);
26
+	this.settings.height = tinyMCE.getParam("height", -1);
27
+	this.selection = new TinyMCE_Selection(this);
28
+	this.undoRedo = new TinyMCE_UndoRedo(this);
29
+	this.cleanup = new TinyMCE_Cleanup();
30
+	this.shortcuts = [];
31
+	this.hasMouseMoved = false;
32
+	this.foreColor = this.backColor = "#999999";
33
+	this.data = {};
34
+	this.cssClasses = [];
35
+
36
+	this.cleanup.init({
37
+		valid_elements : s.valid_elements,
38
+		extended_valid_elements : s.extended_valid_elements,
39
+		valid_child_elements : s.valid_child_elements,
40
+		entities : s.entities,
41
+		entity_encoding : s.entity_encoding,
42
+		debug : s.cleanup_debug,
43
+		indent : s.apply_source_formatting,
44
+		invalid_elements : s.invalid_elements,
45
+		verify_html : s.verify_html,
46
+		fix_content_duplication : s.fix_content_duplication,
47
+		convert_fonts_to_spans : s.convert_fonts_to_spans
48
+	});
49
+
50
+	// Wrap old theme
51
+	t = this.settings.theme;
52
+	if (!tinyMCE.hasTheme(t)) {
53
+		fn = tinyMCE.callbacks;
54
+		tos = {};
55
+
56
+		for (i=0; i<fn.length; i++) {
57
+			if ((fu = window['TinyMCE_' + t + "_" + fn[i]]))
58
+				tos[fn[i]] = fu;
59
+		}
60
+
61
+		tinyMCE.addTheme(t, tos);
62
+	}
63
+
64
+	// Wrap old plugins
65
+	this.plugins = [];
66
+	p = tinyMCE.getParam('plugins', '', true, ',');
67
+	if (p.length > 0) {
68
+		for (i=0; i<p.length; i++) {
69
+			pn = p[i];
70
+
71
+			if (pn.charAt(0) == '-')
72
+				pn = pn.substring(1);
73
+
74
+			if (!tinyMCE.hasPlugin(pn)) {
75
+				fn = tinyMCE.callbacks;
76
+				tos = {};
77
+
78
+				for (x=0; x<fn.length; x++) {
79
+					if ((fu = window['TinyMCE_' + pn + "_" + fn[x]]))
80
+						tos[fn[x]] = fu;
81
+				}
82
+
83
+				tinyMCE.addPlugin(pn, tos);
84
+			}
85
+
86
+			this.plugins[this.plugins.length] = pn; 
87
+		}
88
+	}
89
+};
90
+
91
+/**#@+
92
+ * @member TinyMCE_Control
93
+ */
94
+TinyMCE_Control.prototype = {
95
+	/**#@+
96
+	 * @field
97
+	 */
98
+
99
+	/**
100
+	 * Contains methods for handling the current instance selection.
101
+	 *
102
+	 * @type TinyMCE_Selection
103
+	 */
104
+	selection : null,
105
+
106
+	/**
107
+	 * Name/Value array containing all instance settings.
108
+	 *
109
+	 * @type Array
110
+	 */
111
+	settings : null,
112
+
113
+	/**
114
+	 * Cleanup engine reference, handles all XHTML serialization and cleanup.
115
+	 *
116
+	 * @type TinyMCE_Cleanup
117
+	 */
118
+	cleanup : null,
119
+
120
+	/**#@+
121
+	 * @method
122
+	 */
123
+
124
+	/**
125
+	 * Get custom data storage object by name. The name should be for example the theme name or plugin name.
126
+	 * The custom data storage can be used to store plugin/theme specific information on a editor instance. A empty
127
+	 * object will be created automaticly the first time called.
128
+	 *
129
+	 * @param {String} na Name of data storate to retrive.
130
+	 * @return Data storage object
131
+	 * @type Object
132
+	 */
133
+	getData : function(na) {
134
+		var o = this.data[na];
135
+
136
+		if (!o)
137
+			o = this.data[na] = {};
138
+
139
+		return o;
140
+	},
141
+
142
+	/**
143
+	 * Returns true/false if the instance has the current plugin available.
144
+	 *
145
+	 * @param {string} n Plugin name to check for.
146
+	 * @return true/false if the instance has the current plugin available.
147
+	 * @type boolean
148
+	 */
149
+	hasPlugin : function(n) {
150
+		var i;
151
+
152
+		for (i=0; i<this.plugins.length; i++) {
153
+			if (this.plugins[i] == n)
154
+				return true;
155
+		}
156
+
157
+		return false;
158
+	},
159
+
160
+	/**
161
+	 * Adds a plugin to the editor instance. This will also add it globaly.
162
+	 *
163
+	 * @param {string} n Plugin name to check for.
164
+	 * @param {TinyMCE_Plugin} n TinyMCE plugin instance.
165
+	 */
166
+	addPlugin : function(n, p) {
167
+		if (!this.hasPlugin(n)) {
168
+			tinyMCE.addPlugin(n, p);
169
+			this.plugins[this.plugins.length] = n;
170
+		}
171
+	},
172
+
173
+	/**
174
+	 * Repaints the editarea in Gecko browsers. This method removes ghost resize handlers
175
+	 * and other trailing graphics.
176
+	 */
177
+	repaint : function() {
178
+		var s, b, ex;
179
+
180
+		if (tinyMCE.isRealIE)
181
+			return;
182
+
183
+		try {
184
+			s = this.selection;
185
+			b = s.getBookmark(true);
186
+			this.getBody().style.display = 'none';
187
+			this.getDoc().execCommand('selectall', false, null);
188
+			this.getSel().collapseToStart();
189
+			this.getBody().style.display = 'block';
190
+			s.moveToBookmark(b);
191
+		} catch (ex) {
192
+			// Ignore
193
+		}
194
+	},
195
+
196
+	/**
197
+	 * Switches the global TinyMCE settings to the current instance settings. This method is
198
+	 * used to handle multiple configurations.
199
+	 */
200
+	switchSettings : function() {
201
+		if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings.index) {
202
+			tinyMCE.settings = this.settings;
203
+			tinyMCE.currentConfig = this.settings.index;
204
+		}
205
+	},
206
+
207
+	/**
208
+	 * Selects this instance as the currently selected instance. This will also dispatch a selectInstance call to all
209
+	 * themes, plugins and other listeners.
210
+	 */
211
+	select : function() {
212
+		var oldInst = tinyMCE.selectedInstance;
213
+
214
+		if (oldInst != this) {
215
+			if (oldInst)
216
+				oldInst.execCommand('mceEndTyping');
217
+
218
+			tinyMCE.dispatchCallback(this, 'select_instance_callback', 'selectInstance', this, oldInst);
219
+			tinyMCE.selectedInstance = this;
220
+		}
221
+	},
222
+
223
+	/**
224
+	 * Returns the body element of a editor instance.
225
+	 *
226
+	 * @return Body element of a editor instance.
227
+	 * @type HTMLElement
228
+	 */
229
+	getBody : function() {
230
+		return this.contentBody ? this.contentBody : this.getDoc().body;
231
+	},
232
+
233
+	/**
234
+	 * Returns the DOM document of a editor instance.
235
+	 *
236
+	 * @return DOM document of a editor instance.
237
+	 * @type DOMDocument
238
+	 */
239
+	getDoc : function() {
240
+//		return this.contentDocument ? this.contentDocument : this.contentWindow.document; // Removed due to IE 5.5 ?
241
+		return this.contentWindow.document;
242
+	},
243
+
244
+	/**
245
+	 * Returns the window of a editor instance.
246
+	 *
247
+	 * @return Window of a editor instance.
248
+	 * @type Window
249
+	 */
250
+	getWin : function() {
251
+		return this.contentWindow;
252
+	},
253
+
254
+	/**
255
+	 * Returns the container window of a editor instance. The container window is the window where the current instance lives in.
256
+	 *
257
+	 * @return container window of a editor instance.
258
+	 * @type DOMDocument
259
+	 */
260
+	getContainerWin : function() {
261
+		return this.containerWindow ? this.containerWindow : window;
262
+	},
263
+
264
+	/**
265
+	 * Returns the viewport of the editor instance.
266
+	 *
267
+	 * @return Viewport object with fields top, left, width and height.
268
+	 * @type Object
269
+	 */
270
+	getViewPort : function() {
271
+		return tinyMCE.getViewPort(this.getWin());
272
+	},
273
+
274
+	/**
275
+	 * Returns a node by the specified selector function. This function will
276
+	 * loop through all parent nodes and call the specified function for each node.
277
+	 * If the function then returns true it will stop the execution and return that node.
278
+	 * This function will not go below the instance body element.
279
+	 *
280
+	 * @param {DOMNode} n HTML node to search parents on.
281
+	 * @param {function} f Selection function to execute on each node.
282
+	 * @return DOMNode or null if it wasn't found.
283
+	 * @type DOMNode
284
+	 */
285
+	getParentNode : function(n, f) {
286
+		return tinyMCE.getParentNode(n, f, this.getBody());
287
+	},
288
+
289
+	/**
290
+	 * Returns the parent element of the specified node based on the search criteria.
291
+	 * This method will not go below the point of the instance body.
292
+	 *
293
+	 * @param {HTMLNode} node Node to get parent element of.
294
+	 * @param {string} na Comma separated list of element names to get.
295
+	 * @param {function} f Optional function to call for each node, if it returns true the node is valid.
296
+	 * @return HTMLElement or null based on search criteras.
297
+	 * @type HTMLElement
298
+	 */
299
+	getParentElement : function(n, na, f) {
300
+		return tinyMCE.getParentElement(n, na, f, this.getBody());
301
+	},
302
+
303
+	/**
304
+	 * Returns the first block element parent of the specified node.
305
+	 * This method will not go below the point of the instance body.
306
+	 *
307
+	 * @param {HTMLNode} n Node get parent block element for.
308
+	 * @return First block element parent of the specified node or null if it wasn't found.
309
+	 * @type HTMLElement
310
+	 */
311
+	getParentBlockElement : function(n) {
312
+		return tinyMCE.getParentBlockElement(n, this.getBody());
313
+	},
314
+
315
+	/**
316
+	 * Auto resizes the current editor instance to match the inner document size.
317
+	 */
318
+	resizeToContent : function() {
319
+		var d = this.getDoc(), b = d.body, de = d.documentElement;
320
+
321
+		this.iframeElement.style.height = (tinyMCE.isRealIE) ? b.scrollHeight : de.offsetHeight + 'px';
322
+	},
323
+
324
+	/**
325
+	 * Adds a keyboard shortcut to a specific command. These shortcuts can for example be added
326
+	 * at the initInstance callback of a plugin. The shortcut description can be a language variable name
327
+	 * or a string describing the function. If you don't specify a command, the shortcut will simply be a blocker
328
+	 * shortcut. This enables you to remove built in shortcuts or remove theme specific shortcuts from a plugin.<br />
329
+	 * Example shortcut inst.addShortcut('ctrl,alt', 'k', 'mceSomeCommand', false, 'somevalue');
330
+	 * Example blocker inst.addShortcut('ctrl,alt', 'k');
331
+	 *
332
+	 * @param {string} m List of shortcut modifiers keys, for example "ctrl,alt".
333
+	 * @param {Object} k Shortcut key char for example "s" or a keycode value "13".
334
+	 * @param {string} d Optional Shortcut description, this will be presented in the about dialog.
335
+	 * @param {string} cmd Optional Command name to execute, for example mceLink or Bold.
336
+	 * @param {boolean} ui Optional True/false state if a UI (dialog) should be presented or not.
337
+	 * @param {Object} va Optional command value, this can be anything.
338
+	 * @return true/false if the shortcut was added or not
339
+	 * @type boolean
340
+	 */
341
+	addShortcut : function(m, k, d, cmd, ui, va) {
342
+		var n = typeof(k) == "number", ie = tinyMCE.isIE, c, sc, i, scl = this.shortcuts;
343
+
344
+		if (!tinyMCE.getParam('custom_shortcuts'))
345
+			return false;
346
+
347
+		m = m.toLowerCase();
348
+		k = ie && !n ? k.toUpperCase() : k;
349
+		c = n ? null : k.charCodeAt(0);
350
+		d = d && d.indexOf('lang_') == 0 ? tinyMCE.getLang(d) : d;
351
+
352
+		sc = {
353
+			alt : m.indexOf('alt') != -1,
354
+			ctrl : m.indexOf('ctrl') != -1,
355
+			shift : m.indexOf('shift') != -1,
356
+			charCode : c,
357
+			keyCode : n ? k : (ie ? c : null),
358
+			desc : d,
359
+			cmd : cmd,
360
+			ui : ui,
361
+			val : va
362
+		};
363
+
364
+		for (i=0; i<scl.length; i++) {
365
+			if (sc.alt == scl[i].alt && sc.ctrl == scl[i].ctrl && sc.shift == scl[i].shift
366
+				&& sc.charCode == scl[i].charCode && sc.keyCode == scl[i].keyCode) {
367
+				return false;
368
+			}
369
+		}
370
+
371
+		scl[scl.length] = sc;
372
+
373
+		return true;
374
+	},
375
+
376
+	/**
377
+	 * Executes shortcuts based on the event information.
378
+	 *
379
+	 * @param {DOMEvent} e Keyboard event to handle.
380
+	 * @return true/false if the shortcut was found and executed or not.
381
+	 * @type boolean
382
+	 */
383
+	handleShortcut : function(e) {
384
+		var i, s, o;
385
+
386
+		// Normal key press, then ignore it
387
+		if (!e.altKey && !e.ctrlKey)
388
+			return false;
389
+
390
+		s = this.shortcuts;
391
+
392
+		for (i=0; i<s.length; i++) {
393
+			o = s[i];
394
+
395
+			if (o.alt == e.altKey && o.ctrl == e.ctrlKey && (o.keyCode == e.keyCode || o.charCode == e.charCode)) {
396
+				if (o.cmd && (e.type == "keydown" || (e.type == "keypress" && !tinyMCE.isOpera)))
397
+					tinyMCE.execCommand(o.cmd, o.ui, o.val);
398
+
399
+				tinyMCE.cancelEvent(e);
400
+				return true;
401
+			}
402
+		}
403
+
404
+		return false;
405
+	},
406
+
407
+	/**
408
+	 * Auto resets the design mode of the document if it gets lost.
409
+	 * This is a Gecko specific function since it's a workaround for a bug where Gecko browsers
410
+	 * loose the designMode state if the editor is hidden and shown in a tab or div.
411
+	 */
412
+	autoResetDesignMode : function() {
413
+		// Add fix for tab/style.display none/block problems in Gecko
414
+		if (!tinyMCE.isIE && this.isHidden() && tinyMCE.getParam('auto_reset_designmode'))
415
+			eval('try { this.getDoc().designMode = "On"; this.useCSS = false; } catch(e) {}');
416
+	},
417
+
418
+	/**
419
+	 * Returns if the instance is hidden or not. This is a Gecko specific function
420
+	 * other browsers will always return false. This function is used to workaround the lost
421
+	 * designMode bug in Gecko browsers.
422
+	 *
423
+	 * @return Returns if the instance is hidden or not.
424
+	 * @type boolean
425
+	 */
426
+	isHidden : function() {
427
+		var s;
428
+
429
+		if (tinyMCE.isIE)
430
+			return false;
431
+
432
+		s = this.getSel();
433
+
434
+		// Weird, wheres that cursor selection?
435
+		return (!s || !s.rangeCount || s.rangeCount == 0);
436
+	},
437
+
438
+	/**
439
+	 * Returns true/false if the editor instance is dirty or not. In other words if it has been modified
440
+	 * or not.
441
+	 *
442
+	 * @return Editor instance dirty state.
443
+	 * @type boolean
444
+	 */
445
+	isDirty : function() {
446
+		// Is content modified and not in a submit procedure
447
+		return tinyMCE.trim(this.startContent) != tinyMCE.trim(this.getBody().innerHTML) && !this.isNotDirty;
448
+	},
449
+
450
+	/**
451
+	 * ..
452
+	 *
453
+	 * @private
454
+	 */
455
+	_mergeElements : function(scmd, pa, ch, override) {
456
+		var st, stc, className, n;
457
+
458
+		if (scmd == "removeformat") {
459
+			pa.className = "";
460
+			pa.style.cssText = "";
461
+			ch.className = "";
462
+			ch.style.cssText = "";
463
+			return;
464
+		}
465
+
466
+		st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));
467
+		stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));
468
+		className = tinyMCE.getAttrib(pa, "class");
469
+
470
+		// Removed class adding due to bug #1478272
471
+		className = tinyMCE.getAttrib(ch, "class");
472
+
473
+		if (override) {
474
+			for (n in st) {
475
+				if (typeof(st[n]) == 'function')
476
+					continue;
477
+
478
+				stc[n] = st[n];
479
+			}
480
+		} else {
481
+			for (n in stc) {
482
+				if (typeof(stc[n]) == 'function')
483
+					continue;
484
+
485
+				st[n] = stc[n];
486
+			}
487
+		}
488
+
489
+		tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));
490
+		tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));
491
+		ch.className = "";
492
+		ch.style.cssText = "";
493
+		ch.removeAttribute("class");
494
+		ch.removeAttribute("style");
495
+	},
496
+
497
+	/**
498
+	 * Generates root level block elements such a P for inline elements and text nodes.
499
+	 */
500
+	_fixRootBlocks : function() {
501
+		var rb, b, ne, be, nx, bm;
502
+
503
+		rb = tinyMCE.getParam('forced_root_block');
504
+		if (!rb)
505
+			return;
506
+
507
+		b = this.getBody();
508
+		ne = b.firstChild;
509
+
510
+		while (ne) {
511
+			nx = ne.nextSibling;
512
+
513
+			// If text node or inline element wrap it in a block element
514
+			if ((ne.nodeType == 3 && ne.nodeValue.replace(/\s+/g, '') != '') || (ne.nodeType == 1 && !tinyMCE.blockRegExp.test(ne.nodeName))) {
515
+				if (!bm)
516
+					bm = this.selection.getBookmark();
517
+
518
+				if (!be) {
519
+					be = this.getDoc().createElement(rb);
520
+					be.appendChild(ne.cloneNode(true));
521
+					b.replaceChild(be, ne);
522
+				} else {
523
+					be.appendChild(ne.cloneNode(true));
524
+					b.removeChild(ne);
525
+				}
526
+			} else
527
+				be = null;
528
+
529
+			ne = nx;
530
+		}
531
+
532
+		if (bm)
533
+			this.selection.moveToBookmark(bm);
534
+	},
535
+
536
+	/**
537
+	 * Removes any traling &nbsp; to the current block element.
538
+	 */
539
+	_fixTrailingNbsp : function() {
540
+		var s = this.selection, e = s.getFocusElement(), bm, v;
541
+
542
+		if (e && tinyMCE.blockRegExp.test(e.nodeName) && e.firstChild) {
543
+			v = e.firstChild.nodeValue;
544
+
545
+			if (v && v.length > 1 && /(^\u00a0|\u00a0$)/.test(v)) {
546
+				e.firstChild.nodeValue = v.replace(/(^\u00a0|\u00a0$)/, '');
547
+				s.selectNode(e.firstChild, true, false, false); // Select and collapse
548
+			}
549
+		}
550
+	},
551
+
552
+	/**
553
+	 * Sets the useCSS mode in Gecko browsers. This will also remove the build in
554
+	 * inline table editing controls since they are buggy when it comes to col/rowspans.
555
+	 *
556
+	 * @param {boolean} b UseCSS state true/false.
557
+	 * @private
558
+	 */
559
+	_setUseCSS : function(b) {
560
+		var d = this.getDoc();
561
+
562
+		try {d.execCommand("useCSS", false, !b);} catch (ex) {}
563
+		try {d.execCommand("styleWithCSS", false, b);} catch (ex) {}
564
+
565
+		if (!tinyMCE.getParam("table_inline_editing"))
566
+			try {d.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}
567
+
568
+		if (!tinyMCE.getParam("object_resizing"))
569
+			try {d.execCommand('enableObjectResizing', false, "false");} catch (ex) {}
570
+	},
571
+
572
+	/**
573
+	 * Executes a command on the current instance. These commands can be TinyMCE internal commands prefixed with "mce" or
574
+	 * they can be build in browser commands such as "Bold". A compleate list of browser commands is available on MSDN or Mozilla.org.
575
+	 * This function will dispatch the execCommand function on each plugin, theme or the execcommand_callback option if none of these
576
+	 * return true it will handle the command as a internal browser command.
577
+	 *
578
+	 * @param {string} command Command name to execute, for example mceLink or Bold.
579
+	 * @param {boolean} user_interface True/false state if a UI (dialog) should be presented or not.
580
+	 * @param {mixed} value Optional command value, this can be anything.
581
+	 */
582
+	execCommand : function(command, user_interface, value) {
583
+		var i, x, z, align, img, div, doc = this.getDoc(), win = this.getWin(), focusElm = this.getFocusElement();
584
+
585
+		// Is not a undo specific command
586
+		if (!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command))
587
+			this.undoBookmark = null;
588
+
589
+		// Mozilla issue
590
+		if (!tinyMCE.isIE && !this.useCSS) {
591
+			this._setUseCSS(false);
592
+			this.useCSS = true;
593
+		}
594
+
595
+		//debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);
596
+		this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks
597
+
598
+		// Don't dispatch key commands
599
+		if (!/mceStartTyping|mceEndTyping/.test(command)) {
600
+			if (tinyMCE.execCommandCallback(this, 'execcommand_callback', 'execCommand', this.editorId, this.getBody(), command, user_interface, value))
601
+				return;
602
+		}
603
+
604
+		// Fix align on images
605
+		if (focusElm && focusElm.nodeName == "IMG") {
606
+			align = focusElm.getAttribute('align');
607
+			img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;
608
+
609
+			switch (command) {
610
+				case "JustifyLeft":
611
+					if (align == 'left') {
612
+						img.setAttribute('align', ''); // Needed for IE
613
+						img.removeAttribute('align');
614
+					} else
615
+						img.setAttribute('align', 'left');
616
+
617
+					// Remove the div
618
+					div = focusElm.parentNode;
619
+					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
620
+						div.parentNode.replaceChild(img, div);
621
+
622
+					this.selection.selectNode(img);
623
+					this.repaint();
624
+					tinyMCE.triggerNodeChange();
625
+					return;
626
+
627
+				case "JustifyCenter":
628
+					img.setAttribute('align', ''); // Needed for IE
629
+					img.removeAttribute('align');
630
+
631
+					// Is centered
632
+					div = tinyMCE.getParentElement(focusElm, "div");
633
+					if (div && div.style.textAlign == "center") {
634
+						// Remove div
635
+						if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
636
+							div.parentNode.replaceChild(img, div);
637
+					} else {
638
+						// Add div
639
+						div = this.getDoc().createElement("div");
640
+						div.style.textAlign = 'center';
641
+						div.appendChild(img);
642
+						focusElm.parentNode.replaceChild(div, focusElm);
643
+					}
644
+
645
+					this.selection.selectNode(img);
646
+					this.repaint();
647
+					tinyMCE.triggerNodeChange();
648
+					return;
649
+
650
+				case "JustifyRight":
651
+					if (align == 'right') {
652
+						img.setAttribute('align', ''); // Needed for IE
653
+						img.removeAttribute('align');
654
+					} else
655
+						img.setAttribute('align', 'right');
656
+
657
+					// Remove the div
658
+					div = focusElm.parentNode;
659
+					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
660
+						div.parentNode.replaceChild(img, div);
661
+
662
+					this.selection.selectNode(img);
663
+					this.repaint();
664
+					tinyMCE.triggerNodeChange();
665
+					return;
666
+			}
667
+		}
668
+
669
+		if (tinyMCE.settings.force_br_newlines) {
670
+			var alignValue = "";
671
+
672
+			if (doc.selection.type != "Control") {
673
+				switch (command) {
674
+						case "JustifyLeft":
675
+							alignValue = "left";
676
+							break;
677
+
678
+						case "JustifyCenter":
679
+							alignValue = "center";
680
+							break;
681
+
682
+						case "JustifyFull":
683
+							alignValue = "justify";
684
+							break;
685
+
686
+						case "JustifyRight":
687
+							alignValue = "right";
688
+							break;
689
+				}
690
+
691
+				if (alignValue !== '') {
692
+					var rng = doc.selection.createRange();
693
+
694
+					if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)
695
+						divElm.setAttribute("align", alignValue);
696
+					else if (rng.pasteHTML && rng.htmlText.length > 0)
697
+						rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");
698
+
699
+					tinyMCE.triggerNodeChange();
700
+					return;
701
+				}
702
+			}
703
+		}
704
+
705
+		switch (command) {
706
+			case "mceRepaint":
707
+				this.repaint();
708
+				return true;
709
+
710
+			case "JustifyLeft":
711
+			case "JustifyCenter":
712
+			case "JustifyFull":
713
+			case "JustifyRight":
714
+				var el = tinyMCE.getParentNode(focusElm, function(n) {return tinyMCE.getAttrib(n, 'align');});
715
+
716
+				if (el) {
717
+					el.setAttribute('align', ''); // Needed for IE
718
+					el.removeAttribute('align');
719
+				} else
720
+					this.getDoc().execCommand(command, user_interface, value);
721
+
722
+				tinyMCE.triggerNodeChange();
723
+
724
+				return true;
725
+
726
+			case "unlink":
727
+				// Unlink if caret is inside link
728
+				if (tinyMCE.isGecko && this.getSel().isCollapsed) {
729
+					focusElm = tinyMCE.getParentElement(focusElm, 'A');
730
+
731
+					if (focusElm)
732
+						this.selection.selectNode(focusElm, false);
733
+				}
734
+
735
+				this.getDoc().execCommand(command, user_interface, value);
736
+
737
+				tinyMCE.isGecko && this.getSel().collapseToEnd();
738
+
739
+				tinyMCE.triggerNodeChange();
740
+
741
+				return true;
742
+
743
+			case "InsertUnorderedList":
744
+			case "InsertOrderedList":
745
+				this.getDoc().execCommand(command, user_interface, value);
746
+				tinyMCE.triggerNodeChange();
747
+				break;
748
+
749
+			case "Strikethrough":
750
+				this.getDoc().execCommand(command, user_interface, value);
751
+				tinyMCE.triggerNodeChange();
752
+				break;
753
+
754
+			case "mceSelectNode":
755
+				this.selection.selectNode(value);
756
+				tinyMCE.triggerNodeChange();
757
+				tinyMCE.selectedNode = value;
758
+				break;
759
+
760
+			case "FormatBlock":
761
+				if (value == null || value == '') {
762
+					var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address,blockquote,dt,dl,dd,samp");
763
+
764
+					if (elm)
765
+						this.execCommand("mceRemoveNode", false, elm);
766
+				} else {
767
+					if (!this.cleanup.isValid(value))
768
+						return true;
769
+
770
+					if (tinyMCE.isGecko && new RegExp('<(div|blockquote|code|dt|dd|dl|samp)>', 'gi').test(value))
771
+						value = value.replace(/[^a-z]/gi, '');
772
+
773
+					if (tinyMCE.isIE && new RegExp('blockquote|code|samp', 'gi').test(value)) {
774
+						var b = this.selection.getBookmark();
775
+						this.getDoc().execCommand("FormatBlock", false, '<p>');
776
+						tinyMCE.renameElement(tinyMCE.getParentBlockElement(this.getFocusElement()), value);
777
+						this.selection.moveToBookmark(b);
778
+					} else
779
+						this.getDoc().execCommand("FormatBlock", false, value);
780
+				}
781
+
782
+				tinyMCE.triggerNodeChange();
783
+
784
+				break;
785
+
786
+			case "mceRemoveNode":
787
+				if (!value)
788
+					value = tinyMCE.getParentElement(this.getFocusElement());
789
+
790
+				if (tinyMCE.isIE) {
791
+					value.outerHTML = value.innerHTML;
792
+				} else {
793
+					var rng = value.ownerDocument.createRange();
794
+					rng.setStartBefore(value);
795
+					rng.setEndAfter(value);
796
+					rng.deleteContents();
797
+					rng.insertNode(rng.createContextualFragment(value.innerHTML));
798
+				}
799
+
800
+				tinyMCE.triggerNodeChange();
801
+
802
+				break;
803
+
804
+			case "mceSelectNodeDepth":
805
+				var parentNode = this.getFocusElement();
806
+				for (i=0; parentNode; i++) {
807
+					if (parentNode.nodeName.toLowerCase() == "body")
808
+						break;
809
+
810
+					if (parentNode.nodeName.toLowerCase() == "#text") {
811
+						i--;
812
+						parentNode = parentNode.parentNode;
813
+						continue;
814
+					}
815
+
816
+					if (i == value) {
817
+						this.selection.selectNode(parentNode, false);
818
+						tinyMCE.triggerNodeChange();
819
+						tinyMCE.selectedNode = parentNode;
820
+						return;
821
+					}
822
+
823
+					parentNode = parentNode.parentNode;
824
+				}
825
+
826
+				break;
827
+
828
+			case "mceSetStyleInfo":
829
+			case "SetStyleInfo":
830
+				var rng = this.getRng();
831
+				var sel = this.getSel();
832
+				var scmd = value.command;
833
+				var sname = value.name;
834
+				var svalue = value.value == null ? '' : value.value;
835
+				//var svalue = value['value'] == null ? '' : value['value'];
836
+				var wrapper = value.wrapper ? value.wrapper : "span";
837
+				var parentElm = null;
838
+				var invalidRe = new RegExp("^BODY|HTML$", "g");
839
+				var invalidParentsRe = tinyMCE.settings.merge_styles_invalid_parents !== '' ? new RegExp(tinyMCE.settings.merge_styles_invalid_parents, "gi") : null;
840
+
841
+				// Whole element selected check
842
+				if (tinyMCE.isIE) {
843
+					// Control range
844
+					if (rng.item)
845
+						parentElm = rng.item(0);
846
+					else {
847
+						var pelm = rng.parentElement();
848
+						var prng = doc.selection.createRange();
849
+						prng.moveToElementText(pelm);
850
+
851
+						if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {
852
+							if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))
853
+								parentElm = pelm;
854
+						}
855
+					}
856
+				} else {
857
+					var felm = this.getFocusElement();
858
+					if (sel.isCollapsed || (new RegExp('td|tr|tbody|table|img', 'gi').test(felm.nodeName) && sel.anchorNode == felm.parentNode))
859
+						parentElm = felm;
860
+				}
861
+
862
+				// Whole element selected
863
+				if (parentElm && !invalidRe.test(parentElm.nodeName)) {
864
+					if (scmd == "setstyle")
865
+						tinyMCE.setStyleAttrib(parentElm, sname, svalue);
866
+
867
+					if (scmd == "setattrib")
868
+						tinyMCE.setAttrib(parentElm, sname, svalue);
869
+
870
+					if (scmd == "removeformat") {
871
+						parentElm.style.cssText = '';
872
+						tinyMCE.setAttrib(parentElm, 'class', '');
873
+					}
874
+
875
+					// Remove style/attribs from all children
876
+					var ch = tinyMCE.getNodeTree(parentElm, [], 1);
877
+					for (z=0; z<ch.length; z++) {
878
+						if (ch[z] == parentElm)
879
+							continue;
880
+
881
+						if (scmd == "setstyle")
882
+							tinyMCE.setStyleAttrib(ch[z], sname, '');
883
+
884
+						if (scmd == "setattrib")
885
+							tinyMCE.setAttrib(ch[z], sname, '');
886
+
887
+						if (scmd == "removeformat") {
888
+							ch[z].style.cssText = '';
889
+							tinyMCE.setAttrib(ch[z], 'class', '');
890
+						}
891
+					}
892
+				} else {
893
+					this._setUseCSS(false); // Bug in FF when running in fullscreen
894
+					doc.execCommand("FontName", false, "#mce_temp_font#");
895
+					var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");
896
+
897
+					// Change them all
898
+					for (x=0; x<elementArray.length; x++) {
899
+						elm = elementArray[x];
900
+						if (elm) {
901
+							var spanElm = doc.createElement(wrapper);
902
+
903
+							if (scmd == "setstyle")
904
+								tinyMCE.setStyleAttrib(spanElm, sname, svalue);
905
+
906
+							if (scmd == "setattrib")
907
+								tinyMCE.setAttrib(spanElm, sname, svalue);
908
+
909
+							if (scmd == "removeformat") {
910
+								spanElm.style.cssText = '';
911
+								tinyMCE.setAttrib(spanElm, 'class', '');
912
+							}
913
+
914
+							if (elm.hasChildNodes()) {
915
+								for (i=0; i<elm.childNodes.length; i++)
916
+									spanElm.appendChild(elm.childNodes[i].cloneNode(true));
917
+							}
918
+
919
+							spanElm.setAttribute("mce_new", "true");
920
+							elm.parentNode.replaceChild(spanElm, elm);
921
+
922
+							// Remove style/attribs from all children
923
+							var ch = tinyMCE.getNodeTree(spanElm, [], 1);
924
+							for (z=0; z<ch.length; z++) {
925
+								if (ch[z] == spanElm)
926
+									continue;
927
+
928
+								if (scmd == "setstyle")
929
+									tinyMCE.setStyleAttrib(ch[z], sname, '');
930
+
931
+								if (scmd == "setattrib")
932
+									tinyMCE.setAttrib(ch[z], sname, '');
933
+
934
+								if (scmd == "removeformat") {
935
+									ch[z].style.cssText = '';
936
+									tinyMCE.setAttrib(ch[z], 'class', '');
937
+								}
938
+							}
939
+						}
940
+					}
941
+				}
942
+
943
+				// Cleaup wrappers
944
+				var nodes = doc.getElementsByTagName(wrapper);
945
+				for (i=nodes.length-1; i>=0; i--) {
946
+					var elm = nodes[i];
947
+					var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";
948
+
949
+					elm.removeAttribute("mce_new");
950
+
951
+					// Is only child a element
952
+					if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {
953
+						//tinyMCE.debug("merge1" + isNew);
954
+						this._mergeElements(scmd, elm, elm.childNodes[0], isNew);
955
+						continue;
956
+					}
957
+
958
+					// Is I the only child
959
+					if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {
960
+						//tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);
961
+						if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))
962
+							this._mergeElements(scmd, elm.parentNode, elm, false);
963
+					}
964
+				}
965
+
966
+				// Remove empty wrappers
967
+				var nodes = doc.getElementsByTagName(wrapper);
968
+				for (i=nodes.length-1; i>=0; i--) {
969
+					var elm = nodes[i], isEmpty = true;
970
+
971
+					// Check if it has any attribs
972
+					var tmp = doc.createElement("body");
973
+					tmp.appendChild(elm.cloneNode(false));
974
+
975
+					// Is empty span, remove it
976
+					tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');
977
+					//tinyMCE.debug(tmp.innerHTML);
978
+					if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {
979
+						for (x=0; x<elm.childNodes.length; x++) {
980
+							if (elm.parentNode != null)
981
+								elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);
982
+						}
983
+
984
+						elm.parentNode.removeChild(elm);
985
+					}
986
+				}
987
+
988
+				// Re add the visual aids
989
+				if (scmd == "removeformat")
990
+					tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
991
+
992
+				tinyMCE.triggerNodeChange();
993
+
994
+				break;
995
+
996
+			case "FontName":
997
+				if (value == null) {
998
+					var s = this.getSel();
999
+
1000
+					// Find font and select it
1001
+					if (tinyMCE.isGecko && s.isCollapsed) {
1002
+						var f = tinyMCE.getParentElement(this.getFocusElement(), "font");
1003
+
1004
+						if (f != null)
1005
+							this.selection.selectNode(f, false);
1006
+					}
1007
+
1008
+					// Remove format
1009
+					this.getDoc().execCommand("RemoveFormat", false, null);
1010
+
1011
+					// Collapse range if font was found
1012
+					if (f != null && tinyMCE.isGecko) {
1013
+						var r = this.getRng().cloneRange();
1014
+						r.collapse(true);
1015
+						s.removeAllRanges();
1016
+						s.addRange(r);
1017
+					}
1018
+				} else
1019
+					this.getDoc().execCommand('FontName', false, value);
1020
+
1021
+				if (tinyMCE.isGecko)
1022
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
1023
+
1024
+				return;
1025
+
1026
+			case "FontSize":
1027
+				this.getDoc().execCommand('FontSize', false, value);
1028
+
1029
+				if (tinyMCE.isGecko)
1030
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
1031
+
1032
+				return;
1033
+
1034
+			case "forecolor":
1035
+				value = value == null ? this.foreColor : value;
1036
+				value = tinyMCE.trim(value);
1037
+				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
1038
+
1039
+				this.foreColor = value;
1040
+				this.getDoc().execCommand('forecolor', false, value);
1041
+				break;
1042
+
1043
+			case "HiliteColor":
1044
+				value = value == null ? this.backColor : value;
1045
+				value = tinyMCE.trim(value);
1046
+				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
1047
+				this.backColor = value;
1048
+
1049
+				if (tinyMCE.isGecko || tinyMCE.isOpera) {
1050
+					this._setUseCSS(true);
1051
+					this.getDoc().execCommand('hilitecolor', false, value);
1052
+					this._setUseCSS(false);
1053
+				} else
1054
+					this.getDoc().execCommand('BackColor', false, value);
1055
+				break;
1056
+
1057
+			case "Cut":
1058
+			case "Copy":
1059
+			case "Paste":
1060
+				var cmdFailed = false;
1061
+
1062
+				// Try executing command
1063
+				eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');
1064
+
1065
+				if (tinyMCE.isOpera && cmdFailed)
1066
+					alert('Currently not supported by your browser, use keyboard shortcuts instead.');
1067
+
1068
+				// Alert error in gecko if command failed
1069
+				if (tinyMCE.isGecko && cmdFailed) {
1070
+					// Confirm more info
1071
+					if (confirm(tinyMCE.entityDecode(tinyMCE.getLang('lang_clipboard_msg'))))
1072
+						window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');
1073
+
1074
+					return;
1075
+				} else
1076
+					tinyMCE.triggerNodeChange();
1077
+			break;
1078
+
1079
+			case "mceSetContent":
1080
+				if (!value)
1081
+					value = "";
1082
+
1083
+				// Call custom cleanup code
1084
+				value = tinyMCE.storeAwayURLs(value);
1085
+				value = tinyMCE._customCleanup(this, "insert_to_editor", value);
1086
+
1087
+				if (this.getBody().nodeName == 'BODY')
1088
+					tinyMCE._setHTML(doc, value);
1089
+				else
1090
+					this.getBody().innerHTML = value;
1091
+
1092
+				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, doc, this.settings, this.getBody(), false, false, false, true));
1093
+				tinyMCE.convertAllRelativeURLs(this.getBody());
1094
+
1095
+				// Cleanup any mess left from storyAwayURLs
1096
+				tinyMCE._removeInternal(this.getBody());
1097
+
1098
+				// When editing always use fonts internaly
1099
+				if (tinyMCE.getParam("convert_fonts_to_spans"))
1100
+					tinyMCE.convertSpansToFonts(doc);
1101
+
1102
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
1103
+				tinyMCE._setEventsEnabled(this.getBody(), false);
1104
+				this._addBogusBR();
1105
+
1106
+				return true;
1107
+
1108
+			case "mceCleanup":
1109
+				var b = this.selection.getBookmark();
1110
+				tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);
1111
+				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));
1112
+				tinyMCE.convertAllRelativeURLs(doc.body);
1113
+
1114
+				// When editing always use fonts internaly
1115
+				if (tinyMCE.getParam("convert_fonts_to_spans"))
1116
+					tinyMCE.convertSpansToFonts(doc);
1117
+
1118
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
1119
+				tinyMCE._setEventsEnabled(this.getBody(), false);
1120
+				this._addBogusBR();
1121
+				this.repaint();
1122
+				this.selection.moveToBookmark(b);
1123
+				tinyMCE.triggerNodeChange();
1124
+			break;
1125
+
1126
+			case "mceReplaceContent":
1127
+				// Force empty string
1128
+				if (!value)
1129
+					value = '';
1130
+
1131
+				this.getWin().focus();
1132
+
1133
+				var selectedText = "";
1134
+
1135
+				if (tinyMCE.isIE) {
1136
+					var rng = doc.selection.createRange();
1137
+					selectedText = rng.text;
1138
+				} else
1139
+					selectedText = this.getSel().toString();
1140
+
1141
+				if (selectedText.length > 0) {
1142
+					value = tinyMCE.replaceVar(value, "selection", selectedText);
1143
+					tinyMCE.execCommand('mceInsertContent', false, value);
1144
+				}
1145
+
1146
+				this._addBogusBR();
1147
+				tinyMCE.triggerNodeChange();
1148
+			break;
1149
+
1150
+			case "mceSetAttribute":
1151
+				if (typeof(value) == 'object') {
1152
+					var targetElms = (typeof(value.targets) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value.targets;
1153
+					var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);
1154
+
1155
+					if (targetNode) {
1156
+						targetNode.setAttribute(value.name, value.value);
1157
+						tinyMCE.triggerNodeChange();
1158
+					}
1159
+				}
1160
+			break;
1161
+
1162
+			case "mceSetCSSClass":
1163
+				this.execCommand("mceSetStyleInfo", false, {command : "setattrib", name : "class", value : value});
1164
+			break;
1165
+
1166
+			case "mceInsertRawHTML":
1167
+				var key = 'tiny_mce_marker';
1168
+
1169
+				this.execCommand('mceBeginUndoLevel');
1170
+
1171
+				// Insert marker key
1172
+				this.execCommand('mceInsertContent', false, key);
1173
+
1174
+				// Store away scroll pos
1175
+				var scrollX = this.getBody().scrollLeft + this.getDoc().documentElement.scrollLeft;
1176
+				var scrollY = this.getBody().scrollTop + this.getDoc().documentElement.scrollTop;
1177
+
1178
+				// Find marker and replace with RAW HTML
1179
+				var html = this.getBody().innerHTML;
1180
+				if ((pos = html.indexOf(key)) != -1)
1181
+					tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));
1182
+
1183
+				// Restore scoll pos
1184
+				this.contentWindow.scrollTo(scrollX, scrollY);
1185
+
1186
+				this.execCommand('mceEndUndoLevel');
1187
+
1188
+				break;
1189
+
1190
+			case "mceInsertContent":
1191
+				// Force empty string
1192
+				if (!value)
1193
+					value = '';
1194
+
1195
+				var insertHTMLFailed = false;
1196
+
1197
+				// Removed since it produced problems in IE
1198
+				// this.getWin().focus();
1199
+
1200
+				if (tinyMCE.isGecko || tinyMCE.isOpera) {
1201
+					try {
1202
+						// Is plain text or HTML, &amp;, &nbsp; etc will be encoded wrong in FF
1203
+						if (value.indexOf('<') == -1 && !value.match(/(&#38;|&#160;|&#60;|&#62;)/g)) {
1204
+							var r = this.getRng();
1205
+							var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));
1206
+							var s = this.getSel();
1207
+							var r2 = r.cloneRange();
1208
+
1209
+							// Insert text at cursor position
1210
+							s.removeAllRanges();
1211
+							r.deleteContents();
1212
+							r.insertNode(n);
1213
+
1214
+							// Move the cursor to the end of text
1215
+							r2.selectNode(n);
1216
+							r2.collapse(false);
1217
+							s.removeAllRanges();
1218
+							s.addRange(r2);
1219
+						} else {
1220
+							value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);
1221
+							this.getDoc().execCommand('inserthtml', false, value);
1222
+							tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
1223
+						}
1224
+					} catch (ex) {
1225
+						insertHTMLFailed = true;
1226
+					}
1227
+
1228
+					if (!insertHTMLFailed) {
1229
+						tinyMCE.triggerNodeChange();
1230
+						return;
1231
+					}
1232
+				}
1233
+
1234
+				if (!tinyMCE.isIE) {
1235
+					var isHTML = value.indexOf('<') != -1;
1236
+					var sel = this.getSel();
1237
+					var rng = this.getRng();
1238
+
1239
+					if (isHTML) {
1240
+						if (tinyMCE.isSafari) {
1241
+							var tmpRng = this.getDoc().createRange();
1242
+
1243
+							tmpRng.setStart(this.getBody(), 0);
1244
+							tmpRng.setEnd(this.getBody(), 0);
1245
+
1246
+							value = tmpRng.createContextualFragment(value);
1247
+						} else
1248
+							value = rng.createContextualFragment(value);
1249
+					} else {
1250
+						// Setup text node
1251
+						value = doc.createTextNode(tinyMCE.entityDecode(value));
1252
+					}
1253
+
1254
+					// Insert plain text in Safari
1255
+					if (tinyMCE.isSafari && !isHTML) {
1256
+						this.execCommand('InsertText', false, value.nodeValue);
1257
+						tinyMCE.triggerNodeChange();
1258
+						return true;
1259
+					} else if (tinyMCE.isSafari && isHTML) {
1260
+						rng.deleteContents();
1261
+						rng.insertNode(value);
1262
+						tinyMCE.triggerNodeChange();
1263
+						return true;
1264
+					}
1265
+
1266
+					rng.deleteContents();
1267
+
1268
+					// If target node is text do special treatment, (Mozilla 1.3 fix)
1269
+					if (rng.startContainer.nodeType == 3) {
1270
+						var node = rng.startContainer.splitText(rng.startOffset);
1271
+						node.parentNode.insertBefore(value, node); 
1272
+					} else
1273
+						rng.insertNode(value);
1274
+
1275
+					if (!isHTML) {
1276
+						// Removes weird selection trails
1277
+						sel.selectAllChildren(doc.body);
1278
+						sel.removeAllRanges();
1279
+
1280
+						// Move cursor to end of content
1281
+						var rng = doc.createRange();
1282
+
1283
+						rng.selectNode(value);
1284
+						rng.collapse(false);
1285
+
1286
+						sel.addRange(rng);
1287
+					} else
1288
+						rng.collapse(false);
1289
+
1290
+					tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
1291
+				} else {
1292
+					var rng = doc.selection.createRange(), tmpRng = null;
1293
+					var c = value.indexOf('<!--') != -1;
1294
+
1295
+					// Fix comment bug, add tag before comments
1296
+					if (c)
1297
+						value = tinyMCE.uniqueTag + value;
1298
+
1299
+					//	tmpRng = rng.duplicate(); // Store away range (Fixes Undo bookmark bug in IE)
1300
+
1301
+					if (rng.item)
1302
+						rng.item(0).outerHTML = value;
1303
+					else
1304
+						rng.pasteHTML(value);
1305
+
1306
+					//if (tmpRng)
1307
+					//	tmpRng.select(); // Restore range  (Fixes Undo bookmark bug in IE)
1308
+
1309
+					// Remove unique tag
1310
+					if (c) {
1311
+						var e = this.getDoc().getElementById('mceTMPElement');
1312
+						e.parentNode.removeChild(e);
1313
+					}
1314
+				}
1315
+
1316
+				tinyMCE.execCommand("mceAddUndoLevel");
1317
+				tinyMCE.triggerNodeChange();
1318
+			break;
1319
+
1320
+			case "mceStartTyping":
1321
+				if (tinyMCE.settings.custom_undo_redo && this.undoRedo.typingUndoIndex == -1) {
1322
+					this.undoRedo.typingUndoIndex = this.undoRedo.undoIndex;
1323
+					tinyMCE.typingUndoIndex = tinyMCE.undoIndex;
1324
+					this.execCommand('mceAddUndoLevel');
1325
+				}
1326
+				break;
1327
+
1328
+			case "mceEndTyping":
1329
+				if (tinyMCE.settings.custom_undo_redo && this.undoRedo.typingUndoIndex != -1) {
1330
+					this.execCommand('mceAddUndoLevel');
1331
+					this.undoRedo.typingUndoIndex = -1;
1332
+				}
1333
+
1334
+				tinyMCE.typingUndoIndex = -1;
1335
+				break;
1336
+
1337
+			case "mceBeginUndoLevel":
1338
+				this.undoRedoLevel = false;
1339
+				break;
1340
+
1341
+			case "mceEndUndoLevel":
1342
+				this.undoRedoLevel = true;
1343
+				this.execCommand('mceAddUndoLevel');
1344
+				break;
1345
+
1346
+			case "mceAddUndoLevel":
1347
+				if (tinyMCE.settings.custom_undo_redo && this.undoRedoLevel) {
1348
+					if (this.undoRedo.add())
1349
+						tinyMCE.triggerNodeChange(false);
1350
+				}
1351
+				break;
1352
+
1353
+			case "Undo":
1354
+				if (tinyMCE.settings.custom_undo_redo) {
1355
+					tinyMCE.execCommand("mceEndTyping");
1356
+					this.undoRedo.undo();
1357
+					tinyMCE.triggerNodeChange();
1358
+				} else
1359
+					this.getDoc().execCommand(command, user_interface, value);
1360
+				break;
1361
+
1362
+			case "Redo":
1363
+				if (tinyMCE.settings.custom_undo_redo) {
1364
+					tinyMCE.execCommand("mceEndTyping");
1365
+					this.undoRedo.redo();
1366
+					tinyMCE.triggerNodeChange();
1367
+				} else
1368
+					this.getDoc().execCommand(command, user_interface, value);
1369
+				break;
1370
+
1371
+			case "mceToggleVisualAid":
1372
+				this.visualAid = !this.visualAid;
1373
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
1374
+				tinyMCE.triggerNodeChange();
1375
+				break;
1376
+
1377
+			case "Indent":
1378
+				this.getDoc().execCommand(command, user_interface, value);
1379
+				tinyMCE.triggerNodeChange();
1380
+
1381
+				if (tinyMCE.isIE) {
1382
+					var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");
1383
+					do {
1384
+						if (n && n.nodeName == "BLOCKQUOTE") {
1385
+							n.removeAttribute("dir");
1386
+							n.removeAttribute("style");
1387
+						}
1388
+					} while (n != null && (n = n.parentNode) != null);
1389
+				}
1390
+				break;
1391
+
1392
+			case "RemoveFormat":
1393
+			case "removeformat":
1394
+				var text = this.selection.getSelectedText();
1395
+
1396
+				if (tinyMCE.isOpera) {
1397
+					this.getDoc().execCommand("RemoveFormat", false, null);
1398
+					return;
1399
+				}
1400
+
1401
+				if (tinyMCE.isIE) {
1402
+					try {
1403
+						var rng = doc.selection.createRange();
1404
+						rng.execCommand("RemoveFormat", false, null);
1405
+					} catch (e) {
1406
+						// Do nothing
1407
+					}
1408
+
1409
+					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
1410
+				} else {
1411
+					this.getDoc().execCommand(command, user_interface, value);
1412
+
1413
+					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
1414
+				}
1415
+
1416
+				// Remove class
1417
+				if (text.length == 0)
1418
+					this.execCommand("mceSetCSSClass", false, "");
1419
+
1420
+				tinyMCE.triggerNodeChange();
1421
+				break;
1422
+
1423
+			default:
1424
+				this.getDoc().execCommand(command, user_interface, value);
1425
+
1426
+				if (tinyMCE.isGecko)
1427
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
1428
+				else
1429
+					tinyMCE.triggerNodeChange();
1430
+		}
1431
+
1432
+		// Add undo level after modification
1433
+		if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")
1434
+			tinyMCE.execCommand("mceAddUndoLevel");
1435
+	},
1436
+
1437
+	/**
1438
+	 * Returns a command specific value, for example the current font size.
1439
+	 *
1440
+	 * @param {string} c Command to query value from.
1441
+	 * @return Command specific value, for example the current font size.
1442
+	 * @type mixed
1443
+	 */
1444
+	queryCommandValue : function(c) {
1445
+		try {
1446
+			return this.getDoc().queryCommandValue(c);
1447
+		} catch (e) {
1448
+			return null;
1449
+		}
1450
+	},
1451
+
1452
+	/**
1453
+	 * Returns a command specific state, for example if bold is enabled or not.
1454
+	 *
1455
+	 * @param {string} c Command to query state from.
1456
+	 * @return Command specific state, for example if bold is enabled or not.
1457
+	 * @type boolean
1458
+	 */
1459
+	queryCommandState : function(c) {
1460
+		return this.getDoc().queryCommandState(c);
1461
+	},
1462
+
1463
+	/**
1464
+	 * Adds a bogus BR to make the cursor visible in Gecko.
1465
+	 */
1466
+	_addBogusBR : function() {
1467
+		var b = this.getBody();
1468
+
1469
+		if (tinyMCE.isGecko && !b.hasChildNodes())
1470
+			b.innerHTML = '<br _moz_editor_bogus_node="TRUE" />';
1471
+	},
1472
+
1473
+	/**
1474
+	 * Gets executed when the editor control instance is added.
1475
+	 *
1476
+	 * @param {HTMLElement} replace_element Element to replace with a editor instance.
1477
+	 * @param {string} form_element_name Form element name that gets replaced.
1478
+	 * @param {DOMDocument} target_document Target document reference where the element is located.
1479
+	 * @private
1480
+	 */
1481
+	_onAdd : function(replace_element, form_element_name, target_document) {
1482
+		var hc, th, tos, editorTemplate, targetDoc, deltaWidth, deltaHeight, html, rng, fragment;
1483
+		var dynamicIFrame, tElm, doc, parentElm;
1484
+
1485
+		th = this.settings.theme;
1486
+		tos = tinyMCE.themes[th];
1487
+
1488
+		targetDoc = target_document ? target_document : document;
1489
+
1490
+		this.targetDoc = targetDoc;
1491
+
1492
+		tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings.theme;
1493
+		this.settings.themeurl = tinyMCE.themeURL;
1494
+
1495
+		if (!replace_element) {
1496
+			alert("Error: Could not find the target element.");
1497
+			return false;
1498
+		}
1499
+
1500
+		if (tos.getEditorTemplate)
1501
+			editorTemplate = tos.getEditorTemplate(this.settings, this.editorId);
1502
+
1503
+		deltaWidth = editorTemplate.delta_width ? editorTemplate.delta_width : 0;
1504
+		deltaHeight = editorTemplate.delta_height ? editorTemplate.delta_height : 0;
1505
+		html = '<span id="' + this.editorId + '_parent" class="mceEditorContainer">' + editorTemplate.html;
1506
+
1507
+		html = tinyMCE.replaceVar(html, "editor_id", this.editorId);
1508
+
1509
+		if (!this.settings.default_document)
1510
+			this.settings.default_document = tinyMCE.baseURL + "/blank.htm";
1511
+
1512
+		this.settings.old_width = this.settings.width;
1513
+		this.settings.old_height = this.settings.height;
1514
+
1515
+		// Set default width, height
1516
+		if (this.settings.width == -1)
1517
+			this.settings.width = replace_element.offsetWidth;
1518
+
1519
+		if (this.settings.height == -1)
1520
+			this.settings.height = replace_element.offsetHeight;
1521
+
1522
+		// Try the style width
1523
+		if (this.settings.width == 0)
1524
+			this.settings.width = replace_element.style.width;
1525
+
1526
+		// Try the style height
1527
+		if (this.settings.height == 0)
1528
+			this.settings.height = replace_element.style.height; 
1529
+
1530
+		// If no width/height then default to 320x240, better than nothing
1531
+		if (this.settings.width == 0)
1532
+			this.settings.width = 320;
1533
+
1534
+		if (this.settings.height == 0)
1535
+			this.settings.height = 240;
1536
+
1537
+		this.settings.area_width = parseInt(this.settings.width);
1538
+		this.settings.area_height = parseInt(this.settings.height);
1539
+		this.settings.area_width += deltaWidth;
1540
+		this.settings.area_height += deltaHeight;
1541
+		this.settings.width_style = "" + this.settings.width;
1542
+		this.settings.height_style = "" + this.settings.height;
1543
+
1544
+		// Special % handling
1545
+		if (("" + this.settings.width).indexOf('%') != -1)
1546
+			this.settings.area_width = "100%";
1547
+		else
1548
+			this.settings.width_style += 'px';
1549
+
1550
+		if (("" + this.settings.height).indexOf('%') != -1)
1551
+			this.settings.area_height = "100%";
1552
+		else
1553
+			this.settings.height_style += 'px';
1554
+
1555
+		if (("" + replace_element.style.width).indexOf('%') != -1) {
1556
+			this.settings.width = replace_element.style.width;
1557
+			this.settings.area_width = "100%";
1558
+			this.settings.width_style = "100%";
1559
+		}
1560
+
1561
+		if (("" + replace_element.style.height).indexOf('%') != -1) {
1562
+			this.settings.height = replace_element.style.height;
1563
+			this.settings.area_height = "100%";
1564
+			this.settings.height_style = "100%";
1565
+		}
1566
+
1567
+		html = tinyMCE.applyTemplate(html);
1568
+
1569
+		this.settings.width = this.settings.old_width;
1570
+		this.settings.height = this.settings.old_height;
1571
+
1572
+		this.visualAid = this.settings.visual;
1573
+		this.formTargetElementId = form_element_name;
1574
+
1575
+		// Get replace_element contents
1576
+		if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")
1577
+			this.startContent = replace_element.value;
1578
+		else
1579
+			this.startContent = replace_element.innerHTML;
1580
+
1581
+		// If not text area or input
1582
+		if (replace_element.nodeName != "TEXTAREA" && replace_element.nodeName != "INPUT") {
1583
+			this.oldTargetElement = replace_element;
1584
+
1585
+			// Debug mode
1586
+			hc = '<input type="hidden" id="' + form_element_name + '" name="' + form_element_name + '" />';
1587
+			this.oldTargetDisplay = tinyMCE.getStyle(this.oldTargetElement, 'display', 'inline');
1588
+			this.oldTargetElement.style.display = "none";
1589
+
1590
+			html += '</span>';
1591
+
1592
+			if (tinyMCE.isGecko)
1593
+				html = hc + html;
1594
+			else
1595
+				html += hc;
1596
+
1597
+			// Output HTML and set editable
1598
+			if (tinyMCE.isGecko) {
1599
+				rng = replace_element.ownerDocument.createRange();
1600
+				rng.setStartBefore(replace_element);
1601
+
1602
+				fragment = rng.createContextualFragment(html);
1603
+				tinyMCE.insertAfter(fragment, replace_element);
1604
+			} else
1605
+				replace_element.insertAdjacentHTML("beforeBegin", html);
1606
+		} else {
1607
+			html += '</span>';
1608
+
1609
+			// Just hide the textarea element
1610
+			this.oldTargetElement = replace_element;
1611
+
1612
+			this.oldTargetDisplay = tinyMCE.getStyle(this.oldTargetElement, 'display', 'inline');
1613
+			this.oldTargetElement.style.display = "none";
1614
+
1615
+			// Output HTML and set editable
1616
+			if (tinyMCE.isGecko) {
1617
+				rng = replace_element.ownerDocument.createRange();
1618
+				rng.setStartBefore(replace_element);
1619
+
1620
+				fragment = rng.createContextualFragment(html);
1621
+				tinyMCE.insertAfter(fragment, replace_element);
1622
+			} else
1623
+				replace_element.insertAdjacentHTML("beforeBegin", html);
1624
+		}
1625
+
1626
+		// Setup iframe
1627
+		dynamicIFrame = false;
1628
+		tElm = targetDoc.getElementById(this.editorId);
1629
+
1630
+		if (!tinyMCE.isIE) {
1631
+			// Node case is preserved in XML strict mode
1632
+			if (tElm && (tElm.nodeName == "SPAN" || tElm.nodeName == "span")) {
1633
+				tElm = tinyMCE._createIFrame(tElm, targetDoc);
1634
+				dynamicIFrame = true;
1635
+			}
1636
+
1637
+			this.targetElement = tElm;
1638
+			this.iframeElement = tElm;
1639
+			this.contentDocument = tElm.contentDocument;
1640
+			this.contentWindow = tElm.contentWindow;
1641
+
1642
+			//this.getDoc().designMode = "on";
1643
+		} else {
1644
+			if (tElm && tElm.nodeName == "SPAN")
1645
+				tElm = tinyMCE._createIFrame(tElm, targetDoc, targetDoc.parentWindow);
1646
+			else
1647
+				tElm = targetDoc.frames[this.editorId];
1648
+
1649
+			this.targetElement = tElm;
1650
+			this.iframeElement = targetDoc.getElementById(this.editorId);
1651
+
1652
+			if (tinyMCE.isOpera) {
1653
+				this.contentDocument = this.iframeElement.contentDocument;
1654
+				this.contentWindow = this.iframeElement.contentWindow;
1655
+				dynamicIFrame = true;
1656
+			} else {
1657
+				this.contentDocument = tElm.window.document;
1658
+				this.contentWindow = tElm.window;
1659
+			}
1660
+
1661
+			this.getDoc().designMode = "on";
1662
+		}
1663
+
1664
+		// Setup base HTML
1665
+		doc = this.contentDocument;
1666
+		if (dynamicIFrame) {
1667
+			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>';
1668
+
1669
+			try {
1670
+				if (!this.isHidden())
1671
+					this.getDoc().designMode = "on";
1672
+
1673
+				doc.open();
1674
+				doc.write(html);
1675
+				doc.close();
1676
+			} catch (e) {
1677
+				// Failed Mozilla 1.3
1678
+				this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";
1679
+			}
1680
+		}
1681
+
1682
+		// This timeout is needed in MSIE 5.5 for some odd reason
1683
+		// it seems that the document.frames isn't initialized yet?
1684
+		if (tinyMCE.isIE)
1685
+			window.setTimeout("tinyMCE.addEventHandlers(tinyMCE.instances[\"" + this.editorId + "\"]);", 1);
1686
+
1687
+		// Setup element references
1688
+		parentElm = this.targetDoc.getElementById(this.editorId + '_parent');
1689
+		this.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;
1690
+
1691
+		tinyMCE.setupContent(this.editorId, true);
1692
+
1693
+		return true;
1694
+	},
1695
+
1696
+	/**
1697
+	 * Sets the base href url of the current document instance. This method is used
1698
+	 * to temporarly remove the base url during copy/paste and drag/drop operations
1699
+	 * of relative links from external sites into TinyMCE. MSIE has a bug and converts
1700
+	 * relative links from external sites to absolute links incorrectly.
1701
+	 *
1702
+	 * @param {string} u URL to set as base URL or null to remove it.
1703
+	 */
1704
+	setBaseHREF : function(u) {
1705
+		var h, b, d, nl;
1706
+
1707
+		d = this.getDoc();
1708
+		nl = d.getElementsByTagName("base");
1709
+		b = nl.length > 0 ? nl[0] : null;
1710
+
1711
+		if (!b) {
1712
+			nl = d.getElementsByTagName("head");
1713
+			h = nl.length > 0 ? nl[0] : null;
1714
+
1715
+			b = d.createElement("base");
1716
+			b.setAttribute('href', u);
1717
+			h.appendChild(b);
1718
+		} else {
1719
+			if (u == '' || u == null)
1720
+				b.parentNode.removeChild(b);
1721
+			else
1722
+				b.setAttribute('href', u);
1723
+		}
1724
+	},
1725
+
1726
+	/**
1727
+	 * Returns the cleaned HTML of the editor control instance.
1728
+	 *
1729
+	 * @param {bool} r Optional raw parameter, if set to true. Cleanup will be skipped.
1730
+	 * @return Cleaned HTML content string.
1731
+	 * @type string
1732
+	 */
1733
+	getHTML : function(r) {
1734
+		var h, d = this.getDoc(), b = this.getBody();
1735
+
1736
+		if (r)
1737
+			return b.innerHTML;
1738
+
1739
+		h = tinyMCE._cleanupHTML(this, d, this.settings, b, false, true, false, true);
1740
+
1741
+		if (tinyMCE.getParam("convert_fonts_to_spans"))
1742
+			tinyMCE.convertSpansToFonts(d);
1743
+
1744
+		return h;
1745
+	},
1746
+
1747
+	/**
1748
+	 * Sets the HTML contents of the instance.
1749
+	 *
1750
+	 * @param {string} h HTML content string to replace body with.
1751
+	 */
1752
+	setHTML : function(h) {
1753
+		this.execCommand('mceSetContent', false, h);
1754
+		this.repaint();
1755
+	},
1756
+
1757
+	/**
1758
+	 * Returns the currently selected element. This is was added for compatiblity and is deprecated.
1759
+	 * Please use inst.selection.getFocusElement instead.
1760
+	 *
1761
+	 * @return Currently selected element.
1762
+	 * @type HTMLElement
1763
+	 * @deprecated
1764
+	 */
1765
+	getFocusElement : function() {
1766
+		return this.selection.getFocusElement();
1767
+	},
1768
+
1769
+	/**
1770
+	 * Returns the browsers selection instance. This is was added for compatiblity and is deprecated.
1771
+	 * Please use inst.selection.getSel instead.
1772
+	 *
1773
+	 * @return Browser selection instance.
1774
+	 * @type DOMSelection
1775
+	 * @deprecated
1776
+	 */
1777
+	getSel : function() {
1778
+		return this.selection.getSel();
1779
+	},
1780
+
1781
+	/**
1782
+	 * Returns the browsers selections first range instance. This is was added for compatiblity and is deprecated.
1783
+	 * Please use inst.selection.getRng instead.
1784
+	 *
1785
+	 * @return Browsers selections first range instance.
1786
+	 * @type DOMRange
1787
+	 * @deprecated
1788
+	 */
1789
+	getRng : function() {
1790
+		return this.selection.getRng();
1791
+	},
1792
+
1793
+	/**
1794
+	 * Moves the contents from the TinyMCE editor control instance to the hidden textarea
1795
+	 * that got replaced with TinyMCE. This is executed automaticly on for example form submit unless you configure otherwice.
1796
+	 *
1797
+	 * @param {boolean} skip_cleanup Optional Skip cleanup, simply move the contents as fast as possible.
1798
+	 * @param {boolean} skip_callback Optional Skip callback, don't call the save_callback function.
1799
+	 */
1800
+	triggerSave : function(skip_cleanup, skip_callback) {
1801
+		var e, nl = [], i, s, content, htm;
1802
+
1803
+		if (!this.enabled)
1804
+			return;
1805
+
1806
+		this.switchSettings();
1807
+		s = tinyMCE.settings;
1808
+
1809
+		// Force hidden tabs visible while serializing
1810
+		if (tinyMCE.isRealIE) {
1811
+			e = this.iframeElement;
1812
+
1813
+			do {
1814
+				if (e.style && e.style.display == 'none') {
1815
+					e.style.display = 'block';
1816
+					nl[nl.length] = {elm : e, type : 'style'};
1817
+				}
1818
+
1819
+				if (e.style && s.hidden_tab_class.length > 0 && e.className.indexOf(s.hidden_tab_class) != -1) {
1820
+					e.className = s.display_tab_class;
1821
+					nl[nl.length] = {elm : e, type : 'class'};
1822
+				}
1823
+			} while ((e = e.parentNode) != null)
1824
+		}
1825
+
1826
+		tinyMCE.settings.preformatted = false;
1827
+
1828
+		// Default to false
1829
+		if (typeof(skip_cleanup) == "undefined")
1830
+			skip_cleanup = false;
1831
+
1832
+		// Default to false
1833
+		if (typeof(skip_callback) == "undefined")
1834
+			skip_callback = false;
1835
+
1836
+		tinyMCE._setHTML(this.getDoc(), this.getBody().innerHTML);
1837
+
1838
+		// Remove visual aids when cleanup is disabled
1839
+		if (this.settings.cleanup == false) {
1840
+			tinyMCE.handleVisualAid(this.getBody(), true, false, this);
1841
+			tinyMCE._setEventsEnabled(this.getBody(), true);
1842
+		}
1843
+
1844
+		tinyMCE._customCleanup(this, "submit_content_dom", this.contentWindow.document.body);
1845
+		htm = skip_cleanup ? this.getBody().innerHTML : tinyMCE._cleanupHTML(this, this.getDoc(), this.settings, this.getBody(), tinyMCE.visualAid, true, true);
1846
+		htm = tinyMCE._customCleanup(this, "submit_content", htm);
1847
+
1848
+		if (!skip_callback && tinyMCE.settings.save_callback !== '')
1849
+			content = tinyMCE.resolveDots(tinyMCE.settings.save_callback, window)(this.formTargetElementId,htm,this.getBody());
1850
+
1851
+		// Use callback content if available
1852
+		if ((typeof(content) != "undefined") && content != null)
1853
+			htm = content;
1854
+
1855
+		// Replace some weird entities (Bug: #1056343)
1856
+		htm = tinyMCE.regexpReplace(htm, "&#40;", "(", "gi");
1857
+		htm = tinyMCE.regexpReplace(htm, "&#41;", ")", "gi");
1858
+		htm = tinyMCE.regexpReplace(htm, "&#59;", ";", "gi");
1859
+		htm = tinyMCE.regexpReplace(htm, "&#34;", "&quot;", "gi");
1860
+		htm = tinyMCE.regexpReplace(htm, "&#94;", "^", "gi");
1861
+
1862
+		if (this.formElement)
1863
+			this.formElement.value = htm;
1864
+
1865
+		if (tinyMCE.isSafari && this.formElement)
1866
+			this.formElement.innerText = htm;
1867
+
1868
+		// Hide them again (tabs in MSIE)
1869
+		for (i=0; i<nl.length; i++) {
1870
+			if (nl[i].type == 'style')
1871
+				nl[i].elm.style.display = 'none';
1872
+			else
1873
+				nl[i].elm.className = s.hidden_tab_class;
1874
+		}
1875
+	}
1876
+
1877
+	/**#@-*/
1878
+};