tinymce/3rdparty/tiny_mce_src.js
changeset 0 c78d206bf01c
equal deleted inserted replaced
-1:000000000000 0:c78d206bf01c
       
     1 var tinymce = {
       
     2 	majorVersion : '3',
       
     3 	minorVersion : '2.7',
       
     4 	releaseDate : '2009-09-22',
       
     5 
       
     6 	_init : function() {
       
     7 		var t = this, d = document, w = window, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
       
     8 
       
     9 		t.isOpera = w.opera && opera.buildNumber;
       
    10 
       
    11 		t.isWebKit = /WebKit/.test(ua);
       
    12 
       
    13 		t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
       
    14 
       
    15 		t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
       
    16 
       
    17 		t.isGecko = !t.isWebKit && /Gecko/.test(ua);
       
    18 
       
    19 		t.isMac = ua.indexOf('Mac') != -1;
       
    20 
       
    21 		t.isAir = /adobeair/i.test(ua);
       
    22 
       
    23 		// TinyMCE .NET webcontrol might be setting the values for TinyMCE
       
    24 		if (w.tinyMCEPreInit) {
       
    25 			t.suffix = tinyMCEPreInit.suffix;
       
    26 			t.baseURL = tinyMCEPreInit.base;
       
    27 			t.query = tinyMCEPreInit.query;
       
    28 			return;
       
    29 		}
       
    30 
       
    31 		// Get suffix and base
       
    32 		t.suffix = '';
       
    33 
       
    34 		// If base element found, add that infront of baseURL
       
    35 		nl = d.getElementsByTagName('base');
       
    36 		for (i=0; i<nl.length; i++) {
       
    37 			if (v = nl[i].href) {
       
    38 				// Host only value like http://site.com or http://site.com:8008
       
    39 				if (/^https?:\/\/[^\/]+$/.test(v))
       
    40 					v += '/';
       
    41 
       
    42 				base = v ? v.match(/.*\//)[0] : ''; // Get only directory
       
    43 			}
       
    44 		}
       
    45 
       
    46 		function getBase(n) {
       
    47 			if (n.src && /tiny_mce(|_gzip|_jquery|_prototype)(_dev|_src)?.js/.test(n.src)) {
       
    48 				if (/_(src|dev)\.js/g.test(n.src))
       
    49 					t.suffix = '_src';
       
    50 
       
    51 				if ((p = n.src.indexOf('?')) != -1)
       
    52 					t.query = n.src.substring(p + 1);
       
    53 
       
    54 				t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
       
    55 
       
    56 				// If path to script is relative and a base href was found add that one infront
       
    57 				// the src property will always be an absolute one on non IE browsers and IE 8
       
    58 				// so this logic will basically only be executed on older IE versions
       
    59 				if (base && t.baseURL.indexOf('://') == -1 && t.baseURL.indexOf('/') !== 0)
       
    60 					t.baseURL = base + t.baseURL;
       
    61 
       
    62 				return t.baseURL;
       
    63 			}
       
    64 
       
    65 			return null;
       
    66 		};
       
    67 
       
    68 		// Check document
       
    69 		nl = d.getElementsByTagName('script');
       
    70 		for (i=0; i<nl.length; i++) {
       
    71 			if (getBase(nl[i]))
       
    72 				return;
       
    73 		}
       
    74 
       
    75 		// Check head
       
    76 		n = d.getElementsByTagName('head')[0];
       
    77 		if (n) {
       
    78 			nl = n.getElementsByTagName('script');
       
    79 			for (i=0; i<nl.length; i++) {
       
    80 				if (getBase(nl[i]))
       
    81 					return;
       
    82 			}
       
    83 		}
       
    84 
       
    85 		return;
       
    86 	},
       
    87 
       
    88 	is : function(o, t) {
       
    89 		var n = typeof(o);
       
    90 
       
    91 		if (!t)
       
    92 			return n != 'undefined';
       
    93 
       
    94 		if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
       
    95 			return true;
       
    96 
       
    97 		return n == t;
       
    98 	},
       
    99 
       
   100 	each : function(o, cb, s) {
       
   101 		var n, l;
       
   102 
       
   103 		if (!o)
       
   104 			return 0;
       
   105 
       
   106 		s = s || o;
       
   107 
       
   108 		if (typeof(o.length) != 'undefined') {
       
   109 			// Indexed arrays, needed for Safari
       
   110 			for (n=0, l = o.length; n<l; n++) {
       
   111 				if (cb.call(s, o[n], n, o) === false)
       
   112 					return 0;
       
   113 			}
       
   114 		} else {
       
   115 			// Hashtables
       
   116 			for (n in o) {
       
   117 				if (o.hasOwnProperty(n)) {
       
   118 					if (cb.call(s, o[n], n, o) === false)
       
   119 						return 0;
       
   120 				}
       
   121 			}
       
   122 		}
       
   123 
       
   124 		return 1;
       
   125 	},
       
   126 
       
   127 
       
   128 	map : function(a, f) {
       
   129 		var o = [];
       
   130 
       
   131 		tinymce.each(a, function(v) {
       
   132 			o.push(f(v));
       
   133 		});
       
   134 
       
   135 		return o;
       
   136 	},
       
   137 
       
   138 	grep : function(a, f) {
       
   139 		var o = [];
       
   140 
       
   141 		tinymce.each(a, function(v) {
       
   142 			if (!f || f(v))
       
   143 				o.push(v);
       
   144 		});
       
   145 
       
   146 		return o;
       
   147 	},
       
   148 
       
   149 	inArray : function(a, v) {
       
   150 		var i, l;
       
   151 
       
   152 		if (a) {
       
   153 			for (i = 0, l = a.length; i < l; i++) {
       
   154 				if (a[i] === v)
       
   155 					return i;
       
   156 			}
       
   157 		}
       
   158 
       
   159 		return -1;
       
   160 	},
       
   161 
       
   162 	extend : function(o, e) {
       
   163 		var i, a = arguments;
       
   164 
       
   165 		for (i=1; i<a.length; i++) {
       
   166 			e = a[i];
       
   167 
       
   168 			tinymce.each(e, function(v, n) {
       
   169 				if (typeof(v) !== 'undefined')
       
   170 					o[n] = v;
       
   171 			});
       
   172 		}
       
   173 
       
   174 		return o;
       
   175 	},
       
   176 
       
   177 
       
   178 	trim : function(s) {
       
   179 		return (s ? '' + s : '').replace(/^\s*|\s*$/g, '');
       
   180 	},
       
   181 
       
   182 	create : function(s, p) {
       
   183 		var t = this, sp, ns, cn, scn, c, de = 0;
       
   184 
       
   185 		// Parse : <prefix> <class>:<super class>
       
   186 		s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
       
   187 		cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
       
   188 
       
   189 		// Create namespace for new class
       
   190 		ns = t.createNS(s[3].replace(/\.\w+$/, ''));
       
   191 
       
   192 		// Class already exists
       
   193 		if (ns[cn])
       
   194 			return;
       
   195 
       
   196 		// Make pure static class
       
   197 		if (s[2] == 'static') {
       
   198 			ns[cn] = p;
       
   199 
       
   200 			if (this.onCreate)
       
   201 				this.onCreate(s[2], s[3], ns[cn]);
       
   202 
       
   203 			return;
       
   204 		}
       
   205 
       
   206 		// Create default constructor
       
   207 		if (!p[cn]) {
       
   208 			p[cn] = function() {};
       
   209 			de = 1;
       
   210 		}
       
   211 
       
   212 		// Add constructor and methods
       
   213 		ns[cn] = p[cn];
       
   214 		t.extend(ns[cn].prototype, p);
       
   215 
       
   216 		// Extend
       
   217 		if (s[5]) {
       
   218 			sp = t.resolve(s[5]).prototype;
       
   219 			scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
       
   220 
       
   221 			// Extend constructor
       
   222 			c = ns[cn];
       
   223 			if (de) {
       
   224 				// Add passthrough constructor
       
   225 				ns[cn] = function() {
       
   226 					return sp[scn].apply(this, arguments);
       
   227 				};
       
   228 			} else {
       
   229 				// Add inherit constructor
       
   230 				ns[cn] = function() {
       
   231 					this.parent = sp[scn];
       
   232 					return c.apply(this, arguments);
       
   233 				};
       
   234 			}
       
   235 			ns[cn].prototype[cn] = ns[cn];
       
   236 
       
   237 			// Add super methods
       
   238 			t.each(sp, function(f, n) {
       
   239 				ns[cn].prototype[n] = sp[n];
       
   240 			});
       
   241 
       
   242 			// Add overridden methods
       
   243 			t.each(p, function(f, n) {
       
   244 				// Extend methods if needed
       
   245 				if (sp[n]) {
       
   246 					ns[cn].prototype[n] = function() {
       
   247 						this.parent = sp[n];
       
   248 						return f.apply(this, arguments);
       
   249 					};
       
   250 				} else {
       
   251 					if (n != cn)
       
   252 						ns[cn].prototype[n] = f;
       
   253 				}
       
   254 			});
       
   255 		}
       
   256 
       
   257 		// Add static methods
       
   258 		t.each(p['static'], function(f, n) {
       
   259 			ns[cn][n] = f;
       
   260 		});
       
   261 
       
   262 		if (this.onCreate)
       
   263 			this.onCreate(s[2], s[3], ns[cn].prototype);
       
   264 	},
       
   265 
       
   266 	walk : function(o, f, n, s) {
       
   267 		s = s || this;
       
   268 
       
   269 		if (o) {
       
   270 			if (n)
       
   271 				o = o[n];
       
   272 
       
   273 			tinymce.each(o, function(o, i) {
       
   274 				if (f.call(s, o, i, n) === false)
       
   275 					return false;
       
   276 
       
   277 				tinymce.walk(o, f, n, s);
       
   278 			});
       
   279 		}
       
   280 	},
       
   281 
       
   282 	createNS : function(n, o) {
       
   283 		var i, v;
       
   284 
       
   285 		o = o || window;
       
   286 
       
   287 		n = n.split('.');
       
   288 		for (i=0; i<n.length; i++) {
       
   289 			v = n[i];
       
   290 
       
   291 			if (!o[v])
       
   292 				o[v] = {};
       
   293 
       
   294 			o = o[v];
       
   295 		}
       
   296 
       
   297 		return o;
       
   298 	},
       
   299 
       
   300 	resolve : function(n, o) {
       
   301 		var i, l;
       
   302 
       
   303 		o = o || window;
       
   304 
       
   305 		n = n.split('.');
       
   306 		for (i = 0, l = n.length; i < l; i++) {
       
   307 			o = o[n[i]];
       
   308 
       
   309 			if (!o)
       
   310 				break;
       
   311 		}
       
   312 
       
   313 		return o;
       
   314 	},
       
   315 
       
   316 	addUnload : function(f, s) {
       
   317 		var t = this, w = window;
       
   318 
       
   319 		f = {func : f, scope : s || this};
       
   320 
       
   321 		if (!t.unloads) {
       
   322 			function unload() {
       
   323 				var li = t.unloads, o, n;
       
   324 
       
   325 				if (li) {
       
   326 					// Call unload handlers
       
   327 					for (n in li) {
       
   328 						o = li[n];
       
   329 
       
   330 						if (o && o.func)
       
   331 							o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
       
   332 					}
       
   333 
       
   334 					// Detach unload function
       
   335 					if (w.detachEvent) {
       
   336 						w.detachEvent('onbeforeunload', fakeUnload);
       
   337 						w.detachEvent('onunload', unload);
       
   338 					} else if (w.removeEventListener)
       
   339 						w.removeEventListener('unload', unload, false);
       
   340 
       
   341 					// Destroy references
       
   342 					t.unloads = o = li = w = unload = 0;
       
   343 
       
   344 					// Run garbarge collector on IE
       
   345 					if (window.CollectGarbage)
       
   346 						window.CollectGarbage();
       
   347 				}
       
   348 			};
       
   349 
       
   350 			function fakeUnload() {
       
   351 				var d = document;
       
   352 
       
   353 				// Is there things still loading, then do some magic
       
   354 				if (d.readyState == 'interactive') {
       
   355 					function stop() {
       
   356 						// Prevent memory leak
       
   357 						d.detachEvent('onstop', stop);
       
   358 
       
   359 						// Call unload handler
       
   360 						if (unload)
       
   361 							unload();
       
   362 
       
   363 						d = 0;
       
   364 					};
       
   365 
       
   366 					// Fire unload when the currently loading page is stopped
       
   367 					if (d)
       
   368 						d.attachEvent('onstop', stop);
       
   369 
       
   370 					// Remove onstop listener after a while to prevent the unload function
       
   371 					// to execute if the user presses cancel in an onbeforeunload
       
   372 					// confirm dialog and then presses the browser stop button
       
   373 					window.setTimeout(function() {
       
   374 						if (d)
       
   375 							d.detachEvent('onstop', stop);
       
   376 					}, 0);
       
   377 				}
       
   378 			};
       
   379 
       
   380 			// Attach unload handler
       
   381 			if (w.attachEvent) {
       
   382 				w.attachEvent('onunload', unload);
       
   383 				w.attachEvent('onbeforeunload', fakeUnload);
       
   384 			} else if (w.addEventListener)
       
   385 				w.addEventListener('unload', unload, false);
       
   386 
       
   387 			// Setup initial unload handler array
       
   388 			t.unloads = [f];
       
   389 		} else
       
   390 			t.unloads.push(f);
       
   391 
       
   392 		return f;
       
   393 	},
       
   394 
       
   395 	removeUnload : function(f) {
       
   396 		var u = this.unloads, r = null;
       
   397 
       
   398 		tinymce.each(u, function(o, i) {
       
   399 			if (o && o.func == f) {
       
   400 				u.splice(i, 1);
       
   401 				r = f;
       
   402 				return false;
       
   403 			}
       
   404 		});
       
   405 
       
   406 		return r;
       
   407 	},
       
   408 
       
   409 	explode : function(s, d) {
       
   410 		return s ? tinymce.map(s.split(d || ','), tinymce.trim) : s;
       
   411 	},
       
   412 
       
   413 	_addVer : function(u) {
       
   414 		var v;
       
   415 
       
   416 		if (!this.query)
       
   417 			return u;
       
   418 
       
   419 		v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;
       
   420 
       
   421 		if (u.indexOf('#') == -1)
       
   422 			return u + v;
       
   423 
       
   424 		return u.replace('#', v + '#');
       
   425 	}
       
   426 
       
   427 	};
       
   428 
       
   429 // Required for GZip AJAX loading
       
   430 window.tinymce = tinymce;
       
   431 
       
   432 // Initialize the API
       
   433 tinymce._init();
       
   434 tinymce.create('tinymce.util.Dispatcher', {
       
   435 	scope : null,
       
   436 	listeners : null,
       
   437 
       
   438 	Dispatcher : function(s) {
       
   439 		this.scope = s || this;
       
   440 		this.listeners = [];
       
   441 	},
       
   442 
       
   443 	add : function(cb, s) {
       
   444 		this.listeners.push({cb : cb, scope : s || this.scope});
       
   445 
       
   446 		return cb;
       
   447 	},
       
   448 
       
   449 	addToTop : function(cb, s) {
       
   450 		this.listeners.unshift({cb : cb, scope : s || this.scope});
       
   451 
       
   452 		return cb;
       
   453 	},
       
   454 
       
   455 	remove : function(cb) {
       
   456 		var l = this.listeners, o = null;
       
   457 
       
   458 		tinymce.each(l, function(c, i) {
       
   459 			if (cb == c.cb) {
       
   460 				o = cb;
       
   461 				l.splice(i, 1);
       
   462 				return false;
       
   463 			}
       
   464 		});
       
   465 
       
   466 		return o;
       
   467 	},
       
   468 
       
   469 	dispatch : function() {
       
   470 		var s, a = arguments, i, li = this.listeners, c;
       
   471 
       
   472 		// Needs to be a real loop since the listener count might change while looping
       
   473 		// And this is also more efficient
       
   474 		for (i = 0; i<li.length; i++) {
       
   475 			c = li[i];
       
   476 			s = c.cb.apply(c.scope, a);
       
   477 
       
   478 			if (s === false)
       
   479 				break;
       
   480 		}
       
   481 
       
   482 		return s;
       
   483 	}
       
   484 
       
   485 	});
       
   486 (function() {
       
   487 	var each = tinymce.each;
       
   488 
       
   489 	tinymce.create('tinymce.util.URI', {
       
   490 		URI : function(u, s) {
       
   491 			var t = this, o, a, b;
       
   492 
       
   493 			// Trim whitespace
       
   494 			u = tinymce.trim(u);
       
   495 
       
   496 			// Default settings
       
   497 			s = t.settings = s || {};
       
   498 
       
   499 			// Strange app protocol or local anchor
       
   500 			if (/^(mailto|tel|news|javascript|about|data):/i.test(u) || /^\s*#/.test(u)) {
       
   501 				t.source = u;
       
   502 				return;
       
   503 			}
       
   504 
       
   505 			// Absolute path with no host, fake host and protocol
       
   506 			if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
       
   507 				u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
       
   508 
       
   509 			// Relative path http:// or protocol relative //path
       
   510 			if (!/^\w*:?\/\//.test(u))
       
   511 				u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);
       
   512 
       
   513 			// Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
       
   514 			u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
       
   515 			u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
       
   516 			each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
       
   517 				var s = u[i];
       
   518 
       
   519 				// Zope 3 workaround, they use @@something
       
   520 				if (s)
       
   521 					s = s.replace(/\(mce_at\)/g, '@@');
       
   522 
       
   523 				t[v] = s;
       
   524 			});
       
   525 
       
   526 			if (b = s.base_uri) {
       
   527 				if (!t.protocol)
       
   528 					t.protocol = b.protocol;
       
   529 
       
   530 				if (!t.userInfo)
       
   531 					t.userInfo = b.userInfo;
       
   532 
       
   533 				if (!t.port && t.host == 'mce_host')
       
   534 					t.port = b.port;
       
   535 
       
   536 				if (!t.host || t.host == 'mce_host')
       
   537 					t.host = b.host;
       
   538 
       
   539 				t.source = '';
       
   540 			}
       
   541 
       
   542 			//t.path = t.path || '/';
       
   543 		},
       
   544 
       
   545 		setPath : function(p) {
       
   546 			var t = this;
       
   547 
       
   548 			p = /^(.*?)\/?(\w+)?$/.exec(p);
       
   549 
       
   550 			// Update path parts
       
   551 			t.path = p[0];
       
   552 			t.directory = p[1];
       
   553 			t.file = p[2];
       
   554 
       
   555 			// Rebuild source
       
   556 			t.source = '';
       
   557 			t.getURI();
       
   558 		},
       
   559 
       
   560 		toRelative : function(u) {
       
   561 			var t = this, o;
       
   562 
       
   563 			if (u === "./")
       
   564 				return u;
       
   565 
       
   566 			u = new tinymce.util.URI(u, {base_uri : t});
       
   567 
       
   568 			// Not on same domain/port or protocol
       
   569 			if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
       
   570 				return u.getURI();
       
   571 
       
   572 			o = t.toRelPath(t.path, u.path);
       
   573 
       
   574 			// Add query
       
   575 			if (u.query)
       
   576 				o += '?' + u.query;
       
   577 
       
   578 			// Add anchor
       
   579 			if (u.anchor)
       
   580 				o += '#' + u.anchor;
       
   581 
       
   582 			return o;
       
   583 		},
       
   584 	
       
   585 		toAbsolute : function(u, nh) {
       
   586 			var u = new tinymce.util.URI(u, {base_uri : this});
       
   587 
       
   588 			return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0);
       
   589 		},
       
   590 
       
   591 		toRelPath : function(base, path) {
       
   592 			var items, bp = 0, out = '', i, l;
       
   593 
       
   594 			// Split the paths
       
   595 			base = base.substring(0, base.lastIndexOf('/'));
       
   596 			base = base.split('/');
       
   597 			items = path.split('/');
       
   598 
       
   599 			if (base.length >= items.length) {
       
   600 				for (i = 0, l = base.length; i < l; i++) {
       
   601 					if (i >= items.length || base[i] != items[i]) {
       
   602 						bp = i + 1;
       
   603 						break;
       
   604 					}
       
   605 				}
       
   606 			}
       
   607 
       
   608 			if (base.length < items.length) {
       
   609 				for (i = 0, l = items.length; i < l; i++) {
       
   610 					if (i >= base.length || base[i] != items[i]) {
       
   611 						bp = i + 1;
       
   612 						break;
       
   613 					}
       
   614 				}
       
   615 			}
       
   616 
       
   617 			if (bp == 1)
       
   618 				return path;
       
   619 
       
   620 			for (i = 0, l = base.length - (bp - 1); i < l; i++)
       
   621 				out += "../";
       
   622 
       
   623 			for (i = bp - 1, l = items.length; i < l; i++) {
       
   624 				if (i != bp - 1)
       
   625 					out += "/" + items[i];
       
   626 				else
       
   627 					out += items[i];
       
   628 			}
       
   629 
       
   630 			return out;
       
   631 		},
       
   632 
       
   633 		toAbsPath : function(base, path) {
       
   634 			var i, nb = 0, o = [], tr, outPath;
       
   635 
       
   636 			// Split paths
       
   637 			tr = /\/$/.test(path) ? '/' : '';
       
   638 			base = base.split('/');
       
   639 			path = path.split('/');
       
   640 
       
   641 			// Remove empty chunks
       
   642 			each(base, function(k) {
       
   643 				if (k)
       
   644 					o.push(k);
       
   645 			});
       
   646 
       
   647 			base = o;
       
   648 
       
   649 			// Merge relURLParts chunks
       
   650 			for (i = path.length - 1, o = []; i >= 0; i--) {
       
   651 				// Ignore empty or .
       
   652 				if (path[i].length == 0 || path[i] == ".")
       
   653 					continue;
       
   654 
       
   655 				// Is parent
       
   656 				if (path[i] == '..') {
       
   657 					nb++;
       
   658 					continue;
       
   659 				}
       
   660 
       
   661 				// Move up
       
   662 				if (nb > 0) {
       
   663 					nb--;
       
   664 					continue;
       
   665 				}
       
   666 
       
   667 				o.push(path[i]);
       
   668 			}
       
   669 
       
   670 			i = base.length - nb;
       
   671 
       
   672 			// If /a/b/c or /
       
   673 			if (i <= 0)
       
   674 				outPath = o.reverse().join('/');
       
   675 			else
       
   676 				outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
       
   677 
       
   678 			// Add front / if it's needed
       
   679 			if (outPath.indexOf('/') !== 0)
       
   680 				outPath = '/' + outPath;
       
   681 
       
   682 			// Add traling / if it's needed
       
   683 			if (tr && outPath.lastIndexOf('/') !== outPath.length - 1)
       
   684 				outPath += tr;
       
   685 
       
   686 			return outPath;
       
   687 		},
       
   688 
       
   689 		getURI : function(nh) {
       
   690 			var s, t = this;
       
   691 
       
   692 			// Rebuild source
       
   693 			if (!t.source || nh) {
       
   694 				s = '';
       
   695 
       
   696 				if (!nh) {
       
   697 					if (t.protocol)
       
   698 						s += t.protocol + '://';
       
   699 
       
   700 					if (t.userInfo)
       
   701 						s += t.userInfo + '@';
       
   702 
       
   703 					if (t.host)
       
   704 						s += t.host;
       
   705 
       
   706 					if (t.port)
       
   707 						s += ':' + t.port;
       
   708 				}
       
   709 
       
   710 				if (t.path)
       
   711 					s += t.path;
       
   712 
       
   713 				if (t.query)
       
   714 					s += '?' + t.query;
       
   715 
       
   716 				if (t.anchor)
       
   717 					s += '#' + t.anchor;
       
   718 
       
   719 				t.source = s;
       
   720 			}
       
   721 
       
   722 			return t.source;
       
   723 		}
       
   724 	});
       
   725 })();
       
   726 (function() {
       
   727 	var each = tinymce.each;
       
   728 
       
   729 	tinymce.create('static tinymce.util.Cookie', {
       
   730 		getHash : function(n) {
       
   731 			var v = this.get(n), h;
       
   732 
       
   733 			if (v) {
       
   734 				each(v.split('&'), function(v) {
       
   735 					v = v.split('=');
       
   736 					h = h || {};
       
   737 					h[unescape(v[0])] = unescape(v[1]);
       
   738 				});
       
   739 			}
       
   740 
       
   741 			return h;
       
   742 		},
       
   743 
       
   744 		setHash : function(n, v, e, p, d, s) {
       
   745 			var o = '';
       
   746 
       
   747 			each(v, function(v, k) {
       
   748 				o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
       
   749 			});
       
   750 
       
   751 			this.set(n, o, e, p, d, s);
       
   752 		},
       
   753 
       
   754 		get : function(n) {
       
   755 			var c = document.cookie, e, p = n + "=", b;
       
   756 
       
   757 			// Strict mode
       
   758 			if (!c)
       
   759 				return;
       
   760 
       
   761 			b = c.indexOf("; " + p);
       
   762 
       
   763 			if (b == -1) {
       
   764 				b = c.indexOf(p);
       
   765 
       
   766 				if (b != 0)
       
   767 					return null;
       
   768 			} else
       
   769 				b += 2;
       
   770 
       
   771 			e = c.indexOf(";", b);
       
   772 
       
   773 			if (e == -1)
       
   774 				e = c.length;
       
   775 
       
   776 			return unescape(c.substring(b + p.length, e));
       
   777 		},
       
   778 
       
   779 		set : function(n, v, e, p, d, s) {
       
   780 			document.cookie = n + "=" + escape(v) +
       
   781 				((e) ? "; expires=" + e.toGMTString() : "") +
       
   782 				((p) ? "; path=" + escape(p) : "") +
       
   783 				((d) ? "; domain=" + d : "") +
       
   784 				((s) ? "; secure" : "");
       
   785 		},
       
   786 
       
   787 		remove : function(n, p) {
       
   788 			var d = new Date();
       
   789 
       
   790 			d.setTime(d.getTime() - 1000);
       
   791 
       
   792 			this.set(n, '', d, p, d);
       
   793 		}
       
   794 	});
       
   795 })();
       
   796 tinymce.create('static tinymce.util.JSON', {
       
   797 	serialize : function(o) {
       
   798 		var i, v, s = tinymce.util.JSON.serialize, t;
       
   799 
       
   800 		if (o == null)
       
   801 			return 'null';
       
   802 
       
   803 		t = typeof o;
       
   804 
       
   805 		if (t == 'string') {
       
   806 			v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
       
   807 
       
   808 			return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) {
       
   809 				i = v.indexOf(b);
       
   810 
       
   811 				if (i + 1)
       
   812 					return '\\' + v.charAt(i + 1);
       
   813 
       
   814 				a = b.charCodeAt().toString(16);
       
   815 
       
   816 				return '\\u' + '0000'.substring(a.length) + a;
       
   817 			}) + '"';
       
   818 		}
       
   819 
       
   820 		if (t == 'object') {
       
   821 			if (o.hasOwnProperty && o instanceof Array) {
       
   822 					for (i=0, v = '['; i<o.length; i++)
       
   823 						v += (i > 0 ? ',' : '') + s(o[i]);
       
   824 
       
   825 					return v + ']';
       
   826 				}
       
   827 
       
   828 				v = '{';
       
   829 
       
   830 				for (i in o)
       
   831 					v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';
       
   832 
       
   833 				return v + '}';
       
   834 		}
       
   835 
       
   836 		return '' + o;
       
   837 	},
       
   838 
       
   839 	parse : function(s) {
       
   840 		try {
       
   841 			return eval('(' + s + ')');
       
   842 		} catch (ex) {
       
   843 			// Ignore
       
   844 		}
       
   845 	}
       
   846 
       
   847 	});
       
   848 tinymce.create('static tinymce.util.XHR', {
       
   849 	send : function(o) {
       
   850 		var x, t, w = window, c = 0;
       
   851 
       
   852 		// Default settings
       
   853 		o.scope = o.scope || this;
       
   854 		o.success_scope = o.success_scope || o.scope;
       
   855 		o.error_scope = o.error_scope || o.scope;
       
   856 		o.async = o.async === false ? false : true;
       
   857 		o.data = o.data || '';
       
   858 
       
   859 		function get(s) {
       
   860 			x = 0;
       
   861 
       
   862 			try {
       
   863 				x = new ActiveXObject(s);
       
   864 			} catch (ex) {
       
   865 			}
       
   866 
       
   867 			return x;
       
   868 		};
       
   869 
       
   870 		x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
       
   871 
       
   872 		if (x) {
       
   873 			if (x.overrideMimeType)
       
   874 				x.overrideMimeType(o.content_type);
       
   875 
       
   876 			x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
       
   877 
       
   878 			if (o.content_type)
       
   879 				x.setRequestHeader('Content-Type', o.content_type);
       
   880 
       
   881 			x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
       
   882 
       
   883 			x.send(o.data);
       
   884 
       
   885 			function ready() {
       
   886 				if (!o.async || x.readyState == 4 || c++ > 10000) {
       
   887 					if (o.success && c < 10000 && x.status == 200)
       
   888 						o.success.call(o.success_scope, '' + x.responseText, x, o);
       
   889 					else if (o.error)
       
   890 						o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
       
   891 
       
   892 					x = null;
       
   893 				} else
       
   894 					w.setTimeout(ready, 10);
       
   895 			};
       
   896 
       
   897 			// Syncronous request
       
   898 			if (!o.async)
       
   899 				return ready();
       
   900 
       
   901 			// Wait for response, onReadyStateChange can not be used since it leaks memory in IE
       
   902 			t = w.setTimeout(ready, 10);
       
   903 		}
       
   904 	}
       
   905 });
       
   906 (function() {
       
   907 	var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
       
   908 
       
   909 	tinymce.create('tinymce.util.JSONRequest', {
       
   910 		JSONRequest : function(s) {
       
   911 			this.settings = extend({
       
   912 			}, s);
       
   913 			this.count = 0;
       
   914 		},
       
   915 
       
   916 		send : function(o) {
       
   917 			var ecb = o.error, scb = o.success;
       
   918 
       
   919 			o = extend(this.settings, o);
       
   920 
       
   921 			o.success = function(c, x) {
       
   922 				c = JSON.parse(c);
       
   923 
       
   924 				if (typeof(c) == 'undefined') {
       
   925 					c = {
       
   926 						error : 'JSON Parse error.'
       
   927 					};
       
   928 				}
       
   929 
       
   930 				if (c.error)
       
   931 					ecb.call(o.error_scope || o.scope, c.error, x);
       
   932 				else
       
   933 					scb.call(o.success_scope || o.scope, c.result);
       
   934 			};
       
   935 
       
   936 			o.error = function(ty, x) {
       
   937 				ecb.call(o.error_scope || o.scope, ty, x);
       
   938 			};
       
   939 
       
   940 			o.data = JSON.serialize({
       
   941 				id : o.id || 'c' + (this.count++),
       
   942 				method : o.method,
       
   943 				params : o.params
       
   944 			});
       
   945 
       
   946 			// JSON content type for Ruby on rails. Bug: #1883287
       
   947 			o.content_type = 'application/json';
       
   948 
       
   949 			XHR.send(o);
       
   950 		},
       
   951 
       
   952 		'static' : {
       
   953 			sendRPC : function(o) {
       
   954 				return new tinymce.util.JSONRequest().send(o);
       
   955 			}
       
   956 		}
       
   957 	});
       
   958 }());(function(tinymce) {
       
   959 	// Shorten names
       
   960 	var each = tinymce.each, is = tinymce.is;
       
   961 	var isWebKit = tinymce.isWebKit, isIE = tinymce.isIE;
       
   962 
       
   963 	tinymce.create('tinymce.dom.DOMUtils', {
       
   964 		doc : null,
       
   965 		root : null,
       
   966 		files : null,
       
   967 		pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,
       
   968 		props : {
       
   969 			"for" : "htmlFor",
       
   970 			"class" : "className",
       
   971 			className : "className",
       
   972 			checked : "checked",
       
   973 			disabled : "disabled",
       
   974 			maxlength : "maxLength",
       
   975 			readonly : "readOnly",
       
   976 			selected : "selected",
       
   977 			value : "value",
       
   978 			id : "id",
       
   979 			name : "name",
       
   980 			type : "type"
       
   981 		},
       
   982 
       
   983 		DOMUtils : function(d, s) {
       
   984 			var t = this;
       
   985 
       
   986 			t.doc = d;
       
   987 			t.win = window;
       
   988 			t.files = {};
       
   989 			t.cssFlicker = false;
       
   990 			t.counter = 0;
       
   991 			t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat"; 
       
   992 			t.stdMode = d.documentMode === 8;
       
   993 
       
   994 			t.settings = s = tinymce.extend({
       
   995 				keep_values : false,
       
   996 				hex_colors : 1,
       
   997 				process_html : 1
       
   998 			}, s);
       
   999 
       
  1000 			// Fix IE6SP2 flicker and check it failed for pre SP2
       
  1001 			if (tinymce.isIE6) {
       
  1002 				try {
       
  1003 					d.execCommand('BackgroundImageCache', false, true);
       
  1004 				} catch (e) {
       
  1005 					t.cssFlicker = true;
       
  1006 				}
       
  1007 			}
       
  1008 
       
  1009 			tinymce.addUnload(t.destroy, t);
       
  1010 		},
       
  1011 
       
  1012 		getRoot : function() {
       
  1013 			var t = this, s = t.settings;
       
  1014 
       
  1015 			return (s && t.get(s.root_element)) || t.doc.body;
       
  1016 		},
       
  1017 
       
  1018 		getViewPort : function(w) {
       
  1019 			var d, b;
       
  1020 
       
  1021 			w = !w ? this.win : w;
       
  1022 			d = w.document;
       
  1023 			b = this.boxModel ? d.documentElement : d.body;
       
  1024 
       
  1025 			// Returns viewport size excluding scrollbars
       
  1026 			return {
       
  1027 				x : w.pageXOffset || b.scrollLeft,
       
  1028 				y : w.pageYOffset || b.scrollTop,
       
  1029 				w : w.innerWidth || b.clientWidth,
       
  1030 				h : w.innerHeight || b.clientHeight
       
  1031 			};
       
  1032 		},
       
  1033 
       
  1034 		getRect : function(e) {
       
  1035 			var p, t = this, sr;
       
  1036 
       
  1037 			e = t.get(e);
       
  1038 			p = t.getPos(e);
       
  1039 			sr = t.getSize(e);
       
  1040 
       
  1041 			return {
       
  1042 				x : p.x,
       
  1043 				y : p.y,
       
  1044 				w : sr.w,
       
  1045 				h : sr.h
       
  1046 			};
       
  1047 		},
       
  1048 
       
  1049 		getSize : function(e) {
       
  1050 			var t = this, w, h;
       
  1051 
       
  1052 			e = t.get(e);
       
  1053 			w = t.getStyle(e, 'width');
       
  1054 			h = t.getStyle(e, 'height');
       
  1055 
       
  1056 			// Non pixel value, then force offset/clientWidth
       
  1057 			if (w.indexOf('px') === -1)
       
  1058 				w = 0;
       
  1059 
       
  1060 			// Non pixel value, then force offset/clientWidth
       
  1061 			if (h.indexOf('px') === -1)
       
  1062 				h = 0;
       
  1063 
       
  1064 			return {
       
  1065 				w : parseInt(w) || e.offsetWidth || e.clientWidth,
       
  1066 				h : parseInt(h) || e.offsetHeight || e.clientHeight
       
  1067 			};
       
  1068 		},
       
  1069 
       
  1070 		getParent : function(n, f, r) {
       
  1071 			return this.getParents(n, f, r, false);
       
  1072 		},
       
  1073 
       
  1074 		getParents : function(n, f, r, c) {
       
  1075 			var t = this, na, se = t.settings, o = [];
       
  1076 
       
  1077 			n = t.get(n);
       
  1078 			c = c === undefined;
       
  1079 
       
  1080 			if (se.strict_root)
       
  1081 				r = r || t.getRoot();
       
  1082 
       
  1083 			// Wrap node name as func
       
  1084 			if (is(f, 'string')) {
       
  1085 				na = f;
       
  1086 
       
  1087 				if (f === '*') {
       
  1088 					f = function(n) {return n.nodeType == 1;};
       
  1089 				} else {
       
  1090 					f = function(n) {
       
  1091 						return t.is(n, na);
       
  1092 					};
       
  1093 				}
       
  1094 			}
       
  1095 
       
  1096 			while (n) {
       
  1097 				if (n == r || !n.nodeType || n.nodeType === 9)
       
  1098 					break;
       
  1099 
       
  1100 				if (!f || f(n)) {
       
  1101 					if (c)
       
  1102 						o.push(n);
       
  1103 					else
       
  1104 						return n;
       
  1105 				}
       
  1106 
       
  1107 				n = n.parentNode;
       
  1108 			}
       
  1109 
       
  1110 			return c ? o : null;
       
  1111 		},
       
  1112 
       
  1113 		get : function(e) {
       
  1114 			var n;
       
  1115 
       
  1116 			if (e && this.doc && typeof(e) == 'string') {
       
  1117 				n = e;
       
  1118 				e = this.doc.getElementById(e);
       
  1119 
       
  1120 				// IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
       
  1121 				if (e && e.id !== n)
       
  1122 					return this.doc.getElementsByName(n)[1];
       
  1123 			}
       
  1124 
       
  1125 			return e;
       
  1126 		},
       
  1127 
       
  1128 		getNext : function(node, selector) {
       
  1129 			return this._findSib(node, selector, 'nextSibling');
       
  1130 		},
       
  1131 
       
  1132 		getPrev : function(node, selector) {
       
  1133 			return this._findSib(node, selector, 'previousSibling');
       
  1134 		},
       
  1135 
       
  1136 
       
  1137 		select : function(pa, s) {
       
  1138 			var t = this;
       
  1139 
       
  1140 			return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []);
       
  1141 		},
       
  1142 
       
  1143 		is : function(n, patt) {
       
  1144 			return tinymce.dom.Sizzle.matches(patt, n.nodeType ? [n] : n).length > 0;
       
  1145 		},
       
  1146 
       
  1147 
       
  1148 		add : function(p, n, a, h, c) {
       
  1149 			var t = this;
       
  1150 
       
  1151 			return this.run(p, function(p) {
       
  1152 				var e, k;
       
  1153 
       
  1154 				e = is(n, 'string') ? t.doc.createElement(n) : n;
       
  1155 				t.setAttribs(e, a);
       
  1156 
       
  1157 				if (h) {
       
  1158 					if (h.nodeType)
       
  1159 						e.appendChild(h);
       
  1160 					else
       
  1161 						t.setHTML(e, h);
       
  1162 				}
       
  1163 
       
  1164 				return !c ? p.appendChild(e) : e;
       
  1165 			});
       
  1166 		},
       
  1167 
       
  1168 		create : function(n, a, h) {
       
  1169 			return this.add(this.doc.createElement(n), n, a, h, 1);
       
  1170 		},
       
  1171 
       
  1172 		createHTML : function(n, a, h) {
       
  1173 			var o = '', t = this, k;
       
  1174 
       
  1175 			o += '<' + n;
       
  1176 
       
  1177 			for (k in a) {
       
  1178 				if (a.hasOwnProperty(k))
       
  1179 					o += ' ' + k + '="' + t.encode(a[k]) + '"';
       
  1180 			}
       
  1181 
       
  1182 			if (tinymce.is(h))
       
  1183 				return o + '>' + h + '</' + n + '>';
       
  1184 
       
  1185 			return o + ' />';
       
  1186 		},
       
  1187 
       
  1188 		remove : function(n, k) {
       
  1189 			var t = this;
       
  1190 
       
  1191 			return this.run(n, function(n) {
       
  1192 				var p, g, i;
       
  1193 
       
  1194 				p = n.parentNode;
       
  1195 
       
  1196 				if (!p)
       
  1197 					return null;
       
  1198 
       
  1199 				if (k) {
       
  1200 					for (i = n.childNodes.length - 1; i >= 0; i--)
       
  1201 						t.insertAfter(n.childNodes[i], n);
       
  1202 
       
  1203 					//each(n.childNodes, function(c) {
       
  1204 					//	p.insertBefore(c.cloneNode(true), n);
       
  1205 					//});
       
  1206 				}
       
  1207 
       
  1208 				// Fix IE psuedo leak
       
  1209 				if (t.fixPsuedoLeaks) {
       
  1210 					p = n.cloneNode(true);
       
  1211 					k = 'IELeakGarbageBin';
       
  1212 					g = t.get(k) || t.add(t.doc.body, 'div', {id : k, style : 'display:none'});
       
  1213 					g.appendChild(n);
       
  1214 					g.innerHTML = '';
       
  1215 
       
  1216 					return p;
       
  1217 				}
       
  1218 
       
  1219 				return p.removeChild(n);
       
  1220 			});
       
  1221 		},
       
  1222 
       
  1223 		setStyle : function(n, na, v) {
       
  1224 			var t = this;
       
  1225 
       
  1226 			return t.run(n, function(e) {
       
  1227 				var s, i;
       
  1228 
       
  1229 				s = e.style;
       
  1230 
       
  1231 				// Camelcase it, if needed
       
  1232 				na = na.replace(/-(\D)/g, function(a, b){
       
  1233 					return b.toUpperCase();
       
  1234 				});
       
  1235 
       
  1236 				// Default px suffix on these
       
  1237 				if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))
       
  1238 					v += 'px';
       
  1239 
       
  1240 				switch (na) {
       
  1241 					case 'opacity':
       
  1242 						// IE specific opacity
       
  1243 						if (isIE) {
       
  1244 							s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
       
  1245 
       
  1246 							if (!n.currentStyle || !n.currentStyle.hasLayout)
       
  1247 								s.display = 'inline-block';
       
  1248 						}
       
  1249 
       
  1250 						// Fix for older browsers
       
  1251 						s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';
       
  1252 						break;
       
  1253 
       
  1254 					case 'float':
       
  1255 						isIE ? s.styleFloat = v : s.cssFloat = v;
       
  1256 						break;
       
  1257 					
       
  1258 					default:
       
  1259 						s[na] = v || '';
       
  1260 				}
       
  1261 
       
  1262 				// Force update of the style data
       
  1263 				if (t.settings.update_styles)
       
  1264 					t.setAttrib(e, 'mce_style');
       
  1265 			});
       
  1266 		},
       
  1267 
       
  1268 		getStyle : function(n, na, c) {
       
  1269 			n = this.get(n);
       
  1270 
       
  1271 			if (!n)
       
  1272 				return false;
       
  1273 
       
  1274 			// Gecko
       
  1275 			if (this.doc.defaultView && c) {
       
  1276 				// Remove camelcase
       
  1277 				na = na.replace(/[A-Z]/g, function(a){
       
  1278 					return '-' + a;
       
  1279 				});
       
  1280 
       
  1281 				try {
       
  1282 					return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);
       
  1283 				} catch (ex) {
       
  1284 					// Old safari might fail
       
  1285 					return null;
       
  1286 				}
       
  1287 			}
       
  1288 
       
  1289 			// Camelcase it, if needed
       
  1290 			na = na.replace(/-(\D)/g, function(a, b){
       
  1291 				return b.toUpperCase();
       
  1292 			});
       
  1293 
       
  1294 			if (na == 'float')
       
  1295 				na = isIE ? 'styleFloat' : 'cssFloat';
       
  1296 
       
  1297 			// IE & Opera
       
  1298 			if (n.currentStyle && c)
       
  1299 				return n.currentStyle[na];
       
  1300 
       
  1301 			return n.style[na];
       
  1302 		},
       
  1303 
       
  1304 		setStyles : function(e, o) {
       
  1305 			var t = this, s = t.settings, ol;
       
  1306 
       
  1307 			ol = s.update_styles;
       
  1308 			s.update_styles = 0;
       
  1309 
       
  1310 			each(o, function(v, n) {
       
  1311 				t.setStyle(e, n, v);
       
  1312 			});
       
  1313 
       
  1314 			// Update style info
       
  1315 			s.update_styles = ol;
       
  1316 			if (s.update_styles)
       
  1317 				t.setAttrib(e, s.cssText);
       
  1318 		},
       
  1319 
       
  1320 		setAttrib : function(e, n, v) {
       
  1321 			var t = this;
       
  1322 
       
  1323 			// Whats the point
       
  1324 			if (!e || !n)
       
  1325 				return;
       
  1326 
       
  1327 			// Strict XML mode
       
  1328 			if (t.settings.strict)
       
  1329 				n = n.toLowerCase();
       
  1330 
       
  1331 			return this.run(e, function(e) {
       
  1332 				var s = t.settings;
       
  1333 
       
  1334 				switch (n) {
       
  1335 					case "style":
       
  1336 						if (!is(v, 'string')) {
       
  1337 							each(v, function(v, n) {
       
  1338 								t.setStyle(e, n, v);
       
  1339 							});
       
  1340 
       
  1341 							return;
       
  1342 						}
       
  1343 
       
  1344 						// No mce_style for elements with these since they might get resized by the user
       
  1345 						if (s.keep_values) {
       
  1346 							if (v && !t._isRes(v))
       
  1347 								e.setAttribute('mce_style', v, 2);
       
  1348 							else
       
  1349 								e.removeAttribute('mce_style', 2);
       
  1350 						}
       
  1351 
       
  1352 						e.style.cssText = v;
       
  1353 						break;
       
  1354 
       
  1355 					case "class":
       
  1356 						e.className = v || ''; // Fix IE null bug
       
  1357 						break;
       
  1358 
       
  1359 					case "src":
       
  1360 					case "href":
       
  1361 						if (s.keep_values) {
       
  1362 							if (s.url_converter)
       
  1363 								v = s.url_converter.call(s.url_converter_scope || t, v, n, e);
       
  1364 
       
  1365 							t.setAttrib(e, 'mce_' + n, v, 2);
       
  1366 						}
       
  1367 
       
  1368 						break;
       
  1369 					
       
  1370 					case "shape":
       
  1371 						e.setAttribute('mce_style', v);
       
  1372 						break;
       
  1373 				}
       
  1374 
       
  1375 				if (is(v) && v !== null && v.length !== 0)
       
  1376 					e.setAttribute(n, '' + v, 2);
       
  1377 				else
       
  1378 					e.removeAttribute(n, 2);
       
  1379 			});
       
  1380 		},
       
  1381 
       
  1382 		setAttribs : function(e, o) {
       
  1383 			var t = this;
       
  1384 
       
  1385 			return this.run(e, function(e) {
       
  1386 				each(o, function(v, n) {
       
  1387 					t.setAttrib(e, n, v);
       
  1388 				});
       
  1389 			});
       
  1390 		},
       
  1391 
       
  1392 		getAttrib : function(e, n, dv) {
       
  1393 			var v, t = this;
       
  1394 
       
  1395 			e = t.get(e);
       
  1396 
       
  1397 			if (!e || e.nodeType !== 1)
       
  1398 				return false;
       
  1399 
       
  1400 			if (!is(dv))
       
  1401 				dv = '';
       
  1402 
       
  1403 			// Try the mce variant for these
       
  1404 			if (/^(src|href|style|coords|shape)$/.test(n)) {
       
  1405 				v = e.getAttribute("mce_" + n);
       
  1406 
       
  1407 				if (v)
       
  1408 					return v;
       
  1409 			}
       
  1410 
       
  1411 			if (isIE && t.props[n]) {
       
  1412 				v = e[t.props[n]];
       
  1413 				v = v && v.nodeValue ? v.nodeValue : v;
       
  1414 			}
       
  1415 
       
  1416 			if (!v)
       
  1417 				v = e.getAttribute(n, 2);
       
  1418 
       
  1419 			// Check boolean attribs
       
  1420 			if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) {
       
  1421 				if (e[t.props[n]] === true && v === '')
       
  1422 					return n;
       
  1423 
       
  1424 				return v ? n : '';
       
  1425 			}
       
  1426 
       
  1427 			// Inner input elements will override attributes on form elements
       
  1428 			if (e.nodeName === "FORM" && e.getAttributeNode(n))
       
  1429 				return e.getAttributeNode(n).nodeValue;
       
  1430 
       
  1431 			if (n === 'style') {
       
  1432 				v = v || e.style.cssText;
       
  1433 
       
  1434 				if (v) {
       
  1435 					v = t.serializeStyle(t.parseStyle(v));
       
  1436 
       
  1437 					if (t.settings.keep_values && !t._isRes(v))
       
  1438 						e.setAttribute('mce_style', v);
       
  1439 				}
       
  1440 			}
       
  1441 
       
  1442 			// Remove Apple and WebKit stuff
       
  1443 			if (isWebKit && n === "class" && v)
       
  1444 				v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');
       
  1445 
       
  1446 			// Handle IE issues
       
  1447 			if (isIE) {
       
  1448 				switch (n) {
       
  1449 					case 'rowspan':
       
  1450 					case 'colspan':
       
  1451 						// IE returns 1 as default value
       
  1452 						if (v === 1)
       
  1453 							v = '';
       
  1454 
       
  1455 						break;
       
  1456 
       
  1457 					case 'size':
       
  1458 						// IE returns +0 as default value for size
       
  1459 						if (v === '+0' || v === 20 || v === 0)
       
  1460 							v = '';
       
  1461 
       
  1462 						break;
       
  1463 
       
  1464 					case 'width':
       
  1465 					case 'height':
       
  1466 					case 'vspace':
       
  1467 					case 'checked':
       
  1468 					case 'disabled':
       
  1469 					case 'readonly':
       
  1470 						if (v === 0)
       
  1471 							v = '';
       
  1472 
       
  1473 						break;
       
  1474 
       
  1475 					case 'hspace':
       
  1476 						// IE returns -1 as default value
       
  1477 						if (v === -1)
       
  1478 							v = '';
       
  1479 
       
  1480 						break;
       
  1481 
       
  1482 					case 'maxlength':
       
  1483 					case 'tabindex':
       
  1484 						// IE returns default value
       
  1485 						if (v === 32768 || v === 2147483647 || v === '32768')
       
  1486 							v = '';
       
  1487 
       
  1488 						break;
       
  1489 
       
  1490 					case 'multiple':
       
  1491 					case 'compact':
       
  1492 					case 'noshade':
       
  1493 					case 'nowrap':
       
  1494 						if (v === 65535)
       
  1495 							return n;
       
  1496 
       
  1497 						return dv;
       
  1498 
       
  1499 					case 'shape':
       
  1500 						v = v.toLowerCase();
       
  1501 						break;
       
  1502 
       
  1503 					default:
       
  1504 						// IE has odd anonymous function for event attributes
       
  1505 						if (n.indexOf('on') === 0 && v)
       
  1506 							v = ('' + v).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1');
       
  1507 				}
       
  1508 			}
       
  1509 
       
  1510 			return (v !== undefined && v !== null && v !== '') ? '' + v : dv;
       
  1511 		},
       
  1512 
       
  1513 		getPos : function(n, ro) {
       
  1514 			var t = this, x = 0, y = 0, e, d = t.doc, r;
       
  1515 
       
  1516 			n = t.get(n);
       
  1517 			ro = ro || d.body;
       
  1518 
       
  1519 			if (n) {
       
  1520 				// Use getBoundingClientRect on IE, Opera has it but it's not perfect
       
  1521 				if (isIE && !t.stdMode) {
       
  1522 					n = n.getBoundingClientRect();
       
  1523 					e = t.boxModel ? d.documentElement : d.body;
       
  1524 					x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
       
  1525 					x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
       
  1526 					n.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset
       
  1527 
       
  1528 					return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
       
  1529 				}
       
  1530 
       
  1531 				r = n;
       
  1532 				while (r && r != ro && r.nodeType) {
       
  1533 					x += r.offsetLeft || 0;
       
  1534 					y += r.offsetTop || 0;
       
  1535 					r = r.offsetParent;
       
  1536 				}
       
  1537 
       
  1538 				r = n.parentNode;
       
  1539 				while (r && r != ro && r.nodeType) {
       
  1540 					x -= r.scrollLeft || 0;
       
  1541 					y -= r.scrollTop || 0;
       
  1542 					r = r.parentNode;
       
  1543 				}
       
  1544 			}
       
  1545 
       
  1546 			return {x : x, y : y};
       
  1547 		},
       
  1548 
       
  1549 		parseStyle : function(st) {
       
  1550 			var t = this, s = t.settings, o = {};
       
  1551 
       
  1552 			if (!st)
       
  1553 				return o;
       
  1554 
       
  1555 			function compress(p, s, ot) {
       
  1556 				var t, r, b, l;
       
  1557 
       
  1558 				// Get values and check it it needs compressing
       
  1559 				t = o[p + '-top' + s];
       
  1560 				if (!t)
       
  1561 					return;
       
  1562 
       
  1563 				r = o[p + '-right' + s];
       
  1564 				if (t != r)
       
  1565 					return;
       
  1566 
       
  1567 				b = o[p + '-bottom' + s];
       
  1568 				if (r != b)
       
  1569 					return;
       
  1570 
       
  1571 				l = o[p + '-left' + s];
       
  1572 				if (b != l)
       
  1573 					return;
       
  1574 
       
  1575 				// Compress
       
  1576 				o[ot] = l;
       
  1577 				delete o[p + '-top' + s];
       
  1578 				delete o[p + '-right' + s];
       
  1579 				delete o[p + '-bottom' + s];
       
  1580 				delete o[p + '-left' + s];
       
  1581 			};
       
  1582 
       
  1583 			function compress2(ta, a, b, c) {
       
  1584 				var t;
       
  1585 
       
  1586 				t = o[a];
       
  1587 				if (!t)
       
  1588 					return;
       
  1589 
       
  1590 				t = o[b];
       
  1591 				if (!t)
       
  1592 					return;
       
  1593 
       
  1594 				t = o[c];
       
  1595 				if (!t)
       
  1596 					return;
       
  1597 
       
  1598 				// Compress
       
  1599 				o[ta] = o[a] + ' ' + o[b] + ' ' + o[c];
       
  1600 				delete o[a];
       
  1601 				delete o[b];
       
  1602 				delete o[c];
       
  1603 			};
       
  1604 
       
  1605 			st = st.replace(/&(#?[a-z0-9]+);/g, '&$1_MCE_SEMI_'); // Protect entities
       
  1606 
       
  1607 			each(st.split(';'), function(v) {
       
  1608 				var sv, ur = [];
       
  1609 
       
  1610 				if (v) {
       
  1611 					v = v.replace(/_MCE_SEMI_/g, ';'); // Restore entities
       
  1612 					v = v.replace(/url\([^\)]+\)/g, function(v) {ur.push(v);return 'url(' + ur.length + ')';});
       
  1613 					v = v.split(':');
       
  1614 					sv = tinymce.trim(v[1]);
       
  1615 					sv = sv.replace(/url\(([^\)]+)\)/g, function(a, b) {return ur[parseInt(b) - 1];});
       
  1616 
       
  1617 					sv = sv.replace(/rgb\([^\)]+\)/g, function(v) {
       
  1618 						return t.toHex(v);
       
  1619 					});
       
  1620 
       
  1621 					if (s.url_converter) {
       
  1622 						sv = sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g, function(x, c) {
       
  1623 							return 'url(' + s.url_converter.call(s.url_converter_scope || t, t.decode(c), 'style', null) + ')';
       
  1624 						});
       
  1625 					}
       
  1626 
       
  1627 					o[tinymce.trim(v[0]).toLowerCase()] = sv;
       
  1628 				}
       
  1629 			});
       
  1630 
       
  1631 			compress("border", "", "border");
       
  1632 			compress("border", "-width", "border-width");
       
  1633 			compress("border", "-color", "border-color");
       
  1634 			compress("border", "-style", "border-style");
       
  1635 			compress("padding", "", "padding");
       
  1636 			compress("margin", "", "margin");
       
  1637 			compress2('border', 'border-width', 'border-style', 'border-color');
       
  1638 
       
  1639 			if (isIE) {
       
  1640 				// Remove pointless border
       
  1641 				if (o.border == 'medium none')
       
  1642 					o.border = '';
       
  1643 			}
       
  1644 
       
  1645 			return o;
       
  1646 		},
       
  1647 
       
  1648 		serializeStyle : function(o) {
       
  1649 			var s = '';
       
  1650 
       
  1651 			each(o, function(v, k) {
       
  1652 				if (k && v) {
       
  1653 					if (tinymce.isGecko && k.indexOf('-moz-') === 0)
       
  1654 						return;
       
  1655 
       
  1656 					switch (k) {
       
  1657 						case 'color':
       
  1658 						case 'background-color':
       
  1659 							v = v.toLowerCase();
       
  1660 							break;
       
  1661 					}
       
  1662 
       
  1663 					s += (s ? ' ' : '') + k + ': ' + v + ';';
       
  1664 				}
       
  1665 			});
       
  1666 
       
  1667 			return s;
       
  1668 		},
       
  1669 
       
  1670 		loadCSS : function(u) {
       
  1671 			var t = this, d = t.doc, head;
       
  1672 
       
  1673 			if (!u)
       
  1674 				u = '';
       
  1675 
       
  1676 			head = t.select('head')[0];
       
  1677 
       
  1678 			each(u.split(','), function(u) {
       
  1679 				var link;
       
  1680 
       
  1681 				if (t.files[u])
       
  1682 					return;
       
  1683 
       
  1684 				t.files[u] = true;
       
  1685 				link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)});
       
  1686 
       
  1687 				// IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
       
  1688 				// This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading
       
  1689 				// It's ugly but it seems to work fine.
       
  1690 				if (isIE && d.documentMode) {
       
  1691 					link.onload = function() {
       
  1692 						d.recalc();
       
  1693 						link.onload = null;
       
  1694 					};
       
  1695 				}
       
  1696 
       
  1697 				head.appendChild(link);
       
  1698 			});
       
  1699 		},
       
  1700 
       
  1701 		addClass : function(e, c) {
       
  1702 			return this.run(e, function(e) {
       
  1703 				var o;
       
  1704 
       
  1705 				if (!c)
       
  1706 					return 0;
       
  1707 
       
  1708 				if (this.hasClass(e, c))
       
  1709 					return e.className;
       
  1710 
       
  1711 				o = this.removeClass(e, c);
       
  1712 
       
  1713 				return e.className = (o != '' ? (o + ' ') : '') + c;
       
  1714 			});
       
  1715 		},
       
  1716 
       
  1717 		removeClass : function(e, c) {
       
  1718 			var t = this, re;
       
  1719 
       
  1720 			return t.run(e, function(e) {
       
  1721 				var v;
       
  1722 
       
  1723 				if (t.hasClass(e, c)) {
       
  1724 					if (!re)
       
  1725 						re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
       
  1726 
       
  1727 					v = e.className.replace(re, ' ');
       
  1728 
       
  1729 					return e.className = tinymce.trim(v != ' ' ? v : '');
       
  1730 				}
       
  1731 
       
  1732 				return e.className;
       
  1733 			});
       
  1734 		},
       
  1735 
       
  1736 		hasClass : function(n, c) {
       
  1737 			n = this.get(n);
       
  1738 
       
  1739 			if (!n || !c)
       
  1740 				return false;
       
  1741 
       
  1742 			return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;
       
  1743 		},
       
  1744 
       
  1745 		show : function(e) {
       
  1746 			return this.setStyle(e, 'display', 'block');
       
  1747 		},
       
  1748 
       
  1749 		hide : function(e) {
       
  1750 			return this.setStyle(e, 'display', 'none');
       
  1751 		},
       
  1752 
       
  1753 		isHidden : function(e) {
       
  1754 			e = this.get(e);
       
  1755 
       
  1756 			return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none';
       
  1757 		},
       
  1758 
       
  1759 		uniqueId : function(p) {
       
  1760 			return (!p ? 'mce_' : p) + (this.counter++);
       
  1761 		},
       
  1762 
       
  1763 		setHTML : function(e, h) {
       
  1764 			var t = this;
       
  1765 
       
  1766 			return this.run(e, function(e) {
       
  1767 				var x, i, nl, n, p, x;
       
  1768 
       
  1769 				h = t.processHTML(h);
       
  1770 
       
  1771 				if (isIE) {
       
  1772 					function set() {
       
  1773 						try {
       
  1774 							// IE will remove comments from the beginning
       
  1775 							// unless you padd the contents with something
       
  1776 							e.innerHTML = '<br />' + h;
       
  1777 							e.removeChild(e.firstChild);
       
  1778 						} catch (ex) {
       
  1779 							// IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p
       
  1780 							// This seems to fix this problem
       
  1781 
       
  1782 							// Remove all child nodes
       
  1783 							while (e.firstChild)
       
  1784 								e.firstChild.removeNode();
       
  1785 
       
  1786 							// Create new div with HTML contents and a BR infront to keep comments
       
  1787 							x = t.create('div');
       
  1788 							x.innerHTML = '<br />' + h;
       
  1789 
       
  1790 							// Add all children from div to target
       
  1791 							each (x.childNodes, function(n, i) {
       
  1792 								// Skip br element
       
  1793 								if (i)
       
  1794 									e.appendChild(n);
       
  1795 							});
       
  1796 						}
       
  1797 					};
       
  1798 
       
  1799 					// IE has a serious bug when it comes to paragraphs it can produce an invalid
       
  1800 					// DOM tree if contents like this <p><ul><li>Item 1</li></ul></p> is inserted
       
  1801 					// It seems to be that IE doesn't like a root block element placed inside another root block element
       
  1802 					if (t.settings.fix_ie_paragraphs)
       
  1803 						h = h.replace(/<p><\/p>|<p([^>]+)><\/p>|<p[^\/+]\/>/gi, '<p$1 mce_keep="true">&nbsp;</p>');
       
  1804 
       
  1805 					set();
       
  1806 
       
  1807 					if (t.settings.fix_ie_paragraphs) {
       
  1808 						// Check for odd paragraphs this is a sign of a broken DOM
       
  1809 						nl = e.getElementsByTagName("p");
       
  1810 						for (i = nl.length - 1, x = 0; i >= 0; i--) {
       
  1811 							n = nl[i];
       
  1812 
       
  1813 							if (!n.hasChildNodes()) {
       
  1814 								if (!n.mce_keep) {
       
  1815 									x = 1; // Is broken
       
  1816 									break;
       
  1817 								}
       
  1818 
       
  1819 								n.removeAttribute('mce_keep');
       
  1820 							}
       
  1821 						}
       
  1822 					}
       
  1823 
       
  1824 					// Time to fix the madness IE left us
       
  1825 					if (x) {
       
  1826 						// So if we replace the p elements with divs and mark them and then replace them back to paragraphs
       
  1827 						// after we use innerHTML we can fix the DOM tree
       
  1828 						h = h.replace(/<p ([^>]+)>|<p>/ig, '<div $1 mce_tmp="1">');
       
  1829 						h = h.replace(/<\/p>/g, '</div>');
       
  1830 
       
  1831 						// Set the new HTML with DIVs
       
  1832 						set();
       
  1833 
       
  1834 						// Replace all DIV elements with he mce_tmp attibute back to paragraphs
       
  1835 						// This is needed since IE has a annoying bug see above for details
       
  1836 						// This is a slow process but it has to be done. :(
       
  1837 						if (t.settings.fix_ie_paragraphs) {
       
  1838 							nl = e.getElementsByTagName("DIV");
       
  1839 							for (i = nl.length - 1; i >= 0; i--) {
       
  1840 								n = nl[i];
       
  1841 
       
  1842 								// Is it a temp div
       
  1843 								if (n.mce_tmp) {
       
  1844 									// Create new paragraph
       
  1845 									p = t.doc.createElement('p');
       
  1846 
       
  1847 									// Copy all attributes
       
  1848 									n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) {
       
  1849 										var v;
       
  1850 
       
  1851 										if (b !== 'mce_tmp') {
       
  1852 											v = n.getAttribute(b);
       
  1853 
       
  1854 											if (!v && b === 'class')
       
  1855 												v = n.className;
       
  1856 
       
  1857 											p.setAttribute(b, v);
       
  1858 										}
       
  1859 									});
       
  1860 
       
  1861 									// Append all children to new paragraph
       
  1862 									for (x = 0; x<n.childNodes.length; x++)
       
  1863 										p.appendChild(n.childNodes[x].cloneNode(true));
       
  1864 
       
  1865 									// Replace div with new paragraph
       
  1866 									n.swapNode(p);
       
  1867 								}
       
  1868 							}
       
  1869 						}
       
  1870 					}
       
  1871 				} else
       
  1872 					e.innerHTML = h;
       
  1873 
       
  1874 				return h;
       
  1875 			});
       
  1876 		},
       
  1877 
       
  1878 		processHTML : function(h) {
       
  1879 			var t = this, s = t.settings, codeBlocks = [];
       
  1880 
       
  1881 			if (!s.process_html)
       
  1882 				return h;
       
  1883 
       
  1884 			// Convert strong and em to b and i in FF since it can't handle them
       
  1885 			if (tinymce.isGecko) {
       
  1886 				h = h.replace(/<(\/?)strong>|<strong( [^>]+)>/gi, '<$1b$2>');
       
  1887 				h = h.replace(/<(\/?)em>|<em( [^>]+)>/gi, '<$1i$2>');
       
  1888 			} else if (isIE) {
       
  1889 				h = h.replace(/&apos;/g, '&#39;'); // IE can't handle apos
       
  1890 				h = h.replace(/\s+(disabled|checked|readonly|selected)\s*=\s*[\"\']?(false|0)[\"\']?/gi, ''); // IE doesn't handle default values correct
       
  1891 			}
       
  1892 
       
  1893 			// Fix some issues
       
  1894 			h = h.replace(/<a( )([^>]+)\/>|<a\/>/gi, '<a$1$2></a>'); // Force open
       
  1895 
       
  1896 			// Store away src and href in mce_src and mce_href since browsers mess them up
       
  1897 			if (s.keep_values) {
       
  1898 				// Wrap scripts and styles in comments for serialization purposes
       
  1899 				if (/<script|noscript|style/i.test(h)) {
       
  1900 					function trim(s) {
       
  1901 						// Remove prefix and suffix code for element
       
  1902 						s = s.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n');
       
  1903 						s = s.replace(/^[\r\n]*|[\r\n]*$/g, '');
       
  1904 						s = s.replace(/^\s*(\/\/\s*<!--|\/\/\s*<!\[CDATA\[|<!--|<!\[CDATA\[)[\r\n]*/g, '');
       
  1905 						s = s.replace(/\s*(\/\/\s*\]\]>|\/\/\s*-->|\]\]>|-->|\]\]-->)\s*$/g, '');
       
  1906 
       
  1907 						return s;
       
  1908 					};
       
  1909 
       
  1910 					// Wrap the script contents in CDATA and keep them from executing
       
  1911 					h = h.replace(/<script([^>]+|)>([\s\S]*?)<\/script>/gi, function(v, attribs, text) {
       
  1912 						// Force type attribute
       
  1913 						if (!attribs)
       
  1914 							attribs = ' type="text/javascript"';
       
  1915 
       
  1916 						// Convert the src attribute of the scripts
       
  1917 						attribs = attribs.replace(/src=\"([^\"]+)\"?/i, function(a, url) {
       
  1918 							if (s.url_converter)
       
  1919 								url = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(url), 'src', 'script'));
       
  1920 
       
  1921 							return 'mce_src="' + url + '"';
       
  1922 						});
       
  1923 
       
  1924 						// Wrap text contents
       
  1925 						if (tinymce.trim(text)) {
       
  1926 							codeBlocks.push(trim(text));
       
  1927 							text = '<!--\nMCE_SCRIPT:' + (codeBlocks.length - 1) + '\n// -->';
       
  1928 						}
       
  1929 
       
  1930 						return '<mce:script' + attribs + '>' + text + '</mce:script>';
       
  1931 					});
       
  1932 
       
  1933 					// Wrap style elements
       
  1934 					h = h.replace(/<style([^>]+|)>([\s\S]*?)<\/style>/gi, function(v, attribs, text) {
       
  1935 						// Wrap text contents
       
  1936 						if (text) {
       
  1937 							codeBlocks.push(trim(text));
       
  1938 							text = '<!--\nMCE_SCRIPT:' + (codeBlocks.length - 1) + '\n-->';
       
  1939 						}
       
  1940 
       
  1941 						return '<mce:style' + attribs + '>' + text + '</mce:style><style ' + attribs + ' mce_bogus="1">' + text + '</style>';
       
  1942 					});
       
  1943 
       
  1944 					// Wrap noscript elements
       
  1945 					h = h.replace(/<noscript([^>]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) {
       
  1946 						return '<mce:noscript' + attribs + '><!--' + t.encode(text).replace(/--/g, '&#45;&#45;') + '--></mce:noscript>';
       
  1947 					});
       
  1948 				}
       
  1949 
       
  1950 				h = h.replace(/<!\[CDATA\[([\s\S]+)\]\]>/g, '<!--[CDATA[$1]]-->');
       
  1951 
       
  1952 				// Remove false bool attributes and force attributes into xhtml style attr="attr"
       
  1953 				h = h.replace(/<([\w:]+) [^>]*(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)[^>]*>/gi, function(val) {
       
  1954 					function handle(val, name, value) {
       
  1955 						// Remove false/0 attribs
       
  1956 						if (value === 'false' || value === '0')
       
  1957 							return '';
       
  1958 
       
  1959 						return ' ' + name + '="' + name + '"';
       
  1960 					};
       
  1961 
       
  1962 					val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=[\"]([^\"]+)[\"]/gi, handle); // W3C
       
  1963 					val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=[\']([^\']+)[\']/gi, handle); // W3C
       
  1964 					val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=([^\s\"\'>]+)/gi, handle); // IE
       
  1965 					val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)([\s>])/gi, ' $1="$1"$2'); // Force attr="attr"
       
  1966 
       
  1967 					return val;
       
  1968 				});
       
  1969 
       
  1970 				// Process all tags with src, href or style
       
  1971 				h = h.replace(/<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi, function(a, n) {
       
  1972 					function handle(m, b, c) {
       
  1973 						var u = c;
       
  1974 
       
  1975 						// Tag already got a mce_ version
       
  1976 						if (a.indexOf('mce_' + b) != -1)
       
  1977 							return m;
       
  1978 
       
  1979 						if (b == 'style') {
       
  1980 							// No mce_style for elements with these since they might get resized by the user
       
  1981 							if (t._isRes(c))
       
  1982 								return m;
       
  1983 
       
  1984 							// Parse and serialize the style to convert for example uppercase styles like "BORDER: 1px"
       
  1985 							u = t.encode(t.serializeStyle(t.parseStyle(u)));
       
  1986 						} else if (b != 'coords' && b != 'shape') {
       
  1987 							if (s.url_converter)
       
  1988 								u = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n));
       
  1989 						}
       
  1990 
       
  1991 						return ' ' + b + '="' + c + '" mce_' + b + '="' + u + '"';
       
  1992 					};
       
  1993 
       
  1994 					a = a.replace(/ (src|href|style|coords|shape)=[\"]([^\"]+)[\"]/gi, handle); // W3C
       
  1995 					a = a.replace(/ (src|href|style|coords|shape)=[\']([^\']+)[\']/gi, handle); // W3C
       
  1996 
       
  1997 					return a.replace(/ (src|href|style|coords|shape)=([^\s\"\'>]+)/gi, handle); // IE
       
  1998 				});
       
  1999 
       
  2000 				// Restore script blocks
       
  2001 				h = h.replace(/MCE_SCRIPT:([0-9]+)/g, function(val, idx) {
       
  2002 					return codeBlocks[idx];
       
  2003 				});
       
  2004 			}
       
  2005 
       
  2006 			return h;
       
  2007 		},
       
  2008 
       
  2009 		getOuterHTML : function(e) {
       
  2010 			var d;
       
  2011 
       
  2012 			e = this.get(e);
       
  2013 
       
  2014 			if (!e)
       
  2015 				return null;
       
  2016 
       
  2017 			if (e.outerHTML !== undefined)
       
  2018 				return e.outerHTML;
       
  2019 
       
  2020 			d = (e.ownerDocument || this.doc).createElement("body");
       
  2021 			d.appendChild(e.cloneNode(true));
       
  2022 
       
  2023 			return d.innerHTML;
       
  2024 		},
       
  2025 
       
  2026 		setOuterHTML : function(e, h, d) {
       
  2027 			var t = this;
       
  2028 
       
  2029 			function setHTML(e, h, d) {
       
  2030 				var n, tp;
       
  2031 				
       
  2032 				tp = d.createElement("body");
       
  2033 				tp.innerHTML = h;
       
  2034 
       
  2035 				n = tp.lastChild;
       
  2036 				while (n) {
       
  2037 					t.insertAfter(n.cloneNode(true), e);
       
  2038 					n = n.previousSibling;
       
  2039 				}
       
  2040 
       
  2041 				t.remove(e);
       
  2042 			};
       
  2043 
       
  2044 			return this.run(e, function(e) {
       
  2045 				e = t.get(e);
       
  2046 
       
  2047 				// Only set HTML on elements
       
  2048 				if (e.nodeType == 1) {
       
  2049 					d = d || e.ownerDocument || t.doc;
       
  2050 
       
  2051 					if (isIE) {
       
  2052 						try {
       
  2053 							// Try outerHTML for IE it sometimes produces an unknown runtime error
       
  2054 							if (isIE && e.nodeType == 1)
       
  2055 								e.outerHTML = h;
       
  2056 							else
       
  2057 								setHTML(e, h, d);
       
  2058 						} catch (ex) {
       
  2059 							// Fix for unknown runtime error
       
  2060 							setHTML(e, h, d);
       
  2061 						}
       
  2062 					} else
       
  2063 						setHTML(e, h, d);
       
  2064 				}
       
  2065 			});
       
  2066 		},
       
  2067 
       
  2068 		decode : function(s) {
       
  2069 			var e, n, v;
       
  2070 
       
  2071 			// Look for entities to decode
       
  2072 			if (/&[^;]+;/.test(s)) {
       
  2073 				// Decode the entities using a div element not super efficient but less code
       
  2074 				e = this.doc.createElement("div");
       
  2075 				e.innerHTML = s;
       
  2076 				n = e.firstChild;
       
  2077 				v = '';
       
  2078 
       
  2079 				if (n) {
       
  2080 					do {
       
  2081 						v += n.nodeValue;
       
  2082 					} while (n.nextSibling);
       
  2083 				}
       
  2084 
       
  2085 				return v || s;
       
  2086 			}
       
  2087 
       
  2088 			return s;
       
  2089 		},
       
  2090 
       
  2091 		encode : function(s) {
       
  2092 			return s ? ('' + s).replace(/[<>&\"]/g, function (c, b) {
       
  2093 				switch (c) {
       
  2094 					case '&':
       
  2095 						return '&amp;';
       
  2096 
       
  2097 					case '"':
       
  2098 						return '&quot;';
       
  2099 
       
  2100 					case '<':
       
  2101 						return '&lt;';
       
  2102 
       
  2103 					case '>':
       
  2104 						return '&gt;';
       
  2105 				}
       
  2106 
       
  2107 				return c;
       
  2108 			}) : s;
       
  2109 		},
       
  2110 
       
  2111 		insertAfter : function(n, r) {
       
  2112 			var t = this;
       
  2113 
       
  2114 			r = t.get(r);
       
  2115 
       
  2116 			return this.run(n, function(n) {
       
  2117 				var p, ns;
       
  2118 
       
  2119 				p = r.parentNode;
       
  2120 				ns = r.nextSibling;
       
  2121 
       
  2122 				if (ns)
       
  2123 					p.insertBefore(n, ns);
       
  2124 				else
       
  2125 					p.appendChild(n);
       
  2126 
       
  2127 				return n;
       
  2128 			});
       
  2129 		},
       
  2130 
       
  2131 		isBlock : function(n) {
       
  2132 			if (n.nodeType && n.nodeType !== 1)
       
  2133 				return false;
       
  2134 
       
  2135 			n = n.nodeName || n;
       
  2136 
       
  2137 			return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TH|TBODY|TR|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n);
       
  2138 		},
       
  2139 
       
  2140 		replace : function(n, o, k) {
       
  2141 			var t = this;
       
  2142 
       
  2143 			if (is(o, 'array'))
       
  2144 				n = n.cloneNode(true);
       
  2145 
       
  2146 			return t.run(o, function(o) {
       
  2147 				if (k) {
       
  2148 					each(o.childNodes, function(c) {
       
  2149 						n.appendChild(c.cloneNode(true));
       
  2150 					});
       
  2151 				}
       
  2152 
       
  2153 				// Fix IE psuedo leak for elements since replacing elements if fairly common
       
  2154 				// Will break parentNode for some unknown reason
       
  2155 				if (t.fixPsuedoLeaks && o.nodeType === 1) {
       
  2156 					o.parentNode.insertBefore(n, o);
       
  2157 					t.remove(o);
       
  2158 					return n;
       
  2159 				}
       
  2160 
       
  2161 				return o.parentNode.replaceChild(n, o);
       
  2162 			});
       
  2163 		},
       
  2164 
       
  2165 		findCommonAncestor : function(a, b) {
       
  2166 			var ps = a, pe;
       
  2167 
       
  2168 			while (ps) {
       
  2169 				pe = b;
       
  2170 
       
  2171 				while (pe && ps != pe)
       
  2172 					pe = pe.parentNode;
       
  2173 
       
  2174 				if (ps == pe)
       
  2175 					break;
       
  2176 
       
  2177 				ps = ps.parentNode;
       
  2178 			}
       
  2179 
       
  2180 			if (!ps && a.ownerDocument)
       
  2181 				return a.ownerDocument.documentElement;
       
  2182 
       
  2183 			return ps;
       
  2184 		},
       
  2185 
       
  2186 		toHex : function(s) {
       
  2187 			var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);
       
  2188 
       
  2189 			function hex(s) {
       
  2190 				s = parseInt(s).toString(16);
       
  2191 
       
  2192 				return s.length > 1 ? s : '0' + s; // 0 -> 00
       
  2193 			};
       
  2194 
       
  2195 			if (c) {
       
  2196 				s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]);
       
  2197 
       
  2198 				return s;
       
  2199 			}
       
  2200 
       
  2201 			return s;
       
  2202 		},
       
  2203 
       
  2204 		getClasses : function() {
       
  2205 			var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov;
       
  2206 
       
  2207 			if (t.classes)
       
  2208 				return t.classes;
       
  2209 
       
  2210 			function addClasses(s) {
       
  2211 				// IE style imports
       
  2212 				each(s.imports, function(r) {
       
  2213 					addClasses(r);
       
  2214 				});
       
  2215 
       
  2216 				each(s.cssRules || s.rules, function(r) {
       
  2217 					// Real type or fake it on IE
       
  2218 					switch (r.type || 1) {
       
  2219 						// Rule
       
  2220 						case 1:
       
  2221 							if (r.selectorText) {
       
  2222 								each(r.selectorText.split(','), function(v) {
       
  2223 									v = v.replace(/^\s*|\s*$|^\s\./g, "");
       
  2224 
       
  2225 									// Is internal or it doesn't contain a class
       
  2226 									if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v))
       
  2227 										return;
       
  2228 
       
  2229 									// Remove everything but class name
       
  2230 									ov = v;
       
  2231 									v = v.replace(/.*\.([a-z0-9_\-]+).*/i, '$1');
       
  2232 
       
  2233 									// Filter classes
       
  2234 									if (f && !(v = f(v, ov)))
       
  2235 										return;
       
  2236 
       
  2237 									if (!lo[v]) {
       
  2238 										cl.push({'class' : v});
       
  2239 										lo[v] = 1;
       
  2240 									}
       
  2241 								});
       
  2242 							}
       
  2243 							break;
       
  2244 
       
  2245 						// Import
       
  2246 						case 3:
       
  2247 							addClasses(r.styleSheet);
       
  2248 							break;
       
  2249 					}
       
  2250 				});
       
  2251 			};
       
  2252 
       
  2253 			try {
       
  2254 				each(t.doc.styleSheets, addClasses);
       
  2255 			} catch (ex) {
       
  2256 				// Ignore
       
  2257 			}
       
  2258 
       
  2259 			if (cl.length > 0)
       
  2260 				t.classes = cl;
       
  2261 
       
  2262 			return cl;
       
  2263 		},
       
  2264 
       
  2265 		run : function(e, f, s) {
       
  2266 			var t = this, o;
       
  2267 
       
  2268 			if (t.doc && typeof(e) === 'string')
       
  2269 				e = t.get(e);
       
  2270 
       
  2271 			if (!e)
       
  2272 				return false;
       
  2273 
       
  2274 			s = s || this;
       
  2275 			if (!e.nodeType && (e.length || e.length === 0)) {
       
  2276 				o = [];
       
  2277 
       
  2278 				each(e, function(e, i) {
       
  2279 					if (e) {
       
  2280 						if (typeof(e) == 'string')
       
  2281 							e = t.doc.getElementById(e);
       
  2282 
       
  2283 						o.push(f.call(s, e, i));
       
  2284 					}
       
  2285 				});
       
  2286 
       
  2287 				return o;
       
  2288 			}
       
  2289 
       
  2290 			return f.call(s, e);
       
  2291 		},
       
  2292 
       
  2293 		getAttribs : function(n) {
       
  2294 			var o;
       
  2295 
       
  2296 			n = this.get(n);
       
  2297 
       
  2298 			if (!n)
       
  2299 				return [];
       
  2300 
       
  2301 			if (isIE) {
       
  2302 				o = [];
       
  2303 
       
  2304 				// Object will throw exception in IE
       
  2305 				if (n.nodeName == 'OBJECT')
       
  2306 					return n.attributes;
       
  2307 
       
  2308 				// IE doesn't keep the selected attribute if you clone option elements
       
  2309 				if (n.nodeName === 'OPTION' && this.getAttrib(n, 'selected'))
       
  2310 					o.push({specified : 1, nodeName : 'selected'});
       
  2311 
       
  2312 				// It's crazy that this is faster in IE but it's because it returns all attributes all the time
       
  2313 				n.cloneNode(false).outerHTML.replace(/<\/?[\w:]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=\w+|>/gi, '').replace(/[\w:]+/gi, function(a) {
       
  2314 					o.push({specified : 1, nodeName : a});
       
  2315 				});
       
  2316 
       
  2317 				return o;
       
  2318 			}
       
  2319 
       
  2320 			return n.attributes;
       
  2321 		},
       
  2322 
       
  2323 		destroy : function(s) {
       
  2324 			var t = this;
       
  2325 
       
  2326 			if (t.events)
       
  2327 				t.events.destroy();
       
  2328 
       
  2329 			t.win = t.doc = t.root = t.events = null;
       
  2330 
       
  2331 			// Manual destroy then remove unload handler
       
  2332 			if (!s)
       
  2333 				tinymce.removeUnload(t.destroy);
       
  2334 		},
       
  2335 
       
  2336 		createRng : function() {
       
  2337 			var d = this.doc;
       
  2338 
       
  2339 			return d.createRange ? d.createRange() : new tinymce.dom.Range(this);
       
  2340 		},
       
  2341 
       
  2342 		split : function(pe, e, re) {
       
  2343 			var t = this, r = t.createRng(), bef, aft, pa;
       
  2344 
       
  2345 			// W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sence
       
  2346 			// but we don't want that in our code since it serves no purpose
       
  2347 			// For example if this is chopped:
       
  2348 			//   <p>text 1<span><b>CHOP</b></span>text 2</p>
       
  2349 			// would produce:
       
  2350 			//   <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p>
       
  2351 			// this function will then trim of empty edges and produce:
       
  2352 			//   <p>text 1</p><b>CHOP</b><p>text 2</p>
       
  2353 			function trimEdge(n, na) {
       
  2354 				n = n[na];
       
  2355 
       
  2356 				if (n && n[na] && n[na].nodeType == 1 && isEmpty(n[na]))
       
  2357 					t.remove(n[na]);
       
  2358 			};
       
  2359 
       
  2360 			function isEmpty(n) {
       
  2361 				n = t.getOuterHTML(n);
       
  2362 				n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars
       
  2363 				n = n.replace(/<[^>]+>/g, ''); // Remove all tags
       
  2364 
       
  2365 				return n.replace(/[ \t\r\n]+|&nbsp;|&#160;/g, '') == '';
       
  2366 			};
       
  2367 
       
  2368 			// Added until Gecko can create real HTML documents using implementation.createHTMLDocument
       
  2369 			// this is to future proof it if Gecko decides to implement the error checking for range methods.
       
  2370 			function nodeIndex(n) {
       
  2371 				var i = 0;
       
  2372 
       
  2373 				while (n.previousSibling) {
       
  2374 					i++;
       
  2375 					n = n.previousSibling;
       
  2376 				}
       
  2377 
       
  2378 				return i;
       
  2379 			};
       
  2380 
       
  2381 			if (pe && e) {
       
  2382 				// Get before chunk
       
  2383 				r.setStart(pe.parentNode, nodeIndex(pe));
       
  2384 				r.setEnd(e.parentNode, nodeIndex(e));
       
  2385 				bef = r.extractContents();
       
  2386 
       
  2387 				// Get after chunk
       
  2388 				r = t.createRng();
       
  2389 				r.setStart(e.parentNode, nodeIndex(e) + 1);
       
  2390 				r.setEnd(pe.parentNode, nodeIndex(pe) + 1);
       
  2391 				aft = r.extractContents();
       
  2392 
       
  2393 				// Insert chunks and remove parent
       
  2394 				pa = pe.parentNode;
       
  2395 
       
  2396 				// Remove right side edge of the before contents
       
  2397 				trimEdge(bef, 'lastChild');
       
  2398 
       
  2399 				if (!isEmpty(bef))
       
  2400 					pa.insertBefore(bef, pe);
       
  2401 
       
  2402 				if (re)
       
  2403 					pa.replaceChild(re, e);
       
  2404 				else
       
  2405 					pa.insertBefore(e, pe);
       
  2406 
       
  2407 				// Remove left site edge of the after contents
       
  2408 				trimEdge(aft, 'firstChild');
       
  2409 
       
  2410 				if (!isEmpty(aft))
       
  2411 					pa.insertBefore(aft, pe);
       
  2412 
       
  2413 				t.remove(pe);
       
  2414 
       
  2415 				return re || e;
       
  2416 			}
       
  2417 		},
       
  2418 
       
  2419 		bind : function(target, name, func, scope) {
       
  2420 			var t = this;
       
  2421 
       
  2422 			if (!t.events)
       
  2423 				t.events = new tinymce.dom.EventUtils();
       
  2424 
       
  2425 			return t.events.add(target, name, func, scope || this);
       
  2426 		},
       
  2427 
       
  2428 		unbind : function(target, name, func) {
       
  2429 			var t = this;
       
  2430 
       
  2431 			if (!t.events)
       
  2432 				t.events = new tinymce.dom.EventUtils();
       
  2433 
       
  2434 			return t.events.remove(target, name, func);
       
  2435 		},
       
  2436 
       
  2437 
       
  2438 		_findSib : function(node, selector, name) {
       
  2439 			var t = this, f = selector;
       
  2440 
       
  2441 			if (node) {
       
  2442 				// If expression make a function of it using is
       
  2443 				if (is(f, 'string')) {
       
  2444 					f = function(node) {
       
  2445 						return t.is(node, selector);
       
  2446 					};
       
  2447 				}
       
  2448 
       
  2449 				// Loop all siblings
       
  2450 				for (node = node[name]; node; node = node[name]) {
       
  2451 					if (f(node))
       
  2452 						return node;
       
  2453 				}
       
  2454 			}
       
  2455 
       
  2456 			return null;
       
  2457 		},
       
  2458 
       
  2459 		_isRes : function(c) {
       
  2460 			// Is live resizble element
       
  2461 			return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c);
       
  2462 		}
       
  2463 
       
  2464 		/*
       
  2465 		walk : function(n, f, s) {
       
  2466 			var d = this.doc, w;
       
  2467 
       
  2468 			if (d.createTreeWalker) {
       
  2469 				w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
       
  2470 
       
  2471 				while ((n = w.nextNode()) != null)
       
  2472 					f.call(s || this, n);
       
  2473 			} else
       
  2474 				tinymce.walk(n, f, 'childNodes', s);
       
  2475 		}
       
  2476 		*/
       
  2477 
       
  2478 		/*
       
  2479 		toRGB : function(s) {
       
  2480 			var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s);
       
  2481 
       
  2482 			if (c) {
       
  2483 				// #FFF -> #FFFFFF
       
  2484 				if (!is(c[3]))
       
  2485 					c[3] = c[2] = c[1];
       
  2486 
       
  2487 				return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")";
       
  2488 			}
       
  2489 
       
  2490 			return s;
       
  2491 		}
       
  2492 		*/
       
  2493 	});
       
  2494 
       
  2495 	tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0});
       
  2496 })(tinymce);
       
  2497 (function(ns) {
       
  2498 	// Traverse constants
       
  2499 	var EXTRACT = 0, CLONE = 1, DELETE = 2, extend = tinymce.extend;
       
  2500 
       
  2501 	function indexOf(child, parent) {
       
  2502 		var i, node;
       
  2503 
       
  2504 		if (child.parentNode != parent)
       
  2505 			return -1;
       
  2506 
       
  2507 		for (node = parent.firstChild, i = 0; node != child; node = node.nextSibling)
       
  2508 			i++;
       
  2509 
       
  2510 		return i;
       
  2511 	};
       
  2512 
       
  2513 	function nodeIndex(n) {
       
  2514 		var i = 0;
       
  2515 
       
  2516 		while (n.previousSibling) {
       
  2517 			i++;
       
  2518 			n = n.previousSibling;
       
  2519 		}
       
  2520 
       
  2521 		return i;
       
  2522 	};
       
  2523 
       
  2524 	function getSelectedNode(container, offset) {
       
  2525 		var child;
       
  2526 
       
  2527 		if (container.nodeType == 3 /* TEXT_NODE */)
       
  2528 			return container;
       
  2529 
       
  2530 		if (offset < 0)
       
  2531 			return container;
       
  2532 
       
  2533 		child = container.firstChild;
       
  2534 		while (child != null && offset > 0) {
       
  2535 			--offset;
       
  2536 			child = child.nextSibling;
       
  2537 		}
       
  2538 
       
  2539 		if (child != null)
       
  2540 			return child;
       
  2541 
       
  2542 		return container;
       
  2543 	};
       
  2544 
       
  2545 	// Range constructor
       
  2546 	function Range(dom) {
       
  2547 		var d = dom.doc;
       
  2548 
       
  2549 		extend(this, {
       
  2550 			dom : dom,
       
  2551 
       
  2552 			// Inital states
       
  2553 			startContainer : d,
       
  2554 			startOffset : 0,
       
  2555 			endContainer : d,
       
  2556 			endOffset : 0,
       
  2557 			collapsed : true,
       
  2558 			commonAncestorContainer : d,
       
  2559 
       
  2560 			// Range constants
       
  2561 			START_TO_START : 0,
       
  2562 			START_TO_END : 1,
       
  2563 			END_TO_END : 2,
       
  2564 			END_TO_START : 3
       
  2565 		});
       
  2566 	};
       
  2567 
       
  2568 	// Add range methods
       
  2569 	extend(Range.prototype, {
       
  2570 		setStart : function(n, o) {
       
  2571 			this._setEndPoint(true, n, o);
       
  2572 		},
       
  2573 
       
  2574 		setEnd : function(n, o) {
       
  2575 			this._setEndPoint(false, n, o);
       
  2576 		},
       
  2577 
       
  2578 		setStartBefore : function(n) {
       
  2579 			this.setStart(n.parentNode, nodeIndex(n));
       
  2580 		},
       
  2581 
       
  2582 		setStartAfter : function(n) {
       
  2583 			this.setStart(n.parentNode, nodeIndex(n) + 1);
       
  2584 		},
       
  2585 
       
  2586 		setEndBefore : function(n) {
       
  2587 			this.setEnd(n.parentNode, nodeIndex(n));
       
  2588 		},
       
  2589 
       
  2590 		setEndAfter : function(n) {
       
  2591 			this.setEnd(n.parentNode, nodeIndex(n) + 1);
       
  2592 		},
       
  2593 
       
  2594 		collapse : function(ts) {
       
  2595 			var t = this;
       
  2596 
       
  2597 			if (ts) {
       
  2598 				t.endContainer = t.startContainer;
       
  2599 				t.endOffset = t.startOffset;
       
  2600 			} else {
       
  2601 				t.startContainer = t.endContainer;
       
  2602 				t.startOffset = t.endOffset;
       
  2603 			}
       
  2604 
       
  2605 			t.collapsed = true;
       
  2606 		},
       
  2607 
       
  2608 		selectNode : function(n) {
       
  2609 			this.setStartBefore(n);
       
  2610 			this.setEndAfter(n);
       
  2611 		},
       
  2612 
       
  2613 		selectNodeContents : function(n) {
       
  2614 			this.setStart(n, 0);
       
  2615 			this.setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);
       
  2616 		},
       
  2617 
       
  2618 		compareBoundaryPoints : function(h, r) {
       
  2619 			var t = this, sc = t.startContainer, so = t.startOffset, ec = t.endContainer, eo = t.endOffset;
       
  2620 
       
  2621 			// Check START_TO_START
       
  2622 			if (h === 0)
       
  2623 				return t._compareBoundaryPoints(sc, so, sc, so);
       
  2624 
       
  2625 			// Check START_TO_END
       
  2626 			if (h === 1)
       
  2627 				return t._compareBoundaryPoints(sc, so, ec, eo);
       
  2628 
       
  2629 			// Check END_TO_END
       
  2630 			if (h === 2)
       
  2631 				return t._compareBoundaryPoints(ec, eo, ec, eo);
       
  2632 
       
  2633 			// Check END_TO_START
       
  2634 			if (h === 3)
       
  2635 				return t._compareBoundaryPoints(ec, eo, sc, so);
       
  2636 		},
       
  2637 
       
  2638 		deleteContents : function() {
       
  2639 			this._traverse(DELETE);
       
  2640 		},
       
  2641 
       
  2642 		extractContents : function() {
       
  2643 			return this._traverse(EXTRACT);
       
  2644 		},
       
  2645 
       
  2646 		cloneContents : function() {
       
  2647 			return this._traverse(CLONE);
       
  2648 		},
       
  2649 
       
  2650 		insertNode : function(n) {
       
  2651 			var t = this, nn, o;
       
  2652 
       
  2653 			// Node is TEXT_NODE or CDATA
       
  2654 			if (n.nodeType === 3 || n.nodeType === 4) {
       
  2655 				nn = t.startContainer.splitText(t.startOffset);
       
  2656 				t.startContainer.parentNode.insertBefore(n, nn);
       
  2657 			} else {
       
  2658 				// Insert element node
       
  2659 				if (t.startContainer.childNodes.length > 0)
       
  2660 					o = t.startContainer.childNodes[t.startOffset];
       
  2661 
       
  2662 				t.startContainer.insertBefore(n, o);
       
  2663 			}
       
  2664 		},
       
  2665 
       
  2666 		surroundContents : function(n) {
       
  2667 			var t = this, f = t.extractContents();
       
  2668 
       
  2669 			t.insertNode(n);
       
  2670 			n.appendChild(f);
       
  2671 			t.selectNode(n);
       
  2672 		},
       
  2673 
       
  2674 		cloneRange : function() {
       
  2675 			var t = this;
       
  2676 
       
  2677 			return extend(new Range(t.dom), {
       
  2678 				startContainer : t.startContainer,
       
  2679 				startOffset : t.startOffset,
       
  2680 				endContainer : t.endContainer,
       
  2681 				endOffset : t.endOffset,
       
  2682 				collapsed : t.collapsed,
       
  2683 				commonAncestorContainer : t.commonAncestorContainer
       
  2684 			});
       
  2685 		},
       
  2686 
       
  2687 /*
       
  2688 		detach : function() {
       
  2689 			// Not implemented
       
  2690 		},
       
  2691 */
       
  2692 		// Internal methods
       
  2693 
       
  2694 		_isCollapsed : function() {
       
  2695 			return (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
       
  2696 		},
       
  2697 
       
  2698 		_compareBoundaryPoints : function (containerA, offsetA, containerB, offsetB) {
       
  2699 			var c, offsetC, n, cmnRoot, childA, childB;
       
  2700 
       
  2701 			// In the first case the boundary-points have the same container. A is before B 
       
  2702 			// if its offset is less than the offset of B, A is equal to B if its offset is 
       
  2703 			// equal to the offset of B, and A is after B if its offset is greater than the 
       
  2704 			// offset of B.
       
  2705 			if (containerA == containerB) {
       
  2706 				if (offsetA == offsetB) {
       
  2707 					return 0; // equal
       
  2708 				} else if (offsetA < offsetB) {
       
  2709 					return -1; // before
       
  2710 				} else {
       
  2711 					return 1; // after
       
  2712 				}
       
  2713 			}
       
  2714 
       
  2715 			// In the second case a child node C of the container of A is an ancestor 
       
  2716 			// container of B. In this case, A is before B if the offset of A is less than or 
       
  2717 			// equal to the index of the child node C and A is after B otherwise.
       
  2718 			c = containerB;
       
  2719 			while (c && c.parentNode != containerA) {
       
  2720 				c = c.parentNode;
       
  2721 			}
       
  2722 			if (c) {
       
  2723 				offsetC = 0;
       
  2724 				n = containerA.firstChild;
       
  2725 
       
  2726 				while (n != c && offsetC < offsetA) {
       
  2727 					offsetC++;
       
  2728 					n = n.nextSibling;
       
  2729 				}
       
  2730 
       
  2731 				if (offsetA <= offsetC) {
       
  2732 					return -1; // before
       
  2733 				} else {
       
  2734 					return 1; // after
       
  2735 				}
       
  2736 			}
       
  2737 
       
  2738 			// In the third case a child node C of the container of B is an ancestor container 
       
  2739 			// of A. In this case, A is before B if the index of the child node C is less than 
       
  2740 			// the offset of B and A is after B otherwise.
       
  2741 			c = containerA;
       
  2742 			while (c && c.parentNode != containerB) {
       
  2743 				c = c.parentNode;
       
  2744 			}
       
  2745 
       
  2746 			if (c) {
       
  2747 				offsetC = 0;
       
  2748 				n = containerB.firstChild;
       
  2749 
       
  2750 				while (n != c && offsetC < offsetB) {
       
  2751 					offsetC++;
       
  2752 					n = n.nextSibling;
       
  2753 				}
       
  2754 
       
  2755 				if (offsetC < offsetB) {
       
  2756 					return -1; // before
       
  2757 				} else {
       
  2758 					return 1; // after
       
  2759 				}
       
  2760 			}
       
  2761 
       
  2762 			// In the fourth case, none of three other cases hold: the containers of A and B 
       
  2763 			// are siblings or descendants of sibling nodes. In this case, A is before B if 
       
  2764 			// the container of A is before the container of B in a pre-order traversal of the
       
  2765 			// Ranges' context tree and A is after B otherwise.
       
  2766 			cmnRoot = this.dom.findCommonAncestor(containerA, containerB);
       
  2767 			childA = containerA;
       
  2768 
       
  2769 			while (childA && childA.parentNode != cmnRoot) {
       
  2770 				childA = childA.parentNode;  
       
  2771 			}
       
  2772 
       
  2773 			if (!childA) {
       
  2774 				childA = cmnRoot;
       
  2775 			}
       
  2776 
       
  2777 			childB = containerB;
       
  2778 			while (childB && childB.parentNode != cmnRoot) {
       
  2779 				childB = childB.parentNode;
       
  2780 			}
       
  2781 
       
  2782 			if (!childB) {
       
  2783 				childB = cmnRoot;
       
  2784 			}
       
  2785 
       
  2786 			if (childA == childB) {
       
  2787 				return 0; // equal
       
  2788 			}
       
  2789 
       
  2790 			n = cmnRoot.firstChild;
       
  2791 			while (n) {
       
  2792 				if (n == childA) {
       
  2793 					return -1; // before
       
  2794 				}
       
  2795 
       
  2796 				if (n == childB) {
       
  2797 					return 1; // after
       
  2798 				}
       
  2799 
       
  2800 				n = n.nextSibling;
       
  2801 			}
       
  2802 		},
       
  2803 
       
  2804 		_setEndPoint : function(st, n, o) {
       
  2805 			var t = this, ec, sc;
       
  2806 
       
  2807 			if (st) {
       
  2808 				t.startContainer = n;
       
  2809 				t.startOffset = o;
       
  2810 			} else {
       
  2811 				t.endContainer = n;
       
  2812 				t.endOffset = o;
       
  2813 			}
       
  2814 
       
  2815 			// If one boundary-point of a Range is set to have a root container 
       
  2816 			// other than the current one for the Range, the Range is collapsed to 
       
  2817 			// the new position. This enforces the restriction that both boundary-
       
  2818 			// points of a Range must have the same root container.
       
  2819 			ec = t.endContainer;
       
  2820 			while (ec.parentNode)
       
  2821 				ec = ec.parentNode;
       
  2822 
       
  2823 			sc = t.startContainer;
       
  2824 			while (sc.parentNode)
       
  2825 				sc = sc.parentNode;
       
  2826 
       
  2827 			if (sc != ec) {
       
  2828 				t.collapse(st);
       
  2829 			} else {
       
  2830 				// The start position of a Range is guaranteed to never be after the 
       
  2831 				// end position. To enforce this restriction, if the start is set to 
       
  2832 				// be at a position after the end, the Range is collapsed to that 
       
  2833 				// position.
       
  2834 				if (t._compareBoundaryPoints(t.startContainer, t.startOffset, t.endContainer, t.endOffset) > 0)
       
  2835 					t.collapse(st);
       
  2836 			}
       
  2837 
       
  2838 			t.collapsed = t._isCollapsed();
       
  2839 			t.commonAncestorContainer = t.dom.findCommonAncestor(t.startContainer, t.endContainer);
       
  2840 		},
       
  2841 
       
  2842 		// This code is heavily "inspired" by the Apache Xerces implementation. I hope they don't mind. :)
       
  2843 
       
  2844 		_traverse : function(how) {
       
  2845 			var t = this, c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;
       
  2846 
       
  2847 			if (t.startContainer == t.endContainer)
       
  2848 				return t._traverseSameContainer(how);
       
  2849 
       
  2850 			for (c = t.endContainer, p = c.parentNode; p != null; c = p, p = p.parentNode) {
       
  2851 				if (p == t.startContainer)
       
  2852 					return t._traverseCommonStartContainer(c, how);
       
  2853 
       
  2854 				++endContainerDepth;
       
  2855 			}
       
  2856 
       
  2857 			for (c = t.startContainer, p = c.parentNode; p != null; c = p, p = p.parentNode) {
       
  2858 				if (p == t.endContainer)
       
  2859 					return t._traverseCommonEndContainer(c, how);
       
  2860 
       
  2861 				++startContainerDepth;
       
  2862 			}
       
  2863 
       
  2864 			depthDiff = startContainerDepth - endContainerDepth;
       
  2865 
       
  2866 			startNode = t.startContainer;
       
  2867 			while (depthDiff > 0) {
       
  2868 				startNode = startNode.parentNode;
       
  2869 				depthDiff--;
       
  2870 			}
       
  2871 
       
  2872 			endNode = t.endContainer;
       
  2873 			while (depthDiff < 0) {
       
  2874 				endNode = endNode.parentNode;
       
  2875 				depthDiff++;
       
  2876 			}
       
  2877 
       
  2878 			// ascend the ancestor hierarchy until we have a common parent.
       
  2879 			for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {
       
  2880 				startNode = sp;
       
  2881 				endNode = ep;
       
  2882 			}
       
  2883 
       
  2884 			return t._traverseCommonAncestors(startNode, endNode, how);
       
  2885 		},
       
  2886 
       
  2887 		_traverseSameContainer : function(how) {
       
  2888 			var t = this, frag, s, sub, n, cnt, sibling, xferNode;
       
  2889 
       
  2890 			if (how != DELETE)
       
  2891 				frag = t.dom.doc.createDocumentFragment();
       
  2892 
       
  2893 			// If selection is empty, just return the fragment
       
  2894 			if (t.startOffset == t.endOffset)
       
  2895 				return frag;
       
  2896 
       
  2897 			// Text node needs special case handling
       
  2898 			if (t.startContainer.nodeType == 3 /* TEXT_NODE */) {
       
  2899 				// get the substring
       
  2900 				s = t.startContainer.nodeValue;
       
  2901 				sub = s.substring(t.startOffset, t.endOffset);
       
  2902 
       
  2903 				// set the original text node to its new value
       
  2904 				if (how != CLONE) {
       
  2905 					t.startContainer.deleteData(t.startOffset, t.endOffset - t.startOffset);
       
  2906 
       
  2907 					// Nothing is partially selected, so collapse to start point
       
  2908 					t.collapse(true);
       
  2909 				}
       
  2910 
       
  2911 				if (how == DELETE)
       
  2912 					return null;
       
  2913 
       
  2914 				frag.appendChild(t.dom.doc.createTextNode(sub));
       
  2915 				return frag;
       
  2916 			}
       
  2917 
       
  2918 			// Copy nodes between the start/end offsets.
       
  2919 			n = getSelectedNode(t.startContainer, t.startOffset);
       
  2920 			cnt = t.endOffset - t.startOffset;
       
  2921 
       
  2922 			while (cnt > 0) {
       
  2923 				sibling = n.nextSibling;
       
  2924 				xferNode = t._traverseFullySelected(n, how);
       
  2925 
       
  2926 				if (frag)
       
  2927 					frag.appendChild( xferNode );
       
  2928 
       
  2929 				--cnt;
       
  2930 				n = sibling;
       
  2931 			}
       
  2932 
       
  2933 			// Nothing is partially selected, so collapse to start point
       
  2934 			if (how != CLONE)
       
  2935 				t.collapse(true);
       
  2936 
       
  2937 			return frag;
       
  2938 		},
       
  2939 
       
  2940 		_traverseCommonStartContainer : function(endAncestor, how) {
       
  2941 			var t = this, frag, n, endIdx, cnt, sibling, xferNode;
       
  2942 
       
  2943 			if (how != DELETE)
       
  2944 				frag = t.dom.doc.createDocumentFragment();
       
  2945 
       
  2946 			n = t._traverseRightBoundary(endAncestor, how);
       
  2947 
       
  2948 			if (frag)
       
  2949 				frag.appendChild(n);
       
  2950 
       
  2951 			endIdx = indexOf(endAncestor, t.startContainer);
       
  2952 			cnt = endIdx - t.startOffset;
       
  2953 
       
  2954 			if (cnt <= 0) {
       
  2955 				// Collapse to just before the endAncestor, which 
       
  2956 				// is partially selected.
       
  2957 				if (how != CLONE) {
       
  2958 					t.setEndBefore(endAncestor);
       
  2959 					t.collapse(false);
       
  2960 				}
       
  2961 
       
  2962 				return frag;
       
  2963 			}
       
  2964 
       
  2965 			n = endAncestor.previousSibling;
       
  2966 			while (cnt > 0) {
       
  2967 				sibling = n.previousSibling;
       
  2968 				xferNode = t._traverseFullySelected(n, how);
       
  2969 
       
  2970 				if (frag)
       
  2971 					frag.insertBefore(xferNode, frag.firstChild);
       
  2972 
       
  2973 				--cnt;
       
  2974 				n = sibling;
       
  2975 			}
       
  2976 
       
  2977 			// Collapse to just before the endAncestor, which 
       
  2978 			// is partially selected.
       
  2979 			if (how != CLONE) {
       
  2980 				t.setEndBefore(endAncestor);
       
  2981 				t.collapse(false);
       
  2982 			}
       
  2983 
       
  2984 			return frag;
       
  2985 		},
       
  2986 
       
  2987 		_traverseCommonEndContainer : function(startAncestor, how) {
       
  2988 			var t = this, frag, startIdx, n, cnt, sibling, xferNode;
       
  2989 
       
  2990 			if (how != DELETE)
       
  2991 				frag = t.dom.doc.createDocumentFragment();
       
  2992 
       
  2993 			n = t._traverseLeftBoundary(startAncestor, how);
       
  2994 			if (frag)
       
  2995 				frag.appendChild(n);
       
  2996 
       
  2997 			startIdx = indexOf(startAncestor, t.endContainer);
       
  2998 			++startIdx;  // Because we already traversed it....
       
  2999 
       
  3000 			cnt = t.endOffset - startIdx;
       
  3001 			n = startAncestor.nextSibling;
       
  3002 			while (cnt > 0) {
       
  3003 				sibling = n.nextSibling;
       
  3004 				xferNode = t._traverseFullySelected(n, how);
       
  3005 
       
  3006 				if (frag)
       
  3007 					frag.appendChild(xferNode);
       
  3008 
       
  3009 				--cnt;
       
  3010 				n = sibling;
       
  3011 			}
       
  3012 
       
  3013 			if (how != CLONE) {
       
  3014 				t.setStartAfter(startAncestor);
       
  3015 				t.collapse(true);
       
  3016 			}
       
  3017 
       
  3018 			return frag;
       
  3019 		},
       
  3020 
       
  3021 		_traverseCommonAncestors : function(startAncestor, endAncestor, how) {
       
  3022 			var t = this, n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling;
       
  3023 
       
  3024 			if (how != DELETE)
       
  3025 				frag = t.dom.doc.createDocumentFragment();
       
  3026 
       
  3027 			n = t._traverseLeftBoundary(startAncestor, how);
       
  3028 			if (frag)
       
  3029 				frag.appendChild(n);
       
  3030 
       
  3031 			commonParent = startAncestor.parentNode;
       
  3032 			startOffset = indexOf(startAncestor, commonParent);
       
  3033 			endOffset = indexOf(endAncestor, commonParent);
       
  3034 			++startOffset;
       
  3035 
       
  3036 			cnt = endOffset - startOffset;
       
  3037 			sibling = startAncestor.nextSibling;
       
  3038 
       
  3039 			while (cnt > 0) {
       
  3040 				nextSibling = sibling.nextSibling;
       
  3041 				n = t._traverseFullySelected(sibling, how);
       
  3042 
       
  3043 				if (frag)
       
  3044 					frag.appendChild(n);
       
  3045 
       
  3046 				sibling = nextSibling;
       
  3047 				--cnt;
       
  3048 			}
       
  3049 
       
  3050 			n = t._traverseRightBoundary(endAncestor, how);
       
  3051 
       
  3052 			if (frag)
       
  3053 				frag.appendChild(n);
       
  3054 
       
  3055 			if (how != CLONE) {
       
  3056 				t.setStartAfter(startAncestor);
       
  3057 				t.collapse(true);
       
  3058 			}
       
  3059 
       
  3060 			return frag;
       
  3061 		},
       
  3062 
       
  3063 		_traverseRightBoundary : function(root, how) {
       
  3064 			var t = this, next = getSelectedNode(t.endContainer, t.endOffset - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent;
       
  3065 			var isFullySelected = next != t.endContainer;
       
  3066 
       
  3067 			if (next == root)
       
  3068 				return t._traverseNode(next, isFullySelected, false, how);
       
  3069 
       
  3070 			parent = next.parentNode;
       
  3071 			clonedParent = t._traverseNode(parent, false, false, how);
       
  3072 
       
  3073 			while (parent != null) {
       
  3074 				while (next != null) {
       
  3075 					prevSibling = next.previousSibling;
       
  3076 					clonedChild = t._traverseNode(next, isFullySelected, false, how);
       
  3077 
       
  3078 					if (how != DELETE)
       
  3079 						clonedParent.insertBefore(clonedChild, clonedParent.firstChild);
       
  3080 
       
  3081 					isFullySelected = true;
       
  3082 					next = prevSibling;
       
  3083 				}
       
  3084 
       
  3085 				if (parent == root)
       
  3086 					return clonedParent;
       
  3087 
       
  3088 				next = parent.previousSibling;
       
  3089 				parent = parent.parentNode;
       
  3090 
       
  3091 				clonedGrandParent = t._traverseNode(parent, false, false, how);
       
  3092 
       
  3093 				if (how != DELETE)
       
  3094 					clonedGrandParent.appendChild(clonedParent);
       
  3095 
       
  3096 				clonedParent = clonedGrandParent;
       
  3097 			}
       
  3098 
       
  3099 			// should never occur
       
  3100 			return null;
       
  3101 		},
       
  3102 
       
  3103 		_traverseLeftBoundary : function(root, how) {
       
  3104 			var t = this, next = getSelectedNode(t.startContainer, t.startOffset);
       
  3105 			var isFullySelected = next != t.startContainer, parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;
       
  3106 
       
  3107 			if (next == root)
       
  3108 				return t._traverseNode(next, isFullySelected, true, how);
       
  3109 
       
  3110 			parent = next.parentNode;
       
  3111 			clonedParent = t._traverseNode(parent, false, true, how);
       
  3112 
       
  3113 			while (parent != null) {
       
  3114 				while (next != null) {
       
  3115 					nextSibling = next.nextSibling;
       
  3116 					clonedChild = t._traverseNode(next, isFullySelected, true, how);
       
  3117 
       
  3118 					if (how != DELETE)
       
  3119 						clonedParent.appendChild(clonedChild);
       
  3120 
       
  3121 					isFullySelected = true;
       
  3122 					next = nextSibling;
       
  3123 				}
       
  3124 
       
  3125 				if (parent == root)
       
  3126 					return clonedParent;
       
  3127 
       
  3128 				next = parent.nextSibling;
       
  3129 				parent = parent.parentNode;
       
  3130 
       
  3131 				clonedGrandParent = t._traverseNode(parent, false, true, how);
       
  3132 
       
  3133 				if (how != DELETE)
       
  3134 					clonedGrandParent.appendChild(clonedParent);
       
  3135 
       
  3136 				clonedParent = clonedGrandParent;
       
  3137 			}
       
  3138 
       
  3139 			// should never occur
       
  3140 			return null;
       
  3141 		},
       
  3142 
       
  3143 		_traverseNode : function(n, isFullySelected, isLeft, how) {
       
  3144 			var t = this, txtValue, newNodeValue, oldNodeValue, offset, newNode;
       
  3145 
       
  3146 			if (isFullySelected)
       
  3147 				return t._traverseFullySelected(n, how);
       
  3148 
       
  3149 			if (n.nodeType == 3 /* TEXT_NODE */) {
       
  3150 				txtValue = n.nodeValue;
       
  3151 
       
  3152 				if (isLeft) {
       
  3153 					offset = t.startOffset;
       
  3154 					newNodeValue = txtValue.substring(offset);
       
  3155 					oldNodeValue = txtValue.substring(0, offset);
       
  3156 				} else {
       
  3157 					offset = t.endOffset;
       
  3158 					newNodeValue = txtValue.substring(0, offset);
       
  3159 					oldNodeValue = txtValue.substring(offset);
       
  3160 				}
       
  3161 
       
  3162 				if (how != CLONE)
       
  3163 					n.nodeValue = oldNodeValue;
       
  3164 
       
  3165 				if (how == DELETE)
       
  3166 					return null;
       
  3167 
       
  3168 				newNode = n.cloneNode(false);
       
  3169 				newNode.nodeValue = newNodeValue;
       
  3170 
       
  3171 				return newNode;
       
  3172 			}
       
  3173 
       
  3174 			if (how == DELETE)
       
  3175 				return null;
       
  3176 
       
  3177 			return n.cloneNode(false);
       
  3178 		},
       
  3179 
       
  3180 		_traverseFullySelected : function(n, how) {
       
  3181 			var t = this;
       
  3182 
       
  3183 			if (how != DELETE)
       
  3184 				return how == CLONE ? n.cloneNode(true) : n;
       
  3185 
       
  3186 			n.parentNode.removeChild(n);
       
  3187 			return null;
       
  3188 		}
       
  3189 	});
       
  3190 
       
  3191 	ns.Range = Range;
       
  3192 })(tinymce.dom);
       
  3193 (function() {
       
  3194 	function Selection(selection) {
       
  3195 		var t = this, invisibleChar = '\uFEFF', range, lastIERng;
       
  3196 
       
  3197 		function compareRanges(rng1, rng2) {
       
  3198 			if (rng1 && rng2) {
       
  3199 				// Both are control ranges and the selected element matches
       
  3200 				if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))
       
  3201 					return 1;
       
  3202 
       
  3203 				// Both are text ranges and the range matches
       
  3204 				if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1))
       
  3205 					return 1;
       
  3206 			}
       
  3207 
       
  3208 			return 0;
       
  3209 		};
       
  3210 
       
  3211 		function getRange() {
       
  3212 			var dom = selection.dom, ieRange = selection.getRng(), domRange = dom.createRng(), startPos, endPos, element, sc, ec, collapsed;
       
  3213 
       
  3214 			function findIndex(element) {
       
  3215 				var nl = element.parentNode.childNodes, i;
       
  3216 
       
  3217 				for (i = nl.length - 1; i >= 0; i--) {
       
  3218 					if (nl[i] == element)
       
  3219 						return i;
       
  3220 				}
       
  3221 
       
  3222 				return -1;
       
  3223 			};
       
  3224 
       
  3225 			function findEndPoint(start) {
       
  3226 				var rng = ieRange.duplicate(), parent, i, nl, n, offset = 0, index = 0, pos, tmpRng;
       
  3227 
       
  3228 				// Insert marker character
       
  3229 				rng.collapse(start);
       
  3230 				parent = rng.parentElement();
       
  3231 				rng.pasteHTML(invisibleChar); // Needs to be a pasteHTML instead of .text = since IE has a bug with nodeValue
       
  3232 
       
  3233 				// Find marker character
       
  3234 				nl = parent.childNodes;
       
  3235 				for (i = 0; i < nl.length; i++) {
       
  3236 					n = nl[i];
       
  3237 
       
  3238 					// Calculate node index excluding text node fragmentation
       
  3239 					if (i > 0 && (n.nodeType !== 3 || nl[i - 1].nodeType !== 3))
       
  3240 						index++;
       
  3241 
       
  3242 					// If text node then calculate offset
       
  3243 					if (n.nodeType === 3) {
       
  3244 						// Look for marker
       
  3245 						pos = n.nodeValue.indexOf(invisibleChar);
       
  3246 						if (pos !== -1) {
       
  3247 							offset += pos;
       
  3248 							break;
       
  3249 						}
       
  3250 
       
  3251 						offset += n.nodeValue.length;
       
  3252 					} else
       
  3253 						offset = 0;
       
  3254 				}
       
  3255 
       
  3256 				// Remove marker character
       
  3257 				rng.moveStart('character', -1);
       
  3258 				rng.text = '';
       
  3259 
       
  3260 				return {index : index, offset : offset, parent : parent};
       
  3261 			};
       
  3262 
       
  3263 			// If selection is outside the current document just return an empty range
       
  3264 			element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
       
  3265 			if (element.ownerDocument != dom.doc)
       
  3266 				return domRange;
       
  3267 
       
  3268 			// Handle control selection or text selection of a image
       
  3269 			if (ieRange.item || !element.hasChildNodes()) {
       
  3270 				domRange.setStart(element.parentNode, findIndex(element));
       
  3271 				domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
       
  3272 
       
  3273 				return domRange;
       
  3274 			}
       
  3275 
       
  3276 			// Check collapsed state
       
  3277 			collapsed = selection.isCollapsed();
       
  3278 
       
  3279 			// Find start and end pos index and offset
       
  3280 			startPos = findEndPoint(true);
       
  3281 			endPos = findEndPoint(false);
       
  3282 
       
  3283 			// Normalize the elements to avoid fragmented dom
       
  3284 			startPos.parent.normalize();
       
  3285 			endPos.parent.normalize();
       
  3286 
       
  3287 			// Set start container and offset
       
  3288 			sc = startPos.parent.childNodes[Math.min(startPos.index, startPos.parent.childNodes.length - 1)];
       
  3289 
       
  3290 			if (sc.nodeType != 3)
       
  3291 				domRange.setStart(startPos.parent, startPos.index);
       
  3292 			else
       
  3293 				domRange.setStart(startPos.parent.childNodes[startPos.index], startPos.offset);
       
  3294 
       
  3295 			// Set end container and offset
       
  3296 			ec = endPos.parent.childNodes[Math.min(endPos.index, endPos.parent.childNodes.length - 1)];
       
  3297 
       
  3298 			if (ec.nodeType != 3) {
       
  3299 				if (!collapsed)
       
  3300 					endPos.index++;
       
  3301 
       
  3302 				domRange.setEnd(endPos.parent, endPos.index);
       
  3303 			} else
       
  3304 				domRange.setEnd(endPos.parent.childNodes[endPos.index], endPos.offset);
       
  3305 
       
  3306 			// If not collapsed then make sure offsets are valid
       
  3307 			if (!collapsed) {
       
  3308 				sc = domRange.startContainer;
       
  3309 				if (sc.nodeType == 1)
       
  3310 					domRange.setStart(sc, Math.min(domRange.startOffset, sc.childNodes.length));
       
  3311 
       
  3312 				ec = domRange.endContainer;
       
  3313 				if (ec.nodeType == 1)
       
  3314 					domRange.setEnd(ec, Math.min(domRange.endOffset, ec.childNodes.length));
       
  3315 			}
       
  3316 
       
  3317 			// Restore selection to new range
       
  3318 			t.addRange(domRange);
       
  3319 
       
  3320 			return domRange;
       
  3321 		};
       
  3322 
       
  3323 		this.addRange = function(rng) {
       
  3324 			var ieRng, body = selection.dom.doc.body, startPos, endPos, sc, so, ec, eo;
       
  3325 
       
  3326 			// Setup some shorter versions
       
  3327 			sc = rng.startContainer;
       
  3328 			so = rng.startOffset;
       
  3329 			ec = rng.endContainer;
       
  3330 			eo = rng.endOffset;
       
  3331 			ieRng = body.createTextRange();
       
  3332 
       
  3333 			// Find element
       
  3334 			sc = sc.nodeType == 1 ? sc.childNodes[Math.min(so, sc.childNodes.length - 1)] : sc;
       
  3335 			ec = ec.nodeType == 1 ? ec.childNodes[Math.min(so == eo ? eo : eo - 1, ec.childNodes.length - 1)] : ec;
       
  3336 
       
  3337 			// Single element selection
       
  3338 			if (sc == ec && sc.nodeType == 1) {
       
  3339 				// Make control selection for some elements
       
  3340 				if (/^(IMG|TABLE)$/.test(sc.nodeName) && so != eo) {
       
  3341 					ieRng = body.createControlRange();
       
  3342 					ieRng.addElement(sc);
       
  3343 				} else {
       
  3344 					ieRng = body.createTextRange();
       
  3345 
       
  3346 					// Padd empty elements with invisible character
       
  3347 					if (!sc.hasChildNodes() && sc.canHaveHTML)
       
  3348 						sc.innerHTML = invisibleChar;
       
  3349 
       
  3350 					// Select element contents
       
  3351 					ieRng.moveToElementText(sc);
       
  3352 
       
  3353 					// If it's only containing a padding remove it so the caret remains
       
  3354 					if (sc.innerHTML == invisibleChar) {
       
  3355 						ieRng.collapse(true);
       
  3356 						sc.removeChild(sc.firstChild);
       
  3357 					}
       
  3358 				}
       
  3359 
       
  3360 				if (so == eo)
       
  3361 					ieRng.collapse(eo <= rng.endContainer.childNodes.length - 1);
       
  3362 
       
  3363 				ieRng.select();
       
  3364 
       
  3365 				return;
       
  3366 			}
       
  3367 
       
  3368 			function getCharPos(container, offset) {
       
  3369 				var nodeVal, rng, pos;
       
  3370 
       
  3371 				if (container.nodeType != 3)
       
  3372 					return -1;
       
  3373 
       
  3374 				nodeVal = container.nodeValue;
       
  3375 				rng = body.createTextRange();
       
  3376 
       
  3377 				// Insert marker at offset position
       
  3378 				container.nodeValue = nodeVal.substring(0, offset) + invisibleChar + nodeVal.substring(offset);
       
  3379 
       
  3380 				// Find char pos of marker and remove it
       
  3381 				rng.moveToElementText(container.parentNode);
       
  3382 				rng.findText(invisibleChar);
       
  3383 				pos = Math.abs(rng.moveStart('character', -0xFFFFF));
       
  3384 				container.nodeValue = nodeVal;
       
  3385 
       
  3386 				return pos;
       
  3387 			};
       
  3388 
       
  3389 			// Collapsed range
       
  3390 			if (rng.collapsed) {
       
  3391 				pos = getCharPos(sc, so);
       
  3392 
       
  3393 				ieRng = body.createTextRange();
       
  3394 				ieRng.move('character', pos);
       
  3395 				ieRng.select();
       
  3396 
       
  3397 				return;
       
  3398 			} else {
       
  3399 				// If same text container
       
  3400 				if (sc == ec && sc.nodeType == 3) {
       
  3401 					startPos = getCharPos(sc, so);
       
  3402 
       
  3403 					ieRng = body.createTextRange();
       
  3404 					ieRng.move('character', startPos);
       
  3405 					ieRng.moveEnd('character', eo - so);
       
  3406 					ieRng.select();
       
  3407 
       
  3408 					return;
       
  3409 				}
       
  3410 
       
  3411 				// Get caret positions
       
  3412 				startPos = getCharPos(sc, so);
       
  3413 				endPos = getCharPos(ec, eo);
       
  3414 				ieRng = body.createTextRange();
       
  3415 
       
  3416 				// Move start of range to start character position or start element
       
  3417 				if (startPos == -1) {
       
  3418 					ieRng.moveToElementText(sc);
       
  3419 					startPos = 0;
       
  3420 				} else
       
  3421 					ieRng.move('character', startPos);
       
  3422 
       
  3423 				// Move end of range to end character position or end element
       
  3424 				tmpRng = body.createTextRange();
       
  3425 
       
  3426 				if (endPos == -1)
       
  3427 					tmpRng.moveToElementText(ec);
       
  3428 				else
       
  3429 					tmpRng.move('character', endPos);
       
  3430 
       
  3431 				ieRng.setEndPoint('EndToEnd', tmpRng);
       
  3432 				ieRng.select();
       
  3433 
       
  3434 				return;
       
  3435 			}
       
  3436 		};
       
  3437 
       
  3438 		this.getRangeAt = function() {
       
  3439 			// Setup new range if the cache is empty
       
  3440 			if (!range || !compareRanges(lastIERng, selection.getRng())) {
       
  3441 				range = getRange();
       
  3442 
       
  3443 				// Store away text range for next call
       
  3444 				lastIERng = selection.getRng();
       
  3445 			}
       
  3446 
       
  3447 			// Return cached range
       
  3448 			return range;
       
  3449 		};
       
  3450 
       
  3451 		this.destroy = function() {
       
  3452 			// Destroy cached range and last IE range to avoid memory leaks
       
  3453 			lastIERng = range = null;
       
  3454 		};
       
  3455 	};
       
  3456 
       
  3457 	// Expose the selection object
       
  3458 	tinymce.dom.TridentSelection = Selection;
       
  3459 })();
       
  3460 
       
  3461 /*
       
  3462  * Sizzle CSS Selector Engine - v1.0
       
  3463  *  Copyright 2009, The Dojo Foundation
       
  3464  *  Released under the MIT, BSD, and GPL Licenses.
       
  3465  *  More information: http://sizzlejs.com/
       
  3466  */
       
  3467 (function(){
       
  3468 
       
  3469 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
       
  3470 	done = 0,
       
  3471 	toString = Object.prototype.toString,
       
  3472 	hasDuplicate = false;
       
  3473 
       
  3474 var Sizzle = function(selector, context, results, seed) {
       
  3475 	results = results || [];
       
  3476 	var origContext = context = context || document;
       
  3477 
       
  3478 	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
       
  3479 		return [];
       
  3480 	}
       
  3481 	
       
  3482 	if ( !selector || typeof selector !== "string" ) {
       
  3483 		return results;
       
  3484 	}
       
  3485 
       
  3486 	var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context);
       
  3487 	
       
  3488 	// Reset the position of the chunker regexp (start from head)
       
  3489 	chunker.lastIndex = 0;
       
  3490 	
       
  3491 	while ( (m = chunker.exec(selector)) !== null ) {
       
  3492 		parts.push( m[1] );
       
  3493 		
       
  3494 		if ( m[2] ) {
       
  3495 			extra = RegExp.rightContext;
       
  3496 			break;
       
  3497 		}
       
  3498 	}
       
  3499 
       
  3500 	if ( parts.length > 1 && origPOS.exec( selector ) ) {
       
  3501 		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
       
  3502 			set = posProcess( parts[0] + parts[1], context );
       
  3503 		} else {
       
  3504 			set = Expr.relative[ parts[0] ] ?
       
  3505 				[ context ] :
       
  3506 				Sizzle( parts.shift(), context );
       
  3507 
       
  3508 			while ( parts.length ) {
       
  3509 				selector = parts.shift();
       
  3510 
       
  3511 				if ( Expr.relative[ selector ] )
       
  3512 					selector += parts.shift();
       
  3513 
       
  3514 				set = posProcess( selector, set );
       
  3515 			}
       
  3516 		}
       
  3517 	} else {
       
  3518 		// Take a shortcut and set the context if the root selector is an ID
       
  3519 		// (but not if it'll be faster if the inner selector is an ID)
       
  3520 		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
       
  3521 				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
       
  3522 			var ret = Sizzle.find( parts.shift(), context, contextXML );
       
  3523 			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
       
  3524 		}
       
  3525 
       
  3526 		if ( context ) {
       
  3527 			var ret = seed ?
       
  3528 				{ expr: parts.pop(), set: makeArray(seed) } :
       
  3529 				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
       
  3530 			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
       
  3531 
       
  3532 			if ( parts.length > 0 ) {
       
  3533 				checkSet = makeArray(set);
       
  3534 			} else {
       
  3535 				prune = false;
       
  3536 			}
       
  3537 
       
  3538 			while ( parts.length ) {
       
  3539 				var cur = parts.pop(), pop = cur;
       
  3540 
       
  3541 				if ( !Expr.relative[ cur ] ) {
       
  3542 					cur = "";
       
  3543 				} else {
       
  3544 					pop = parts.pop();
       
  3545 				}
       
  3546 
       
  3547 				if ( pop == null ) {
       
  3548 					pop = context;
       
  3549 				}
       
  3550 
       
  3551 				Expr.relative[ cur ]( checkSet, pop, contextXML );
       
  3552 			}
       
  3553 		} else {
       
  3554 			checkSet = parts = [];
       
  3555 		}
       
  3556 	}
       
  3557 
       
  3558 	if ( !checkSet ) {
       
  3559 		checkSet = set;
       
  3560 	}
       
  3561 
       
  3562 	if ( !checkSet ) {
       
  3563 		throw "Syntax error, unrecognized expression: " + (cur || selector);
       
  3564 	}
       
  3565 
       
  3566 	if ( toString.call(checkSet) === "[object Array]" ) {
       
  3567 		if ( !prune ) {
       
  3568 			results.push.apply( results, checkSet );
       
  3569 		} else if ( context && context.nodeType === 1 ) {
       
  3570 			for ( var i = 0; checkSet[i] != null; i++ ) {
       
  3571 				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
       
  3572 					results.push( set[i] );
       
  3573 				}
       
  3574 			}
       
  3575 		} else {
       
  3576 			for ( var i = 0; checkSet[i] != null; i++ ) {
       
  3577 				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
       
  3578 					results.push( set[i] );
       
  3579 				}
       
  3580 			}
       
  3581 		}
       
  3582 	} else {
       
  3583 		makeArray( checkSet, results );
       
  3584 	}
       
  3585 
       
  3586 	if ( extra ) {
       
  3587 		Sizzle( extra, origContext, results, seed );
       
  3588 		Sizzle.uniqueSort( results );
       
  3589 	}
       
  3590 
       
  3591 	return results;
       
  3592 };
       
  3593 
       
  3594 Sizzle.uniqueSort = function(results){
       
  3595 	if ( sortOrder ) {
       
  3596 		hasDuplicate = false;
       
  3597 		results.sort(sortOrder);
       
  3598 
       
  3599 		if ( hasDuplicate ) {
       
  3600 			for ( var i = 1; i < results.length; i++ ) {
       
  3601 				if ( results[i] === results[i-1] ) {
       
  3602 					results.splice(i--, 1);
       
  3603 				}
       
  3604 			}
       
  3605 		}
       
  3606 	}
       
  3607 };
       
  3608 
       
  3609 Sizzle.matches = function(expr, set){
       
  3610 	return Sizzle(expr, null, null, set);
       
  3611 };
       
  3612 
       
  3613 Sizzle.find = function(expr, context, isXML){
       
  3614 	var set, match;
       
  3615 
       
  3616 	if ( !expr ) {
       
  3617 		return [];
       
  3618 	}
       
  3619 
       
  3620 	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
       
  3621 		var type = Expr.order[i], match;
       
  3622 		
       
  3623 		if ( (match = Expr.match[ type ].exec( expr )) ) {
       
  3624 			var left = RegExp.leftContext;
       
  3625 
       
  3626 			if ( left.substr( left.length - 1 ) !== "\\" ) {
       
  3627 				match[1] = (match[1] || "").replace(/\\/g, "");
       
  3628 				set = Expr.find[ type ]( match, context, isXML );
       
  3629 				if ( set != null ) {
       
  3630 					expr = expr.replace( Expr.match[ type ], "" );
       
  3631 					break;
       
  3632 				}
       
  3633 			}
       
  3634 		}
       
  3635 	}
       
  3636 
       
  3637 	if ( !set ) {
       
  3638 		set = context.getElementsByTagName("*");
       
  3639 	}
       
  3640 
       
  3641 	return {set: set, expr: expr};
       
  3642 };
       
  3643 
       
  3644 Sizzle.filter = function(expr, set, inplace, not){
       
  3645 	var old = expr, result = [], curLoop = set, match, anyFound,
       
  3646 		isXMLFilter = set && set[0] && isXML(set[0]);
       
  3647 
       
  3648 	while ( expr && set.length ) {
       
  3649 		for ( var type in Expr.filter ) {
       
  3650 			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
       
  3651 				var filter = Expr.filter[ type ], found, item;
       
  3652 				anyFound = false;
       
  3653 
       
  3654 				if ( curLoop == result ) {
       
  3655 					result = [];
       
  3656 				}
       
  3657 
       
  3658 				if ( Expr.preFilter[ type ] ) {
       
  3659 					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
       
  3660 
       
  3661 					if ( !match ) {
       
  3662 						anyFound = found = true;
       
  3663 					} else if ( match === true ) {
       
  3664 						continue;
       
  3665 					}
       
  3666 				}
       
  3667 
       
  3668 				if ( match ) {
       
  3669 					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
       
  3670 						if ( item ) {
       
  3671 							found = filter( item, match, i, curLoop );
       
  3672 							var pass = not ^ !!found;
       
  3673 
       
  3674 							if ( inplace && found != null ) {
       
  3675 								if ( pass ) {
       
  3676 									anyFound = true;
       
  3677 								} else {
       
  3678 									curLoop[i] = false;
       
  3679 								}
       
  3680 							} else if ( pass ) {
       
  3681 								result.push( item );
       
  3682 								anyFound = true;
       
  3683 							}
       
  3684 						}
       
  3685 					}
       
  3686 				}
       
  3687 
       
  3688 				if ( found !== undefined ) {
       
  3689 					if ( !inplace ) {
       
  3690 						curLoop = result;
       
  3691 					}
       
  3692 
       
  3693 					expr = expr.replace( Expr.match[ type ], "" );
       
  3694 
       
  3695 					if ( !anyFound ) {
       
  3696 						return [];
       
  3697 					}
       
  3698 
       
  3699 					break;
       
  3700 				}
       
  3701 			}
       
  3702 		}
       
  3703 
       
  3704 		// Improper expression
       
  3705 		if ( expr == old ) {
       
  3706 			if ( anyFound == null ) {
       
  3707 				throw "Syntax error, unrecognized expression: " + expr;
       
  3708 			} else {
       
  3709 				break;
       
  3710 			}
       
  3711 		}
       
  3712 
       
  3713 		old = expr;
       
  3714 	}
       
  3715 
       
  3716 	return curLoop;
       
  3717 };
       
  3718 
       
  3719 var Expr = Sizzle.selectors = {
       
  3720 	order: [ "ID", "NAME", "TAG" ],
       
  3721 	match: {
       
  3722 		ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
       
  3723 		CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
       
  3724 		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
       
  3725 		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
       
  3726 		TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
       
  3727 		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
       
  3728 		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
       
  3729 		PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
       
  3730 	},
       
  3731 	attrMap: {
       
  3732 		"class": "className",
       
  3733 		"for": "htmlFor"
       
  3734 	},
       
  3735 	attrHandle: {
       
  3736 		href: function(elem){
       
  3737 			return elem.getAttribute("href");
       
  3738 		}
       
  3739 	},
       
  3740 	relative: {
       
  3741 		"+": function(checkSet, part, isXML){
       
  3742 			var isPartStr = typeof part === "string",
       
  3743 				isTag = isPartStr && !/\W/.test(part),
       
  3744 				isPartStrNotTag = isPartStr && !isTag;
       
  3745 
       
  3746 			if ( isTag && !isXML ) {
       
  3747 				part = part.toUpperCase();
       
  3748 			}
       
  3749 
       
  3750 			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
       
  3751 				if ( (elem = checkSet[i]) ) {
       
  3752 					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
       
  3753 
       
  3754 					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
       
  3755 						elem || false :
       
  3756 						elem === part;
       
  3757 				}
       
  3758 			}
       
  3759 
       
  3760 			if ( isPartStrNotTag ) {
       
  3761 				Sizzle.filter( part, checkSet, true );
       
  3762 			}
       
  3763 		},
       
  3764 		">": function(checkSet, part, isXML){
       
  3765 			var isPartStr = typeof part === "string";
       
  3766 
       
  3767 			if ( isPartStr && !/\W/.test(part) ) {
       
  3768 				part = isXML ? part : part.toUpperCase();
       
  3769 
       
  3770 				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
       
  3771 					var elem = checkSet[i];
       
  3772 					if ( elem ) {
       
  3773 						var parent = elem.parentNode;
       
  3774 						checkSet[i] = parent.nodeName === part ? parent : false;
       
  3775 					}
       
  3776 				}
       
  3777 			} else {
       
  3778 				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
       
  3779 					var elem = checkSet[i];
       
  3780 					if ( elem ) {
       
  3781 						checkSet[i] = isPartStr ?
       
  3782 							elem.parentNode :
       
  3783 							elem.parentNode === part;
       
  3784 					}
       
  3785 				}
       
  3786 
       
  3787 				if ( isPartStr ) {
       
  3788 					Sizzle.filter( part, checkSet, true );
       
  3789 				}
       
  3790 			}
       
  3791 		},
       
  3792 		"": function(checkSet, part, isXML){
       
  3793 			var doneName = done++, checkFn = dirCheck;
       
  3794 
       
  3795 			if ( !part.match(/\W/) ) {
       
  3796 				var nodeCheck = part = isXML ? part : part.toUpperCase();
       
  3797 				checkFn = dirNodeCheck;
       
  3798 			}
       
  3799 
       
  3800 			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
       
  3801 		},
       
  3802 		"~": function(checkSet, part, isXML){
       
  3803 			var doneName = done++, checkFn = dirCheck;
       
  3804 
       
  3805 			if ( typeof part === "string" && !part.match(/\W/) ) {
       
  3806 				var nodeCheck = part = isXML ? part : part.toUpperCase();
       
  3807 				checkFn = dirNodeCheck;
       
  3808 			}
       
  3809 
       
  3810 			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
       
  3811 		}
       
  3812 	},
       
  3813 	find: {
       
  3814 		ID: function(match, context, isXML){
       
  3815 			if ( typeof context.getElementById !== "undefined" && !isXML ) {
       
  3816 				var m = context.getElementById(match[1]);
       
  3817 				return m ? [m] : [];
       
  3818 			}
       
  3819 		},
       
  3820 		NAME: function(match, context, isXML){
       
  3821 			if ( typeof context.getElementsByName !== "undefined" ) {
       
  3822 				var ret = [], results = context.getElementsByName(match[1]);
       
  3823 
       
  3824 				for ( var i = 0, l = results.length; i < l; i++ ) {
       
  3825 					if ( results[i].getAttribute("name") === match[1] ) {
       
  3826 						ret.push( results[i] );
       
  3827 					}
       
  3828 				}
       
  3829 
       
  3830 				return ret.length === 0 ? null : ret;
       
  3831 			}
       
  3832 		},
       
  3833 		TAG: function(match, context){
       
  3834 			return context.getElementsByTagName(match[1]);
       
  3835 		}
       
  3836 	},
       
  3837 	preFilter: {
       
  3838 		CLASS: function(match, curLoop, inplace, result, not, isXML){
       
  3839 			match = " " + match[1].replace(/\\/g, "") + " ";
       
  3840 
       
  3841 			if ( isXML ) {
       
  3842 				return match;
       
  3843 			}
       
  3844 
       
  3845 			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
       
  3846 				if ( elem ) {
       
  3847 					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
       
  3848 						if ( !inplace )
       
  3849 							result.push( elem );
       
  3850 					} else if ( inplace ) {
       
  3851 						curLoop[i] = false;
       
  3852 					}
       
  3853 				}
       
  3854 			}
       
  3855 
       
  3856 			return false;
       
  3857 		},
       
  3858 		ID: function(match){
       
  3859 			return match[1].replace(/\\/g, "");
       
  3860 		},
       
  3861 		TAG: function(match, curLoop){
       
  3862 			for ( var i = 0; curLoop[i] === false; i++ ){}
       
  3863 			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
       
  3864 		},
       
  3865 		CHILD: function(match){
       
  3866 			if ( match[1] == "nth" ) {
       
  3867 				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
       
  3868 				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
       
  3869 					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
       
  3870 					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
       
  3871 
       
  3872 				// calculate the numbers (first)n+(last) including if they are negative
       
  3873 				match[2] = (test[1] + (test[2] || 1)) - 0;
       
  3874 				match[3] = test[3] - 0;
       
  3875 			}
       
  3876 
       
  3877 			// TODO: Move to normal caching system
       
  3878 			match[0] = done++;
       
  3879 
       
  3880 			return match;
       
  3881 		},
       
  3882 		ATTR: function(match, curLoop, inplace, result, not, isXML){
       
  3883 			var name = match[1].replace(/\\/g, "");
       
  3884 			
       
  3885 			if ( !isXML && Expr.attrMap[name] ) {
       
  3886 				match[1] = Expr.attrMap[name];
       
  3887 			}
       
  3888 
       
  3889 			if ( match[2] === "~=" ) {
       
  3890 				match[4] = " " + match[4] + " ";
       
  3891 			}
       
  3892 
       
  3893 			return match;
       
  3894 		},
       
  3895 		PSEUDO: function(match, curLoop, inplace, result, not){
       
  3896 			if ( match[1] === "not" ) {
       
  3897 				// If we're dealing with a complex expression, or a simple one
       
  3898 				if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
       
  3899 					match[3] = Sizzle(match[3], null, null, curLoop);
       
  3900 				} else {
       
  3901 					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
       
  3902 					if ( !inplace ) {
       
  3903 						result.push.apply( result, ret );
       
  3904 					}
       
  3905 					return false;
       
  3906 				}
       
  3907 			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
       
  3908 				return true;
       
  3909 			}
       
  3910 			
       
  3911 			return match;
       
  3912 		},
       
  3913 		POS: function(match){
       
  3914 			match.unshift( true );
       
  3915 			return match;
       
  3916 		}
       
  3917 	},
       
  3918 	filters: {
       
  3919 		enabled: function(elem){
       
  3920 			return elem.disabled === false && elem.type !== "hidden";
       
  3921 		},
       
  3922 		disabled: function(elem){
       
  3923 			return elem.disabled === true;
       
  3924 		},
       
  3925 		checked: function(elem){
       
  3926 			return elem.checked === true;
       
  3927 		},
       
  3928 		selected: function(elem){
       
  3929 			// Accessing this property makes selected-by-default
       
  3930 			// options in Safari work properly
       
  3931 			elem.parentNode.selectedIndex;
       
  3932 			return elem.selected === true;
       
  3933 		},
       
  3934 		parent: function(elem){
       
  3935 			return !!elem.firstChild;
       
  3936 		},
       
  3937 		empty: function(elem){
       
  3938 			return !elem.firstChild;
       
  3939 		},
       
  3940 		has: function(elem, i, match){
       
  3941 			return !!Sizzle( match[3], elem ).length;
       
  3942 		},
       
  3943 		header: function(elem){
       
  3944 			return /h\d/i.test( elem.nodeName );
       
  3945 		},
       
  3946 		text: function(elem){
       
  3947 			return "text" === elem.type;
       
  3948 		},
       
  3949 		radio: function(elem){
       
  3950 			return "radio" === elem.type;
       
  3951 		},
       
  3952 		checkbox: function(elem){
       
  3953 			return "checkbox" === elem.type;
       
  3954 		},
       
  3955 		file: function(elem){
       
  3956 			return "file" === elem.type;
       
  3957 		},
       
  3958 		password: function(elem){
       
  3959 			return "password" === elem.type;
       
  3960 		},
       
  3961 		submit: function(elem){
       
  3962 			return "submit" === elem.type;
       
  3963 		},
       
  3964 		image: function(elem){
       
  3965 			return "image" === elem.type;
       
  3966 		},
       
  3967 		reset: function(elem){
       
  3968 			return "reset" === elem.type;
       
  3969 		},
       
  3970 		button: function(elem){
       
  3971 			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
       
  3972 		},
       
  3973 		input: function(elem){
       
  3974 			return /input|select|textarea|button/i.test(elem.nodeName);
       
  3975 		}
       
  3976 	},
       
  3977 	setFilters: {
       
  3978 		first: function(elem, i){
       
  3979 			return i === 0;
       
  3980 		},
       
  3981 		last: function(elem, i, match, array){
       
  3982 			return i === array.length - 1;
       
  3983 		},
       
  3984 		even: function(elem, i){
       
  3985 			return i % 2 === 0;
       
  3986 		},
       
  3987 		odd: function(elem, i){
       
  3988 			return i % 2 === 1;
       
  3989 		},
       
  3990 		lt: function(elem, i, match){
       
  3991 			return i < match[3] - 0;
       
  3992 		},
       
  3993 		gt: function(elem, i, match){
       
  3994 			return i > match[3] - 0;
       
  3995 		},
       
  3996 		nth: function(elem, i, match){
       
  3997 			return match[3] - 0 == i;
       
  3998 		},
       
  3999 		eq: function(elem, i, match){
       
  4000 			return match[3] - 0 == i;
       
  4001 		}
       
  4002 	},
       
  4003 	filter: {
       
  4004 		PSEUDO: function(elem, match, i, array){
       
  4005 			var name = match[1], filter = Expr.filters[ name ];
       
  4006 
       
  4007 			if ( filter ) {
       
  4008 				return filter( elem, i, match, array );
       
  4009 			} else if ( name === "contains" ) {
       
  4010 				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
       
  4011 			} else if ( name === "not" ) {
       
  4012 				var not = match[3];
       
  4013 
       
  4014 				for ( var i = 0, l = not.length; i < l; i++ ) {
       
  4015 					if ( not[i] === elem ) {
       
  4016 						return false;
       
  4017 					}
       
  4018 				}
       
  4019 
       
  4020 				return true;
       
  4021 			}
       
  4022 		},
       
  4023 		CHILD: function(elem, match){
       
  4024 			var type = match[1], node = elem;
       
  4025 			switch (type) {
       
  4026 				case 'only':
       
  4027 				case 'first':
       
  4028 					while (node = node.previousSibling)  {
       
  4029 						if ( node.nodeType === 1 ) return false;
       
  4030 					}
       
  4031 					if ( type == 'first') return true;
       
  4032 					node = elem;
       
  4033 				case 'last':
       
  4034 					while (node = node.nextSibling)  {
       
  4035 						if ( node.nodeType === 1 ) return false;
       
  4036 					}
       
  4037 					return true;
       
  4038 				case 'nth':
       
  4039 					var first = match[2], last = match[3];
       
  4040 
       
  4041 					if ( first == 1 && last == 0 ) {
       
  4042 						return true;
       
  4043 					}
       
  4044 					
       
  4045 					var doneName = match[0],
       
  4046 						parent = elem.parentNode;
       
  4047 	
       
  4048 					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
       
  4049 						var count = 0;
       
  4050 						for ( node = parent.firstChild; node; node = node.nextSibling ) {
       
  4051 							if ( node.nodeType === 1 ) {
       
  4052 								node.nodeIndex = ++count;
       
  4053 							}
       
  4054 						} 
       
  4055 						parent.sizcache = doneName;
       
  4056 					}
       
  4057 					
       
  4058 					var diff = elem.nodeIndex - last;
       
  4059 					if ( first == 0 ) {
       
  4060 						return diff == 0;
       
  4061 					} else {
       
  4062 						return ( diff % first == 0 && diff / first >= 0 );
       
  4063 					}
       
  4064 			}
       
  4065 		},
       
  4066 		ID: function(elem, match){
       
  4067 			return elem.nodeType === 1 && elem.getAttribute("id") === match;
       
  4068 		},
       
  4069 		TAG: function(elem, match){
       
  4070 			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
       
  4071 		},
       
  4072 		CLASS: function(elem, match){
       
  4073 			return (" " + (elem.className || elem.getAttribute("class")) + " ")
       
  4074 				.indexOf( match ) > -1;
       
  4075 		},
       
  4076 		ATTR: function(elem, match){
       
  4077 			var name = match[1],
       
  4078 				result = Expr.attrHandle[ name ] ?
       
  4079 					Expr.attrHandle[ name ]( elem ) :
       
  4080 					elem[ name ] != null ?
       
  4081 						elem[ name ] :
       
  4082 						elem.getAttribute( name ),
       
  4083 				value = result + "",
       
  4084 				type = match[2],
       
  4085 				check = match[4];
       
  4086 
       
  4087 			return result == null ?
       
  4088 				type === "!=" :
       
  4089 				type === "=" ?
       
  4090 				value === check :
       
  4091 				type === "*=" ?
       
  4092 				value.indexOf(check) >= 0 :
       
  4093 				type === "~=" ?
       
  4094 				(" " + value + " ").indexOf(check) >= 0 :
       
  4095 				!check ?
       
  4096 				value && result !== false :
       
  4097 				type === "!=" ?
       
  4098 				value != check :
       
  4099 				type === "^=" ?
       
  4100 				value.indexOf(check) === 0 :
       
  4101 				type === "$=" ?
       
  4102 				value.substr(value.length - check.length) === check :
       
  4103 				type === "|=" ?
       
  4104 				value === check || value.substr(0, check.length + 1) === check + "-" :
       
  4105 				false;
       
  4106 		},
       
  4107 		POS: function(elem, match, i, array){
       
  4108 			var name = match[2], filter = Expr.setFilters[ name ];
       
  4109 
       
  4110 			if ( filter ) {
       
  4111 				return filter( elem, i, match, array );
       
  4112 			}
       
  4113 		}
       
  4114 	}
       
  4115 };
       
  4116 
       
  4117 var origPOS = Expr.match.POS;
       
  4118 
       
  4119 for ( var type in Expr.match ) {
       
  4120 	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
       
  4121 }
       
  4122 
       
  4123 var makeArray = function(array, results) {
       
  4124 	array = Array.prototype.slice.call( array );
       
  4125 
       
  4126 	if ( results ) {
       
  4127 		results.push.apply( results, array );
       
  4128 		return results;
       
  4129 	}
       
  4130 	
       
  4131 	return array;
       
  4132 };
       
  4133 
       
  4134 // Perform a simple check to determine if the browser is capable of
       
  4135 // converting a NodeList to an array using builtin methods.
       
  4136 try {
       
  4137 	Array.prototype.slice.call( document.documentElement.childNodes );
       
  4138 
       
  4139 // Provide a fallback method if it does not work
       
  4140 } catch(e){
       
  4141 	makeArray = function(array, results) {
       
  4142 		var ret = results || [];
       
  4143 
       
  4144 		if ( toString.call(array) === "[object Array]" ) {
       
  4145 			Array.prototype.push.apply( ret, array );
       
  4146 		} else {
       
  4147 			if ( typeof array.length === "number" ) {
       
  4148 				for ( var i = 0, l = array.length; i < l; i++ ) {
       
  4149 					ret.push( array[i] );
       
  4150 				}
       
  4151 			} else {
       
  4152 				for ( var i = 0; array[i]; i++ ) {
       
  4153 					ret.push( array[i] );
       
  4154 				}
       
  4155 			}
       
  4156 		}
       
  4157 
       
  4158 		return ret;
       
  4159 	};
       
  4160 }
       
  4161 
       
  4162 var sortOrder;
       
  4163 
       
  4164 if ( document.documentElement.compareDocumentPosition ) {
       
  4165 	sortOrder = function( a, b ) {
       
  4166 		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
       
  4167 		if ( ret === 0 ) {
       
  4168 			hasDuplicate = true;
       
  4169 		}
       
  4170 		return ret;
       
  4171 	};
       
  4172 } else if ( "sourceIndex" in document.documentElement ) {
       
  4173 	sortOrder = function( a, b ) {
       
  4174 		var ret = a.sourceIndex - b.sourceIndex;
       
  4175 		if ( ret === 0 ) {
       
  4176 			hasDuplicate = true;
       
  4177 		}
       
  4178 		return ret;
       
  4179 	};
       
  4180 } else if ( document.createRange ) {
       
  4181 	sortOrder = function( a, b ) {
       
  4182 		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
       
  4183 		aRange.setStart(a, 0);
       
  4184 		aRange.setEnd(a, 0);
       
  4185 		bRange.setStart(b, 0);
       
  4186 		bRange.setEnd(b, 0);
       
  4187 		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
       
  4188 		if ( ret === 0 ) {
       
  4189 			hasDuplicate = true;
       
  4190 		}
       
  4191 		return ret;
       
  4192 	};
       
  4193 }
       
  4194 
       
  4195 // Check to see if the browser returns elements by name when
       
  4196 // querying by getElementById (and provide a workaround)
       
  4197 (function(){
       
  4198 	// We're going to inject a fake input element with a specified name
       
  4199 	var form = document.createElement("div"),
       
  4200 		id = "script" + (new Date).getTime();
       
  4201 	form.innerHTML = "<a name='" + id + "'/>";
       
  4202 
       
  4203 	// Inject it into the root element, check its status, and remove it quickly
       
  4204 	var root = document.documentElement;
       
  4205 	root.insertBefore( form, root.firstChild );
       
  4206 
       
  4207 	// The workaround has to do additional checks after a getElementById
       
  4208 	// Which slows things down for other browsers (hence the branching)
       
  4209 	if ( !!document.getElementById( id ) ) {
       
  4210 		Expr.find.ID = function(match, context, isXML){
       
  4211 			if ( typeof context.getElementById !== "undefined" && !isXML ) {
       
  4212 				var m = context.getElementById(match[1]);
       
  4213 				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
       
  4214 			}
       
  4215 		};
       
  4216 
       
  4217 		Expr.filter.ID = function(elem, match){
       
  4218 			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
       
  4219 			return elem.nodeType === 1 && node && node.nodeValue === match;
       
  4220 		};
       
  4221 	}
       
  4222 
       
  4223 	root.removeChild( form );
       
  4224 })();
       
  4225 
       
  4226 (function(){
       
  4227 	// Check to see if the browser returns only elements
       
  4228 	// when doing getElementsByTagName("*")
       
  4229 
       
  4230 	// Create a fake element
       
  4231 	var div = document.createElement("div");
       
  4232 	div.appendChild( document.createComment("") );
       
  4233 
       
  4234 	// Make sure no comments are found
       
  4235 	if ( div.getElementsByTagName("*").length > 0 ) {
       
  4236 		Expr.find.TAG = function(match, context){
       
  4237 			var results = context.getElementsByTagName(match[1]);
       
  4238 
       
  4239 			// Filter out possible comments
       
  4240 			if ( match[1] === "*" ) {
       
  4241 				var tmp = [];
       
  4242 
       
  4243 				for ( var i = 0; results[i]; i++ ) {
       
  4244 					if ( results[i].nodeType === 1 ) {
       
  4245 						tmp.push( results[i] );
       
  4246 					}
       
  4247 				}
       
  4248 
       
  4249 				results = tmp;
       
  4250 			}
       
  4251 
       
  4252 			return results;
       
  4253 		};
       
  4254 	}
       
  4255 
       
  4256 	// Check to see if an attribute returns normalized href attributes
       
  4257 	div.innerHTML = "<a href='#'></a>";
       
  4258 	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
       
  4259 			div.firstChild.getAttribute("href") !== "#" ) {
       
  4260 		Expr.attrHandle.href = function(elem){
       
  4261 			return elem.getAttribute("href", 2);
       
  4262 		};
       
  4263 	}
       
  4264 })();
       
  4265 
       
  4266 if ( document.querySelectorAll ) (function(){
       
  4267 	var oldSizzle = Sizzle, div = document.createElement("div");
       
  4268 	div.innerHTML = "<p class='TEST'></p>";
       
  4269 
       
  4270 	// Safari can't handle uppercase or unicode characters when
       
  4271 	// in quirks mode.
       
  4272 	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
       
  4273 		return;
       
  4274 	}
       
  4275 	
       
  4276 	Sizzle = function(query, context, extra, seed){
       
  4277 		context = context || document;
       
  4278 
       
  4279 		// Only use querySelectorAll on non-XML documents
       
  4280 		// (ID selectors don't work in non-HTML documents)
       
  4281 		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
       
  4282 			try {
       
  4283 				return makeArray( context.querySelectorAll(query), extra );
       
  4284 			} catch(e){}
       
  4285 		}
       
  4286 		
       
  4287 		return oldSizzle(query, context, extra, seed);
       
  4288 	};
       
  4289 
       
  4290 	for ( var prop in oldSizzle ) {
       
  4291 		Sizzle[ prop ] = oldSizzle[ prop ];
       
  4292 	}
       
  4293 })();
       
  4294 
       
  4295 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
       
  4296 	var div = document.createElement("div");
       
  4297 	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
       
  4298 
       
  4299 	// Opera can't find a second classname (in 9.6)
       
  4300 	if ( div.getElementsByClassName("e").length === 0 )
       
  4301 		return;
       
  4302 
       
  4303 	// Safari caches class attributes, doesn't catch changes (in 3.2)
       
  4304 	div.lastChild.className = "e";
       
  4305 
       
  4306 	if ( div.getElementsByClassName("e").length === 1 )
       
  4307 		return;
       
  4308 
       
  4309 	Expr.order.splice(1, 0, "CLASS");
       
  4310 	Expr.find.CLASS = function(match, context, isXML) {
       
  4311 		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
       
  4312 			return context.getElementsByClassName(match[1]);
       
  4313 		}
       
  4314 	};
       
  4315 })();
       
  4316 
       
  4317 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
       
  4318 	var sibDir = dir == "previousSibling" && !isXML;
       
  4319 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
       
  4320 		var elem = checkSet[i];
       
  4321 		if ( elem ) {
       
  4322 			if ( sibDir && elem.nodeType === 1 ){
       
  4323 				elem.sizcache = doneName;
       
  4324 				elem.sizset = i;
       
  4325 			}
       
  4326 			elem = elem[dir];
       
  4327 			var match = false;
       
  4328 
       
  4329 			while ( elem ) {
       
  4330 				if ( elem.sizcache === doneName ) {
       
  4331 					match = checkSet[elem.sizset];
       
  4332 					break;
       
  4333 				}
       
  4334 
       
  4335 				if ( elem.nodeType === 1 && !isXML ){
       
  4336 					elem.sizcache = doneName;
       
  4337 					elem.sizset = i;
       
  4338 				}
       
  4339 
       
  4340 				if ( elem.nodeName === cur ) {
       
  4341 					match = elem;
       
  4342 					break;
       
  4343 				}
       
  4344 
       
  4345 				elem = elem[dir];
       
  4346 			}
       
  4347 
       
  4348 			checkSet[i] = match;
       
  4349 		}
       
  4350 	}
       
  4351 }
       
  4352 
       
  4353 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
       
  4354 	var sibDir = dir == "previousSibling" && !isXML;
       
  4355 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
       
  4356 		var elem = checkSet[i];
       
  4357 		if ( elem ) {
       
  4358 			if ( sibDir && elem.nodeType === 1 ) {
       
  4359 				elem.sizcache = doneName;
       
  4360 				elem.sizset = i;
       
  4361 			}
       
  4362 			elem = elem[dir];
       
  4363 			var match = false;
       
  4364 
       
  4365 			while ( elem ) {
       
  4366 				if ( elem.sizcache === doneName ) {
       
  4367 					match = checkSet[elem.sizset];
       
  4368 					break;
       
  4369 				}
       
  4370 
       
  4371 				if ( elem.nodeType === 1 ) {
       
  4372 					if ( !isXML ) {
       
  4373 						elem.sizcache = doneName;
       
  4374 						elem.sizset = i;
       
  4375 					}
       
  4376 					if ( typeof cur !== "string" ) {
       
  4377 						if ( elem === cur ) {
       
  4378 							match = true;
       
  4379 							break;
       
  4380 						}
       
  4381 
       
  4382 					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
       
  4383 						match = elem;
       
  4384 						break;
       
  4385 					}
       
  4386 				}
       
  4387 
       
  4388 				elem = elem[dir];
       
  4389 			}
       
  4390 
       
  4391 			checkSet[i] = match;
       
  4392 		}
       
  4393 	}
       
  4394 }
       
  4395 
       
  4396 var contains = document.compareDocumentPosition ?  function(a, b){
       
  4397 	return a.compareDocumentPosition(b) & 16;
       
  4398 } : function(a, b){
       
  4399 	return a !== b && (a.contains ? a.contains(b) : true);
       
  4400 };
       
  4401 
       
  4402 var isXML = function(elem){
       
  4403 	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
       
  4404 		!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
       
  4405 };
       
  4406 
       
  4407 var posProcess = function(selector, context){
       
  4408 	var tmpSet = [], later = "", match,
       
  4409 		root = context.nodeType ? [context] : context;
       
  4410 
       
  4411 	// Position selectors must be done after the filter
       
  4412 	// And so must :not(positional) so we move all PSEUDOs to the end
       
  4413 	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
       
  4414 		later += match[0];
       
  4415 		selector = selector.replace( Expr.match.PSEUDO, "" );
       
  4416 	}
       
  4417 
       
  4418 	selector = Expr.relative[selector] ? selector + "*" : selector;
       
  4419 
       
  4420 	for ( var i = 0, l = root.length; i < l; i++ ) {
       
  4421 		Sizzle( selector, root[i], tmpSet );
       
  4422 	}
       
  4423 
       
  4424 	return Sizzle.filter( later, tmpSet );
       
  4425 };
       
  4426 
       
  4427 // EXPOSE
       
  4428 
       
  4429 window.tinymce.dom.Sizzle = Sizzle;
       
  4430 
       
  4431 })();
       
  4432 
       
  4433 (function(tinymce) {
       
  4434 	// Shorten names
       
  4435 	var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
       
  4436 
       
  4437 	tinymce.create('tinymce.dom.EventUtils', {
       
  4438 		EventUtils : function() {
       
  4439 			this.inits = [];
       
  4440 			this.events = [];
       
  4441 		},
       
  4442 
       
  4443 		add : function(o, n, f, s) {
       
  4444 			var cb, t = this, el = t.events, r;
       
  4445 
       
  4446 			if (n instanceof Array) {
       
  4447 				r = [];
       
  4448 
       
  4449 				each(n, function(n) {
       
  4450 					r.push(t.add(o, n, f, s));
       
  4451 				});
       
  4452 
       
  4453 				return r;
       
  4454 			}
       
  4455 
       
  4456 			// Handle array
       
  4457 			if (o && o.hasOwnProperty && o instanceof Array) {
       
  4458 				r = [];
       
  4459 
       
  4460 				each(o, function(o) {
       
  4461 					o = DOM.get(o);
       
  4462 					r.push(t.add(o, n, f, s));
       
  4463 				});
       
  4464 
       
  4465 				return r;
       
  4466 			}
       
  4467 
       
  4468 			o = DOM.get(o);
       
  4469 
       
  4470 			if (!o)
       
  4471 				return;
       
  4472 
       
  4473 			// Setup event callback
       
  4474 			cb = function(e) {
       
  4475 				// Is all events disabled
       
  4476 				if (t.disabled)
       
  4477 					return;
       
  4478 
       
  4479 				e = e || window.event;
       
  4480 
       
  4481 				// Patch in target, preventDefault and stopPropagation in IE it's W3C valid
       
  4482 				if (e && isIE) {
       
  4483 					if (!e.target)
       
  4484 						e.target = e.srcElement;
       
  4485 
       
  4486 					// Patch in preventDefault, stopPropagation methods for W3C compatibility
       
  4487 					tinymce.extend(e, t._stoppers);
       
  4488 				}
       
  4489 
       
  4490 				if (!s)
       
  4491 					return f(e);
       
  4492 
       
  4493 				return f.call(s, e);
       
  4494 			};
       
  4495 
       
  4496 			if (n == 'unload') {
       
  4497 				tinymce.unloads.unshift({func : cb});
       
  4498 				return cb;
       
  4499 			}
       
  4500 
       
  4501 			if (n == 'init') {
       
  4502 				if (t.domLoaded)
       
  4503 					cb();
       
  4504 				else
       
  4505 					t.inits.push(cb);
       
  4506 
       
  4507 				return cb;
       
  4508 			}
       
  4509 
       
  4510 			// Store away listener reference
       
  4511 			el.push({
       
  4512 				obj : o,
       
  4513 				name : n,
       
  4514 				func : f,
       
  4515 				cfunc : cb,
       
  4516 				scope : s
       
  4517 			});
       
  4518 
       
  4519 			t._add(o, n, cb);
       
  4520 
       
  4521 			return f;
       
  4522 		},
       
  4523 
       
  4524 		remove : function(o, n, f) {
       
  4525 			var t = this, a = t.events, s = false, r;
       
  4526 
       
  4527 			// Handle array
       
  4528 			if (o && o.hasOwnProperty && o instanceof Array) {
       
  4529 				r = [];
       
  4530 
       
  4531 				each(o, function(o) {
       
  4532 					o = DOM.get(o);
       
  4533 					r.push(t.remove(o, n, f));
       
  4534 				});
       
  4535 
       
  4536 				return r;
       
  4537 			}
       
  4538 
       
  4539 			o = DOM.get(o);
       
  4540 
       
  4541 			each(a, function(e, i) {
       
  4542 				if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
       
  4543 					a.splice(i, 1);
       
  4544 					t._remove(o, n, e.cfunc);
       
  4545 					s = true;
       
  4546 					return false;
       
  4547 				}
       
  4548 			});
       
  4549 
       
  4550 			return s;
       
  4551 		},
       
  4552 
       
  4553 		clear : function(o) {
       
  4554 			var t = this, a = t.events, i, e;
       
  4555 
       
  4556 			if (o) {
       
  4557 				o = DOM.get(o);
       
  4558 
       
  4559 				for (i = a.length - 1; i >= 0; i--) {
       
  4560 					e = a[i];
       
  4561 
       
  4562 					if (e.obj === o) {
       
  4563 						t._remove(e.obj, e.name, e.cfunc);
       
  4564 						e.obj = e.cfunc = null;
       
  4565 						a.splice(i, 1);
       
  4566 					}
       
  4567 				}
       
  4568 			}
       
  4569 		},
       
  4570 
       
  4571 		cancel : function(e) {
       
  4572 			if (!e)
       
  4573 				return false;
       
  4574 
       
  4575 			this.stop(e);
       
  4576 
       
  4577 			return this.prevent(e);
       
  4578 		},
       
  4579 
       
  4580 		stop : function(e) {
       
  4581 			if (e.stopPropagation)
       
  4582 				e.stopPropagation();
       
  4583 			else
       
  4584 				e.cancelBubble = true;
       
  4585 
       
  4586 			return false;
       
  4587 		},
       
  4588 
       
  4589 		prevent : function(e) {
       
  4590 			if (e.preventDefault)
       
  4591 				e.preventDefault();
       
  4592 			else
       
  4593 				e.returnValue = false;
       
  4594 
       
  4595 			return false;
       
  4596 		},
       
  4597 
       
  4598 		destroy : function() {
       
  4599 			var t = this;
       
  4600 
       
  4601 			each(t.events, function(e, i) {
       
  4602 				t._remove(e.obj, e.name, e.cfunc);
       
  4603 				e.obj = e.cfunc = null;
       
  4604 			});
       
  4605 
       
  4606 			t.events = [];
       
  4607 			t = null;
       
  4608 		},
       
  4609 
       
  4610 		_add : function(o, n, f) {
       
  4611 			if (o.attachEvent)
       
  4612 				o.attachEvent('on' + n, f);
       
  4613 			else if (o.addEventListener)
       
  4614 				o.addEventListener(n, f, false);
       
  4615 			else
       
  4616 				o['on' + n] = f;
       
  4617 		},
       
  4618 
       
  4619 		_remove : function(o, n, f) {
       
  4620 			if (o) {
       
  4621 				try {
       
  4622 					if (o.detachEvent)
       
  4623 						o.detachEvent('on' + n, f);
       
  4624 					else if (o.removeEventListener)
       
  4625 						o.removeEventListener(n, f, false);
       
  4626 					else
       
  4627 						o['on' + n] = null;
       
  4628 				} catch (ex) {
       
  4629 					// Might fail with permission denined on IE so we just ignore that
       
  4630 				}
       
  4631 			}
       
  4632 		},
       
  4633 
       
  4634 		_pageInit : function(win) {
       
  4635 			var t = this;
       
  4636 
       
  4637 			// Keep it from running more than once
       
  4638 			if (t.domLoaded)
       
  4639 				return;
       
  4640 
       
  4641 			t.domLoaded = true;
       
  4642 
       
  4643 			each(t.inits, function(c) {
       
  4644 				c();
       
  4645 			});
       
  4646 
       
  4647 			t.inits = [];
       
  4648 		},
       
  4649 
       
  4650 		_wait : function(win) {
       
  4651 			var t = this, doc = win.document;
       
  4652 
       
  4653 			// No need since the document is already loaded
       
  4654 			if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) {
       
  4655 				t.domLoaded = 1;
       
  4656 				return;
       
  4657 			}
       
  4658 
       
  4659 			// Use IE method
       
  4660 			if (doc.attachEvent) {
       
  4661 				doc.attachEvent("onreadystatechange", function() {
       
  4662 					if (doc.readyState === "complete") {
       
  4663 						doc.detachEvent("onreadystatechange", arguments.callee);
       
  4664 						t._pageInit(win);
       
  4665 					}
       
  4666 				});
       
  4667 
       
  4668 				if (doc.documentElement.doScroll && win == win.top) {
       
  4669 					(function() {
       
  4670 						if (t.domLoaded)
       
  4671 							return;
       
  4672 
       
  4673 						try {
       
  4674 							// If IE is used, use the trick by Diego Perini
       
  4675 							// http://javascript.nwbox.com/IEContentLoaded/
       
  4676 							doc.documentElement.doScroll("left");
       
  4677 						} catch (ex) {
       
  4678 							setTimeout(arguments.callee, 0);
       
  4679 							return;
       
  4680 						}
       
  4681 
       
  4682 						t._pageInit(win);
       
  4683 					})();
       
  4684 				}
       
  4685 			} else if (doc.addEventListener) {
       
  4686 				t._add(win, 'DOMContentLoaded', function() {
       
  4687 					t._pageInit(win);
       
  4688 				});
       
  4689 			}
       
  4690 
       
  4691 			t._add(win, 'load', function() {
       
  4692 				t._pageInit(win);
       
  4693 			});
       
  4694 		},
       
  4695 
       
  4696 		_stoppers : {
       
  4697 			preventDefault :  function() {
       
  4698 				this.returnValue = false;
       
  4699 			},
       
  4700 
       
  4701 			stopPropagation : function() {
       
  4702 				this.cancelBubble = true;
       
  4703 			}
       
  4704 		}
       
  4705 	});
       
  4706 
       
  4707 	Event = tinymce.dom.Event = new tinymce.dom.EventUtils();
       
  4708 
       
  4709 	// Dispatch DOM content loaded event for IE and Safari
       
  4710 	Event._wait(window);
       
  4711 
       
  4712 	tinymce.addUnload(function() {
       
  4713 		Event.destroy();
       
  4714 	});
       
  4715 })(tinymce);
       
  4716 (function(tinymce) {
       
  4717 	var each = tinymce.each;
       
  4718 
       
  4719 	tinymce.create('tinymce.dom.Element', {
       
  4720 		Element : function(id, s) {
       
  4721 			var t = this, dom, el;
       
  4722 
       
  4723 			s = s || {};
       
  4724 			t.id = id;
       
  4725 			t.dom = dom = s.dom || tinymce.DOM;
       
  4726 			t.settings = s;
       
  4727 
       
  4728 			// Only IE leaks DOM references, this is a lot faster
       
  4729 			if (!tinymce.isIE)
       
  4730 				el = t.dom.get(t.id);
       
  4731 
       
  4732 			each([
       
  4733 				'getPos',
       
  4734 				'getRect',
       
  4735 				'getParent',
       
  4736 				'add',
       
  4737 				'setStyle',
       
  4738 				'getStyle',
       
  4739 				'setStyles',
       
  4740 				'setAttrib',
       
  4741 				'setAttribs',
       
  4742 				'getAttrib',
       
  4743 				'addClass',
       
  4744 				'removeClass',
       
  4745 				'hasClass',
       
  4746 				'getOuterHTML',
       
  4747 				'setOuterHTML',
       
  4748 				'remove',
       
  4749 				'show',
       
  4750 				'hide',
       
  4751 				'isHidden',
       
  4752 				'setHTML',
       
  4753 				'get'
       
  4754 			], function(k) {
       
  4755 				t[k] = function() {
       
  4756 					var a = [id], i;
       
  4757 
       
  4758 					for (i = 0; i < arguments.length; i++)
       
  4759 						a.push(arguments[i]);
       
  4760 
       
  4761 					a = dom[k].apply(dom, a);
       
  4762 					t.update(k);
       
  4763 
       
  4764 					return a;
       
  4765 				};
       
  4766 			});
       
  4767 		},
       
  4768 
       
  4769 		on : function(n, f, s) {
       
  4770 			return tinymce.dom.Event.add(this.id, n, f, s);
       
  4771 		},
       
  4772 
       
  4773 		getXY : function() {
       
  4774 			return {
       
  4775 				x : parseInt(this.getStyle('left')),
       
  4776 				y : parseInt(this.getStyle('top'))
       
  4777 			};
       
  4778 		},
       
  4779 
       
  4780 		getSize : function() {
       
  4781 			var n = this.dom.get(this.id);
       
  4782 
       
  4783 			return {
       
  4784 				w : parseInt(this.getStyle('width') || n.clientWidth),
       
  4785 				h : parseInt(this.getStyle('height') || n.clientHeight)
       
  4786 			};
       
  4787 		},
       
  4788 
       
  4789 		moveTo : function(x, y) {
       
  4790 			this.setStyles({left : x, top : y});
       
  4791 		},
       
  4792 
       
  4793 		moveBy : function(x, y) {
       
  4794 			var p = this.getXY();
       
  4795 
       
  4796 			this.moveTo(p.x + x, p.y + y);
       
  4797 		},
       
  4798 
       
  4799 		resizeTo : function(w, h) {
       
  4800 			this.setStyles({width : w, height : h});
       
  4801 		},
       
  4802 
       
  4803 		resizeBy : function(w, h) {
       
  4804 			var s = this.getSize();
       
  4805 
       
  4806 			this.resizeTo(s.w + w, s.h + h);
       
  4807 		},
       
  4808 
       
  4809 		update : function(k) {
       
  4810 			var t = this, b, dom = t.dom;
       
  4811 
       
  4812 			if (tinymce.isIE6 && t.settings.blocker) {
       
  4813 				k = k || '';
       
  4814 
       
  4815 				// Ignore getters
       
  4816 				if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)
       
  4817 					return;
       
  4818 
       
  4819 				// Remove blocker on remove
       
  4820 				if (k == 'remove') {
       
  4821 					dom.remove(t.blocker);
       
  4822 					return;
       
  4823 				}
       
  4824 
       
  4825 				if (!t.blocker) {
       
  4826 					t.blocker = dom.uniqueId();
       
  4827 					b = dom.add(t.settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});
       
  4828 					dom.setStyle(b, 'opacity', 0);
       
  4829 				} else
       
  4830 					b = dom.get(t.blocker);
       
  4831 
       
  4832 				dom.setStyle(b, 'left', t.getStyle('left', 1));
       
  4833 				dom.setStyle(b, 'top', t.getStyle('top', 1));
       
  4834 				dom.setStyle(b, 'width', t.getStyle('width', 1));
       
  4835 				dom.setStyle(b, 'height', t.getStyle('height', 1));
       
  4836 				dom.setStyle(b, 'display', t.getStyle('display', 1));
       
  4837 				dom.setStyle(b, 'zIndex', parseInt(t.getStyle('zIndex', 1) || 0) - 1);
       
  4838 			}
       
  4839 		}
       
  4840 	});
       
  4841 })(tinymce);
       
  4842 (function(tinymce) {
       
  4843 	function trimNl(s) {
       
  4844 		return s.replace(/[\n\r]+/g, '');
       
  4845 	};
       
  4846 
       
  4847 	// Shorten names
       
  4848 	var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each;
       
  4849 
       
  4850 	tinymce.create('tinymce.dom.Selection', {
       
  4851 		Selection : function(dom, win, serializer) {
       
  4852 			var t = this;
       
  4853 
       
  4854 			t.dom = dom;
       
  4855 			t.win = win;
       
  4856 			t.serializer = serializer;
       
  4857 
       
  4858 			// Add events
       
  4859 			each([
       
  4860 				'onBeforeSetContent',
       
  4861 				'onBeforeGetContent',
       
  4862 				'onSetContent',
       
  4863 				'onGetContent'
       
  4864 			], function(e) {
       
  4865 				t[e] = new tinymce.util.Dispatcher(t);
       
  4866 			});
       
  4867 
       
  4868 			// No W3C Range support
       
  4869 			if (!t.win.getSelection)
       
  4870 				t.tridentSel = new tinymce.dom.TridentSelection(t);
       
  4871 
       
  4872 			// Prevent leaks
       
  4873 			tinymce.addUnload(t.destroy, t);
       
  4874 		},
       
  4875 
       
  4876 		getContent : function(s) {
       
  4877 			var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
       
  4878 
       
  4879 			s = s || {};
       
  4880 			wb = wa = '';
       
  4881 			s.get = true;
       
  4882 			s.format = s.format || 'html';
       
  4883 			t.onBeforeGetContent.dispatch(t, s);
       
  4884 
       
  4885 			if (s.format == 'text')
       
  4886 				return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));
       
  4887 
       
  4888 			if (r.cloneContents) {
       
  4889 				n = r.cloneContents();
       
  4890 
       
  4891 				if (n)
       
  4892 					e.appendChild(n);
       
  4893 			} else if (is(r.item) || is(r.htmlText))
       
  4894 				e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
       
  4895 			else
       
  4896 				e.innerHTML = r.toString();
       
  4897 
       
  4898 			// Keep whitespace before and after
       
  4899 			if (/^\s/.test(e.innerHTML))
       
  4900 				wb = ' ';
       
  4901 
       
  4902 			if (/\s+$/.test(e.innerHTML))
       
  4903 				wa = ' ';
       
  4904 
       
  4905 			s.getInner = true;
       
  4906 
       
  4907 			s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;
       
  4908 			t.onGetContent.dispatch(t, s);
       
  4909 
       
  4910 			return s.content;
       
  4911 		},
       
  4912 
       
  4913 		setContent : function(h, s) {
       
  4914 			var t = this, r = t.getRng(), c, d = t.win.document;
       
  4915 
       
  4916 			s = s || {format : 'html'};
       
  4917 			s.set = true;
       
  4918 			h = s.content = t.dom.processHTML(h);
       
  4919 
       
  4920 			// Dispatch before set content event
       
  4921 			t.onBeforeSetContent.dispatch(t, s);
       
  4922 			h = s.content;
       
  4923 
       
  4924 			if (r.insertNode) {
       
  4925 				// Make caret marker since insertNode places the caret in the beginning of text after insert
       
  4926 				h += '<span id="__caret">_</span>';
       
  4927 
       
  4928 				// Delete and insert new node
       
  4929 				r.deleteContents();
       
  4930 				r.insertNode(t.getRng().createContextualFragment(h));
       
  4931 
       
  4932 				// Move to caret marker
       
  4933 				c = t.dom.get('__caret');
       
  4934 
       
  4935 				// Make sure we wrap it compleatly, Opera fails with a simple select call
       
  4936 				r = d.createRange();
       
  4937 				r.setStartBefore(c);
       
  4938 				r.setEndAfter(c);
       
  4939 				t.setRng(r);
       
  4940 
       
  4941 				// Delete the marker, and hopefully the caret gets placed in the right location
       
  4942 				// Removed this since it seems to remove &nbsp; in FF and simply deleting it
       
  4943 				// doesn't seem to affect the caret position in any browser
       
  4944 				//d.execCommand('Delete', false, null);
       
  4945 
       
  4946 				// Remove the caret position
       
  4947 				t.dom.remove('__caret');
       
  4948 			} else {
       
  4949 				if (r.item) {
       
  4950 					// Delete content and get caret text selection
       
  4951 					d.execCommand('Delete', false, null);
       
  4952 					r = t.getRng();
       
  4953 				}
       
  4954 
       
  4955 				r.pasteHTML(h);
       
  4956 			}
       
  4957 
       
  4958 			// Dispatch set content event
       
  4959 			t.onSetContent.dispatch(t, s);
       
  4960 		},
       
  4961 
       
  4962 		getStart : function() {
       
  4963 			var t = this, r = t.getRng(), e;
       
  4964 
       
  4965 			if (isIE) {
       
  4966 				if (r.item)
       
  4967 					return r.item(0);
       
  4968 
       
  4969 				r = r.duplicate();
       
  4970 				r.collapse(1);
       
  4971 				e = r.parentElement();
       
  4972 
       
  4973 				if (e && e.nodeName == 'BODY')
       
  4974 					return e.firstChild;
       
  4975 
       
  4976 				return e;
       
  4977 			} else {
       
  4978 				e = r.startContainer;
       
  4979 
       
  4980 				if (e.nodeName == 'BODY')
       
  4981 					return e.firstChild;
       
  4982 
       
  4983 				return t.dom.getParent(e, '*');
       
  4984 			}
       
  4985 		},
       
  4986 
       
  4987 		getEnd : function() {
       
  4988 			var t = this, r = t.getRng(), e;
       
  4989 
       
  4990 			if (isIE) {
       
  4991 				if (r.item)
       
  4992 					return r.item(0);
       
  4993 
       
  4994 				r = r.duplicate();
       
  4995 				r.collapse(0);
       
  4996 				e = r.parentElement();
       
  4997 
       
  4998 				if (e && e.nodeName == 'BODY')
       
  4999 					return e.lastChild;
       
  5000 
       
  5001 				return e;
       
  5002 			} else {
       
  5003 				e = r.endContainer;
       
  5004 
       
  5005 				if (e.nodeName == 'BODY')
       
  5006 					return e.lastChild;
       
  5007 
       
  5008 				return t.dom.getParent(e, '*');
       
  5009 			}
       
  5010 		},
       
  5011 
       
  5012 		getBookmark : function(si) {
       
  5013 			var t = this, r = t.getRng(), tr, sx, sy, vp = t.dom.getViewPort(t.win), e, sp, bp, le, c = -0xFFFFFF, s, ro = t.dom.getRoot(), wb = 0, wa = 0, nv;
       
  5014 			sx = vp.x;
       
  5015 			sy = vp.y;
       
  5016 
       
  5017 			// Simple bookmark fast but not as persistent
       
  5018 			if (si)
       
  5019 				return {rng : r, scrollX : sx, scrollY : sy};
       
  5020 
       
  5021 			// Handle IE
       
  5022 			if (isIE) {
       
  5023 				// Control selection
       
  5024 				if (r.item) {
       
  5025 					e = r.item(0);
       
  5026 
       
  5027 					each(t.dom.select(e.nodeName), function(n, i) {
       
  5028 						if (e == n) {
       
  5029 							sp = i;
       
  5030 							return false;
       
  5031 						}
       
  5032 					});
       
  5033 
       
  5034 					return {
       
  5035 						tag : e.nodeName,
       
  5036 						index : sp,
       
  5037 						scrollX : sx,
       
  5038 						scrollY : sy
       
  5039 					};
       
  5040 				}
       
  5041 
       
  5042 				// Text selection
       
  5043 				tr = t.dom.doc.body.createTextRange();
       
  5044 				tr.moveToElementText(ro);
       
  5045 				tr.collapse(true);
       
  5046 				bp = Math.abs(tr.move('character', c));
       
  5047 
       
  5048 				tr = r.duplicate();
       
  5049 				tr.collapse(true);
       
  5050 				sp = Math.abs(tr.move('character', c));
       
  5051 
       
  5052 				tr = r.duplicate();
       
  5053 				tr.collapse(false);
       
  5054 				le = Math.abs(tr.move('character', c)) - sp;
       
  5055 
       
  5056 				return {
       
  5057 					start : sp - bp,
       
  5058 					length : le,
       
  5059 					scrollX : sx,
       
  5060 					scrollY : sy
       
  5061 				};
       
  5062 			}
       
  5063 
       
  5064 			// Handle W3C
       
  5065 			e = t.getNode();
       
  5066 			s = t.getSel();
       
  5067 
       
  5068 			if (!s)
       
  5069 				return null;
       
  5070 
       
  5071 			// Image selection
       
  5072 			if (e && e.nodeName == 'IMG') {
       
  5073 				return {
       
  5074 					scrollX : sx,
       
  5075 					scrollY : sy
       
  5076 				};
       
  5077 			}
       
  5078 
       
  5079 			// Text selection
       
  5080 
       
  5081 			function getPos(r, sn, en) {
       
  5082 				var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
       
  5083 
       
  5084 				while ((n = w.nextNode()) != null) {
       
  5085 					if (n == sn)
       
  5086 						d.start = p;
       
  5087 
       
  5088 					if (n == en) {
       
  5089 						d.end = p;
       
  5090 						return d;
       
  5091 					}
       
  5092 
       
  5093 					p += trimNl(n.nodeValue || '').length;
       
  5094 				}
       
  5095 
       
  5096 				return null;
       
  5097 			};
       
  5098 
       
  5099 			// Caret or selection
       
  5100 			if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
       
  5101 				e = getPos(ro, s.anchorNode, s.focusNode);
       
  5102 
       
  5103 				if (!e)
       
  5104 					return {scrollX : sx, scrollY : sy};
       
  5105 
       
  5106 				// Count whitespace before
       
  5107 				trimNl(s.anchorNode.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
       
  5108 
       
  5109 				return {
       
  5110 					start : Math.max(e.start + s.anchorOffset - wb, 0),
       
  5111 					end : Math.max(e.end + s.focusOffset - wb, 0),
       
  5112 					scrollX : sx,
       
  5113 					scrollY : sy,
       
  5114 					beg : s.anchorOffset - wb == 0
       
  5115 				};
       
  5116 			} else {
       
  5117 				e = getPos(ro, r.startContainer, r.endContainer);
       
  5118 
       
  5119 				// Count whitespace before start and end container
       
  5120 				//(r.startContainer.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
       
  5121 				//(r.endContainer.nodeValue || '').replace(/^\s+/, function(a) {wa = a.length;});
       
  5122 
       
  5123 				if (!e)
       
  5124 					return {scrollX : sx, scrollY : sy};
       
  5125 
       
  5126 				return {
       
  5127 					start : Math.max(e.start + r.startOffset - wb, 0),
       
  5128 					end : Math.max(e.end + r.endOffset - wa, 0),
       
  5129 					scrollX : sx,
       
  5130 					scrollY : sy,
       
  5131 					beg : r.startOffset - wb == 0
       
  5132 				};
       
  5133 			}
       
  5134 		},
       
  5135 
       
  5136 		moveToBookmark : function(b) {
       
  5137 			var t = this, r = t.getRng(), s = t.getSel(), ro = t.dom.getRoot(), sd, nvl, nv;
       
  5138 
       
  5139 			function getPos(r, sp, ep) {
       
  5140 				var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}, o, v, wa, wb;
       
  5141 
       
  5142 				while ((n = w.nextNode()) != null) {
       
  5143 					wa = wb = 0;
       
  5144 
       
  5145 					nv = n.nodeValue || '';
       
  5146 					//nv.replace(/^\s+[^\s]/, function(a) {wb = a.length - 1;});
       
  5147 					//nv.replace(/[^\s]\s+$/, function(a) {wa = a.length - 1;});
       
  5148 
       
  5149 					nvl = trimNl(nv).length;
       
  5150 					p += nvl;
       
  5151 
       
  5152 					if (p >= sp && !d.startNode) {
       
  5153 						o = sp - (p - nvl);
       
  5154 
       
  5155 						// Fix for odd quirk in FF
       
  5156 						if (b.beg && o >= nvl)
       
  5157 							continue;
       
  5158 
       
  5159 						d.startNode = n;
       
  5160 						d.startOffset = o + wb;
       
  5161 					}
       
  5162 
       
  5163 					if (p >= ep) {
       
  5164 						d.endNode = n;
       
  5165 						d.endOffset = ep - (p - nvl) + wb;
       
  5166 						return d;
       
  5167 					}
       
  5168 				}
       
  5169 
       
  5170 				return null;
       
  5171 			};
       
  5172 
       
  5173 			if (!b)
       
  5174 				return false;
       
  5175 
       
  5176 			t.win.scrollTo(b.scrollX, b.scrollY);
       
  5177 
       
  5178 			// Handle explorer
       
  5179 			if (isIE) {
       
  5180 				t.tridentSel.destroy();
       
  5181 
       
  5182 				// Handle simple
       
  5183 				if (r = b.rng) {
       
  5184 					try {
       
  5185 						r.select();
       
  5186 					} catch (ex) {
       
  5187 						// Ignore
       
  5188 					}
       
  5189 
       
  5190 					return true;
       
  5191 				}
       
  5192 
       
  5193 				t.win.focus();
       
  5194 
       
  5195 				// Handle control bookmark
       
  5196 				if (b.tag) {
       
  5197 					r = ro.createControlRange();
       
  5198 
       
  5199 					each(t.dom.select(b.tag), function(n, i) {
       
  5200 						if (i == b.index)
       
  5201 							r.addElement(n);
       
  5202 					});
       
  5203 				} else {
       
  5204 					// Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
       
  5205 					try {
       
  5206 						// Incorrect bookmark
       
  5207 						if (b.start < 0)
       
  5208 							return true;
       
  5209 
       
  5210 						r = s.createRange();
       
  5211 						r.moveToElementText(ro);
       
  5212 						r.collapse(true);
       
  5213 						r.moveStart('character', b.start);
       
  5214 						r.moveEnd('character', b.length);
       
  5215 					} catch (ex2) {
       
  5216 						return true;
       
  5217 					}
       
  5218 				}
       
  5219 
       
  5220 				try {
       
  5221 					r.select();
       
  5222 				} catch (ex) {
       
  5223 					// Needed for some odd IE bug #1843306
       
  5224 				}
       
  5225 
       
  5226 				return true;
       
  5227 			}
       
  5228 
       
  5229 			// Handle W3C
       
  5230 			if (!s)
       
  5231 				return false;
       
  5232 
       
  5233 			// Handle simple
       
  5234 			if (b.rng) {
       
  5235 				s.removeAllRanges();
       
  5236 				s.addRange(b.rng);
       
  5237 			} else {
       
  5238 				if (is(b.start) && is(b.end)) {
       
  5239 					try {
       
  5240 						sd = getPos(ro, b.start, b.end);
       
  5241 
       
  5242 						if (sd) {
       
  5243 							r = t.dom.doc.createRange();
       
  5244 							r.setStart(sd.startNode, sd.startOffset);
       
  5245 							r.setEnd(sd.endNode, sd.endOffset);
       
  5246 							s.removeAllRanges();
       
  5247 							s.addRange(r);
       
  5248 						}
       
  5249 
       
  5250 						if (!tinymce.isOpera)
       
  5251 							t.win.focus();
       
  5252 					} catch (ex) {
       
  5253 						// Ignore
       
  5254 					}
       
  5255 				}
       
  5256 			}
       
  5257 		},
       
  5258 
       
  5259 		select : function(n, c) {
       
  5260 			var t = this, r = t.getRng(), s = t.getSel(), b, fn, ln, d = t.win.document;
       
  5261 
       
  5262 			function find(n, start) {
       
  5263 				var walker, o;
       
  5264 
       
  5265 				if (n) {
       
  5266 					walker = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
       
  5267 
       
  5268 					// Find first/last non empty text node
       
  5269 					while (n = walker.nextNode()) {
       
  5270 						o = n;
       
  5271 
       
  5272 						if (tinymce.trim(n.nodeValue).length != 0) {
       
  5273 							if (start)
       
  5274 								return n;
       
  5275 							else
       
  5276 								o = n;
       
  5277 						}
       
  5278 					}
       
  5279 				}
       
  5280 
       
  5281 				return o;
       
  5282 			};
       
  5283 
       
  5284 			if (isIE) {
       
  5285 				try {
       
  5286 					b = d.body;
       
  5287 
       
  5288 					if (/^(IMG|TABLE)$/.test(n.nodeName)) {
       
  5289 						r = b.createControlRange();
       
  5290 						r.addElement(n);
       
  5291 					} else {
       
  5292 						r = b.createTextRange();
       
  5293 						r.moveToElementText(n);
       
  5294 					}
       
  5295 
       
  5296 					r.select();
       
  5297 				} catch (ex) {
       
  5298 					// Throws illigal agrument in IE some times
       
  5299 				}
       
  5300 			} else {
       
  5301 				if (c) {
       
  5302 					fn = find(n, 1) || t.dom.select('br:first', n)[0];
       
  5303 					ln = find(n, 0) || t.dom.select('br:last', n)[0];
       
  5304 
       
  5305 					if (fn && ln) {
       
  5306 						r = d.createRange();
       
  5307 
       
  5308 						if (fn.nodeName == 'BR')
       
  5309 							r.setStartBefore(fn);
       
  5310 						else
       
  5311 							r.setStart(fn, 0);
       
  5312 
       
  5313 						if (ln.nodeName == 'BR')
       
  5314 							r.setEndBefore(ln);
       
  5315 						else
       
  5316 							r.setEnd(ln, ln.nodeValue.length);
       
  5317 					} else
       
  5318 						r.selectNode(n);
       
  5319 				} else
       
  5320 					r.selectNode(n);
       
  5321 
       
  5322 				t.setRng(r);
       
  5323 			}
       
  5324 
       
  5325 			return n;
       
  5326 		},
       
  5327 
       
  5328 		isCollapsed : function() {
       
  5329 			var t = this, r = t.getRng(), s = t.getSel();
       
  5330 
       
  5331 			if (!r || r.item)
       
  5332 				return false;
       
  5333 
       
  5334 			return !s || r.boundingWidth == 0 || r.collapsed;
       
  5335 		},
       
  5336 
       
  5337 		collapse : function(b) {
       
  5338 			var t = this, r = t.getRng(), n;
       
  5339 
       
  5340 			// Control range on IE
       
  5341 			if (r.item) {
       
  5342 				n = r.item(0);
       
  5343 				r = this.win.document.body.createTextRange();
       
  5344 				r.moveToElementText(n);
       
  5345 			}
       
  5346 
       
  5347 			r.collapse(!!b);
       
  5348 			t.setRng(r);
       
  5349 		},
       
  5350 
       
  5351 		getSel : function() {
       
  5352 			var t = this, w = this.win;
       
  5353 
       
  5354 			return w.getSelection ? w.getSelection() : w.document.selection;
       
  5355 		},
       
  5356 
       
  5357 		getRng : function(w3c) {
       
  5358 			var t = this, s, r;
       
  5359 
       
  5360 			// Found tridentSel object then we need to use that one
       
  5361 			if (w3c && t.tridentSel)
       
  5362 				return t.tridentSel.getRangeAt(0);
       
  5363 
       
  5364 			try {
       
  5365 				if (s = t.getSel())
       
  5366 					r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : t.win.document.createRange());
       
  5367 			} catch (ex) {
       
  5368 				// IE throws unspecified error here if TinyMCE is placed in a frame/iframe
       
  5369 			}
       
  5370 
       
  5371 			// No range found then create an empty one
       
  5372 			// This can occur when the editor is placed in a hidden container element on Gecko
       
  5373 			// Or on IE when there was an exception
       
  5374 			if (!r)
       
  5375 				r = isIE ? t.win.document.body.createTextRange() : t.win.document.createRange();
       
  5376 
       
  5377 			return r;
       
  5378 		},
       
  5379 
       
  5380 		setRng : function(r) {
       
  5381 			var s, t = this;
       
  5382 
       
  5383 			if (!t.tridentSel) {
       
  5384 				s = t.getSel();
       
  5385 
       
  5386 				if (s) {
       
  5387 					s.removeAllRanges();
       
  5388 					s.addRange(r);
       
  5389 				}
       
  5390 			} else {
       
  5391 				// Is W3C Range
       
  5392 				if (r.cloneRange) {
       
  5393 					t.tridentSel.addRange(r);
       
  5394 					return;
       
  5395 				}
       
  5396 
       
  5397 				// Is IE specific range
       
  5398 				try {
       
  5399 					r.select();
       
  5400 				} catch (ex) {
       
  5401 					// Needed for some odd IE bug #1843306
       
  5402 				}
       
  5403 			}
       
  5404 		},
       
  5405 
       
  5406 		setNode : function(n) {
       
  5407 			var t = this;
       
  5408 
       
  5409 			t.setContent(t.dom.getOuterHTML(n));
       
  5410 
       
  5411 			return n;
       
  5412 		},
       
  5413 
       
  5414 		getNode : function() {
       
  5415 			var t = this, r = t.getRng(), s = t.getSel(), e;
       
  5416 
       
  5417 			if (!isIE) {
       
  5418 				// Range maybe lost after the editor is made visible again
       
  5419 				if (!r)
       
  5420 					return t.dom.getRoot();
       
  5421 
       
  5422 				e = r.commonAncestorContainer;
       
  5423 
       
  5424 				// Handle selection a image or other control like element such as anchors
       
  5425 				if (!r.collapsed) {
       
  5426 					// If the anchor node is a element instead of a text node then return this element
       
  5427 					if (tinymce.isWebKit && s.anchorNode && s.anchorNode.nodeType == 1) 
       
  5428 						return s.anchorNode.childNodes[s.anchorOffset]; 
       
  5429 
       
  5430 					if (r.startContainer == r.endContainer) {
       
  5431 						if (r.startOffset - r.endOffset < 2) {
       
  5432 							if (r.startContainer.hasChildNodes())
       
  5433 								e = r.startContainer.childNodes[r.startOffset];
       
  5434 						}
       
  5435 					}
       
  5436 				}
       
  5437 
       
  5438 				return t.dom.getParent(e, '*');
       
  5439 			}
       
  5440 
       
  5441 			return r.item ? r.item(0) : r.parentElement();
       
  5442 		},
       
  5443 
       
  5444 		getSelectedBlocks : function(st, en) {
       
  5445 			var t = this, dom = t.dom, sb, eb, n, bl = [];
       
  5446 
       
  5447 			sb = dom.getParent(st || t.getStart(), dom.isBlock);
       
  5448 			eb = dom.getParent(en || t.getEnd(), dom.isBlock);
       
  5449 
       
  5450 			if (sb)
       
  5451 				bl.push(sb);
       
  5452 
       
  5453 			if (sb && eb && sb != eb) {
       
  5454 				n = sb;
       
  5455 
       
  5456 				while ((n = n.nextSibling) && n != eb) {
       
  5457 					if (dom.isBlock(n))
       
  5458 						bl.push(n);
       
  5459 				}
       
  5460 			}
       
  5461 
       
  5462 			if (eb && sb != eb)
       
  5463 				bl.push(eb);
       
  5464 
       
  5465 			return bl;
       
  5466 		},
       
  5467 
       
  5468 		destroy : function(s) {
       
  5469 			var t = this;
       
  5470 
       
  5471 			t.win = null;
       
  5472 
       
  5473 			if (t.tridentSel)
       
  5474 				t.tridentSel.destroy();
       
  5475 
       
  5476 			// Manual destroy then remove unload handler
       
  5477 			if (!s)
       
  5478 				tinymce.removeUnload(t.destroy);
       
  5479 		}
       
  5480 	});
       
  5481 })(tinymce);
       
  5482 (function(tinymce) {
       
  5483 	tinymce.create('tinymce.dom.XMLWriter', {
       
  5484 		node : null,
       
  5485 
       
  5486 		XMLWriter : function(s) {
       
  5487 			// Get XML document
       
  5488 			function getXML() {
       
  5489 				var i = document.implementation;
       
  5490 
       
  5491 				if (!i || !i.createDocument) {
       
  5492 					// Try IE objects
       
  5493 					try {return new ActiveXObject('MSXML2.DOMDocument');} catch (ex) {}
       
  5494 					try {return new ActiveXObject('Microsoft.XmlDom');} catch (ex) {}
       
  5495 				} else
       
  5496 					return i.createDocument('', '', null);
       
  5497 			};
       
  5498 
       
  5499 			this.doc = getXML();
       
  5500 			
       
  5501 			// Since Opera and WebKit doesn't escape > into &gt; we need to do it our self to normalize the output for all browsers
       
  5502 			this.valid = tinymce.isOpera || tinymce.isWebKit;
       
  5503 
       
  5504 			this.reset();
       
  5505 		},
       
  5506 
       
  5507 		reset : function() {
       
  5508 			var t = this, d = t.doc;
       
  5509 
       
  5510 			if (d.firstChild)
       
  5511 				d.removeChild(d.firstChild);
       
  5512 
       
  5513 			t.node = d.appendChild(d.createElement("html"));
       
  5514 		},
       
  5515 
       
  5516 		writeStartElement : function(n) {
       
  5517 			var t = this;
       
  5518 
       
  5519 			t.node = t.node.appendChild(t.doc.createElement(n));
       
  5520 		},
       
  5521 
       
  5522 		writeAttribute : function(n, v) {
       
  5523 			if (this.valid)
       
  5524 				v = v.replace(/>/g, '%MCGT%');
       
  5525 
       
  5526 			this.node.setAttribute(n, v);
       
  5527 		},
       
  5528 
       
  5529 		writeEndElement : function() {
       
  5530 			this.node = this.node.parentNode;
       
  5531 		},
       
  5532 
       
  5533 		writeFullEndElement : function() {
       
  5534 			var t = this, n = t.node;
       
  5535 
       
  5536 			n.appendChild(t.doc.createTextNode(""));
       
  5537 			t.node = n.parentNode;
       
  5538 		},
       
  5539 
       
  5540 		writeText : function(v) {
       
  5541 			if (this.valid)
       
  5542 				v = v.replace(/>/g, '%MCGT%');
       
  5543 
       
  5544 			this.node.appendChild(this.doc.createTextNode(v));
       
  5545 		},
       
  5546 
       
  5547 		writeCDATA : function(v) {
       
  5548 			this.node.appendChild(this.doc.createCDATASection(v));
       
  5549 		},
       
  5550 
       
  5551 		writeComment : function(v) {
       
  5552 			// Fix for bug #2035694
       
  5553 			if (tinymce.isIE)
       
  5554 				v = v.replace(/^\-|\-$/g, ' ');
       
  5555 
       
  5556 			this.node.appendChild(this.doc.createComment(v.replace(/\-\-/g, ' ')));
       
  5557 		},
       
  5558 
       
  5559 		getContent : function() {
       
  5560 			var h;
       
  5561 
       
  5562 			h = this.doc.xml || new XMLSerializer().serializeToString(this.doc);
       
  5563 			h = h.replace(/<\?[^?]+\?>|<html>|<\/html>|<html\/>|<!DOCTYPE[^>]+>/g, '');
       
  5564 			h = h.replace(/ ?\/>/g, ' />');
       
  5565 
       
  5566 			if (this.valid)
       
  5567 				h = h.replace(/\%MCGT%/g, '&gt;');
       
  5568 
       
  5569 			return h;
       
  5570 		}
       
  5571 	});
       
  5572 })(tinymce);
       
  5573 (function(tinymce) {
       
  5574 	tinymce.create('tinymce.dom.StringWriter', {
       
  5575 		str : null,
       
  5576 		tags : null,
       
  5577 		count : 0,
       
  5578 		settings : null,
       
  5579 		indent : null,
       
  5580 
       
  5581 		StringWriter : function(s) {
       
  5582 			this.settings = tinymce.extend({
       
  5583 				indent_char : ' ',
       
  5584 				indentation : 0
       
  5585 			}, s);
       
  5586 
       
  5587 			this.reset();
       
  5588 		},
       
  5589 
       
  5590 		reset : function() {
       
  5591 			this.indent = '';
       
  5592 			this.str = "";
       
  5593 			this.tags = [];
       
  5594 			this.count = 0;
       
  5595 		},
       
  5596 
       
  5597 		writeStartElement : function(n) {
       
  5598 			this._writeAttributesEnd();
       
  5599 			this.writeRaw('<' + n);
       
  5600 			this.tags.push(n);
       
  5601 			this.inAttr = true;
       
  5602 			this.count++;
       
  5603 			this.elementCount = this.count;
       
  5604 		},
       
  5605 
       
  5606 		writeAttribute : function(n, v) {
       
  5607 			var t = this;
       
  5608 
       
  5609 			t.writeRaw(" " + t.encode(n) + '="' + t.encode(v) + '"');
       
  5610 		},
       
  5611 
       
  5612 		writeEndElement : function() {
       
  5613 			var n;
       
  5614 
       
  5615 			if (this.tags.length > 0) {
       
  5616 				n = this.tags.pop();
       
  5617 
       
  5618 				if (this._writeAttributesEnd(1))
       
  5619 					this.writeRaw('</' + n + '>');
       
  5620 
       
  5621 				if (this.settings.indentation > 0)
       
  5622 					this.writeRaw('\n');
       
  5623 			}
       
  5624 		},
       
  5625 
       
  5626 		writeFullEndElement : function() {
       
  5627 			if (this.tags.length > 0) {
       
  5628 				this._writeAttributesEnd();
       
  5629 				this.writeRaw('</' + this.tags.pop() + '>');
       
  5630 
       
  5631 				if (this.settings.indentation > 0)
       
  5632 					this.writeRaw('\n');
       
  5633 			}
       
  5634 		},
       
  5635 
       
  5636 		writeText : function(v) {
       
  5637 			this._writeAttributesEnd();
       
  5638 			this.writeRaw(this.encode(v));
       
  5639 			this.count++;
       
  5640 		},
       
  5641 
       
  5642 		writeCDATA : function(v) {
       
  5643 			this._writeAttributesEnd();
       
  5644 			this.writeRaw('<![CDATA[' + v + ']]>');
       
  5645 			this.count++;
       
  5646 		},
       
  5647 
       
  5648 		writeComment : function(v) {
       
  5649 			this._writeAttributesEnd();
       
  5650 			this.writeRaw('<!-- ' + v + '-->');
       
  5651 			this.count++;
       
  5652 		},
       
  5653 
       
  5654 		writeRaw : function(v) {
       
  5655 			this.str += v;
       
  5656 		},
       
  5657 
       
  5658 		encode : function(s) {
       
  5659 			return s.replace(/[<>&"]/g, function(v) {
       
  5660 				switch (v) {
       
  5661 					case '<':
       
  5662 						return '&lt;';
       
  5663 
       
  5664 					case '>':
       
  5665 						return '&gt;';
       
  5666 
       
  5667 					case '&':
       
  5668 						return '&amp;';
       
  5669 
       
  5670 					case '"':
       
  5671 						return '&quot;';
       
  5672 				}
       
  5673 
       
  5674 				return v;
       
  5675 			});
       
  5676 		},
       
  5677 
       
  5678 		getContent : function() {
       
  5679 			return this.str;
       
  5680 		},
       
  5681 
       
  5682 		_writeAttributesEnd : function(s) {
       
  5683 			if (!this.inAttr)
       
  5684 				return;
       
  5685 
       
  5686 			this.inAttr = false;
       
  5687 
       
  5688 			if (s && this.elementCount == this.count) {
       
  5689 				this.writeRaw(' />');
       
  5690 				return false;
       
  5691 			}
       
  5692 
       
  5693 			this.writeRaw('>');
       
  5694 
       
  5695 			return true;
       
  5696 		}
       
  5697 	});
       
  5698 })(tinymce);
       
  5699 (function(tinymce) {
       
  5700 	// Shorten names
       
  5701 	var extend = tinymce.extend, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, isIE = tinymce.isIE, isGecko = tinymce.isGecko;
       
  5702 
       
  5703 	function wildcardToRE(s) {
       
  5704 		return s.replace(/([?+*])/g, '.$1');
       
  5705 	};
       
  5706 
       
  5707 	tinymce.create('tinymce.dom.Serializer', {
       
  5708 		Serializer : function(s) {
       
  5709 			var t = this;
       
  5710 
       
  5711 			t.key = 0;
       
  5712 			t.onPreProcess = new Dispatcher(t);
       
  5713 			t.onPostProcess = new Dispatcher(t);
       
  5714 
       
  5715 			try {
       
  5716 				t.writer = new tinymce.dom.XMLWriter();
       
  5717 			} catch (ex) {
       
  5718 				// IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter
       
  5719 				t.writer = new tinymce.dom.StringWriter();
       
  5720 			}
       
  5721 
       
  5722 			// Default settings
       
  5723 			t.settings = s = extend({
       
  5724 				dom : tinymce.DOM,
       
  5725 				valid_nodes : 0,
       
  5726 				node_filter : 0,
       
  5727 				attr_filter : 0,
       
  5728 				invalid_attrs : /^(mce_|_moz_|sizset|sizcache)/,
       
  5729 				closed : /^(br|hr|input|meta|img|link|param|area)$/,
       
  5730 				entity_encoding : 'named',
       
  5731 				entities : '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,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,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,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,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro',
       
  5732 				valid_elements : '*[*]',
       
  5733 				extended_valid_elements : 0,
       
  5734 				valid_child_elements : 0,
       
  5735 				invalid_elements : 0,
       
  5736 				fix_table_elements : 1,
       
  5737 				fix_list_elements : true,
       
  5738 				fix_content_duplication : true,
       
  5739 				convert_fonts_to_spans : false,
       
  5740 				font_size_classes : 0,
       
  5741 				font_size_style_values : 0,
       
  5742 				apply_source_formatting : 0,
       
  5743 				indent_mode : 'simple',
       
  5744 				indent_char : '\t',
       
  5745 				indent_levels : 1,
       
  5746 				remove_linebreaks : 1,
       
  5747 				remove_redundant_brs : 1,
       
  5748 				element_format : 'xhtml'
       
  5749 			}, s);
       
  5750 
       
  5751 			t.dom = s.dom;
       
  5752 
       
  5753 			if (s.remove_redundant_brs) {
       
  5754 				t.onPostProcess.add(function(se, o) {
       
  5755 					// Remove single BR at end of block elements since they get rendered
       
  5756 					o.content = o.content.replace(/(<br \/>\s*)+<\/(p|h[1-6]|div|li)>/gi, function(a, b, c) {
       
  5757 						// Check if it's a single element
       
  5758 						if (/^<br \/>\s*<\//.test(a))
       
  5759 							return '</' + c + '>';
       
  5760 
       
  5761 						return a;
       
  5762 					});
       
  5763 				});
       
  5764 			}
       
  5765 
       
  5766 			// Remove XHTML element endings i.e. produce crap :) XHTML is better
       
  5767 			if (s.element_format == 'html') {
       
  5768 				t.onPostProcess.add(function(se, o) {
       
  5769 					o.content = o.content.replace(/<([^>]+) \/>/g, '<$1>');
       
  5770 				});
       
  5771 			}
       
  5772 
       
  5773 			if (s.fix_list_elements) {
       
  5774 				t.onPreProcess.add(function(se, o) {
       
  5775 					var nl, x, a = ['ol', 'ul'], i, n, p, r = /^(OL|UL)$/, np;
       
  5776 
       
  5777 					function prevNode(e, n) {
       
  5778 						var a = n.split(','), i;
       
  5779 
       
  5780 						while ((e = e.previousSibling) != null) {
       
  5781 							for (i=0; i<a.length; i++) {
       
  5782 								if (e.nodeName == a[i])
       
  5783 									return e;
       
  5784 							}
       
  5785 						}
       
  5786 
       
  5787 						return null;
       
  5788 					};
       
  5789 
       
  5790 					for (x=0; x<a.length; x++) {
       
  5791 						nl = t.dom.select(a[x], o.node);
       
  5792 
       
  5793 						for (i=0; i<nl.length; i++) {
       
  5794 							n = nl[i];
       
  5795 							p = n.parentNode;
       
  5796 
       
  5797 							if (r.test(p.nodeName)) {
       
  5798 								np = prevNode(n, 'LI');
       
  5799 
       
  5800 								if (!np) {
       
  5801 									np = t.dom.create('li');
       
  5802 									np.innerHTML = '&nbsp;';
       
  5803 									np.appendChild(n);
       
  5804 									p.insertBefore(np, p.firstChild);
       
  5805 								} else
       
  5806 									np.appendChild(n);
       
  5807 							}
       
  5808 						}
       
  5809 					}
       
  5810 				});
       
  5811 			}
       
  5812 
       
  5813 			if (s.fix_table_elements) {
       
  5814 				t.onPreProcess.add(function(se, o) {
       
  5815 					// Since Opera will crash if you attach the node to a dynamic document we need to brrowser sniff a specific build
       
  5816 					// so Opera users with an older version will have to live with less compaible output not much we can do here
       
  5817 					if (!tinymce.isOpera || opera.buildNumber() >= 1767) {
       
  5818 						each(t.dom.select('p table', o.node).reverse(), function(n) {
       
  5819 							var parent = t.dom.getParent(n.parentNode, 'table,p');
       
  5820 
       
  5821 							if (parent.nodeName != 'TABLE') {
       
  5822 								try {
       
  5823 									t.dom.split(parent, n);
       
  5824 								} catch (ex) {
       
  5825 									// IE can sometimes fire an unknown runtime error so we just ignore it
       
  5826 								}
       
  5827 							}
       
  5828 						});
       
  5829 					}
       
  5830 				});
       
  5831 			}
       
  5832 		},
       
  5833 
       
  5834 		setEntities : function(s) {
       
  5835 			var t = this, a, i, l = {}, re = '', v;
       
  5836 
       
  5837 			// No need to setup more than once
       
  5838 			if (t.entityLookup)
       
  5839 				return;
       
  5840 
       
  5841 			// Build regex and lookup array
       
  5842 			a = s.split(',');
       
  5843 			for (i = 0; i < a.length; i += 2) {
       
  5844 				v = a[i];
       
  5845 
       
  5846 				// Don't add default &amp; &quot; etc.
       
  5847 				if (v == 34 || v == 38 || v == 60 || v == 62)
       
  5848 					continue;
       
  5849 
       
  5850 				l[String.fromCharCode(a[i])] = a[i + 1];
       
  5851 
       
  5852 				v = parseInt(a[i]).toString(16);
       
  5853 				re += '\\u' + '0000'.substring(v.length) + v;
       
  5854 			}
       
  5855 
       
  5856 			if (!re) {
       
  5857 				t.settings.entity_encoding = 'raw';
       
  5858 				return;
       
  5859 			}
       
  5860 
       
  5861 			t.entitiesRE = new RegExp('[' + re + ']', 'g');
       
  5862 			t.entityLookup = l;
       
  5863 		},
       
  5864 
       
  5865 		setValidChildRules : function(s) {
       
  5866 			this.childRules = null;
       
  5867 			this.addValidChildRules(s);
       
  5868 		},
       
  5869 
       
  5870 		addValidChildRules : function(s) {
       
  5871 			var t = this, inst, intr, bloc;
       
  5872 
       
  5873 			if (!s)
       
  5874 				return;
       
  5875 
       
  5876 			inst = 'A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment';
       
  5877 			intr = 'A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment';
       
  5878 			bloc = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';
       
  5879 
       
  5880 			each(s.split(','), function(s) {
       
  5881 				var p = s.split(/\[|\]/), re;
       
  5882 
       
  5883 				s = '';
       
  5884 				each(p[1].split('|'), function(v) {
       
  5885 					if (s)
       
  5886 						s += '|';
       
  5887 
       
  5888 					switch (v) {
       
  5889 						case '%itrans':
       
  5890 							v = intr;
       
  5891 							break;
       
  5892 
       
  5893 						case '%itrans_na':
       
  5894 							v = intr.substring(2);
       
  5895 							break;
       
  5896 
       
  5897 						case '%istrict':
       
  5898 							v = inst;
       
  5899 							break;
       
  5900 
       
  5901 						case '%istrict_na':
       
  5902 							v = inst.substring(2);
       
  5903 							break;
       
  5904 
       
  5905 						case '%btrans':
       
  5906 							v = bloc;
       
  5907 							break;
       
  5908 
       
  5909 						case '%bstrict':
       
  5910 							v = bloc;
       
  5911 							break;
       
  5912 					}
       
  5913 
       
  5914 					s += v;
       
  5915 				});
       
  5916 				re = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
       
  5917 
       
  5918 				each(p[0].split('/'), function(s) {
       
  5919 					t.childRules = t.childRules || {};
       
  5920 					t.childRules[s] = re;
       
  5921 				});
       
  5922 			});
       
  5923 
       
  5924 			// Build regex
       
  5925 			s = '';
       
  5926 			each(t.childRules, function(v, k) {
       
  5927 				if (s)
       
  5928 					s += '|';
       
  5929 
       
  5930 				s += k;
       
  5931 			});
       
  5932 
       
  5933 			t.parentElementsRE = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
       
  5934 
       
  5935 			/*console.debug(t.parentElementsRE.toString());
       
  5936 			each(t.childRules, function(v) {
       
  5937 				console.debug(v.toString());
       
  5938 			});*/
       
  5939 		},
       
  5940 
       
  5941 		setRules : function(s) {
       
  5942 			var t = this;
       
  5943 
       
  5944 			t._setup();
       
  5945 			t.rules = {};
       
  5946 			t.wildRules = [];
       
  5947 			t.validElements = {};
       
  5948 
       
  5949 			return t.addRules(s);
       
  5950 		},
       
  5951 
       
  5952 		addRules : function(s) {
       
  5953 			var t = this, dr;
       
  5954 
       
  5955 			if (!s)
       
  5956 				return;
       
  5957 
       
  5958 			t._setup();
       
  5959 
       
  5960 			each(s.split(','), function(s) {
       
  5961 				var p = s.split(/\[|\]/), tn = p[0].split('/'), ra, at, wat, va = [];
       
  5962 
       
  5963 				// Extend with default rules
       
  5964 				if (dr)
       
  5965 					at = tinymce.extend([], dr.attribs);
       
  5966 
       
  5967 				// Parse attributes
       
  5968 				if (p.length > 1) {
       
  5969 					each(p[1].split('|'), function(s) {
       
  5970 						var ar = {}, i;
       
  5971 
       
  5972 						at = at || [];
       
  5973 
       
  5974 						// Parse attribute rule
       
  5975 						s = s.replace(/::/g, '~');
       
  5976 						s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(s);
       
  5977 						s[2] = s[2].replace(/~/g, ':');
       
  5978 
       
  5979 						// Add required attributes
       
  5980 						if (s[1] == '!') {
       
  5981 							ra = ra || [];
       
  5982 							ra.push(s[2]);
       
  5983 						}
       
  5984 
       
  5985 						// Remove inherited attributes
       
  5986 						if (s[1] == '-') {
       
  5987 							for (i = 0; i <at.length; i++) {
       
  5988 								if (at[i].name == s[2]) {
       
  5989 									at.splice(i, 1);
       
  5990 									return;
       
  5991 								}
       
  5992 							}
       
  5993 						}
       
  5994 
       
  5995 						switch (s[3]) {
       
  5996 							// Add default attrib values
       
  5997 							case '=':
       
  5998 								ar.defaultVal = s[4] || '';
       
  5999 								break;
       
  6000 
       
  6001 							// Add forced attrib values
       
  6002 							case ':':
       
  6003 								ar.forcedVal = s[4];
       
  6004 								break;
       
  6005 
       
  6006 							// Add validation values
       
  6007 							case '<':
       
  6008 								ar.validVals = s[4].split('?');
       
  6009 								break;
       
  6010 						}
       
  6011 
       
  6012 						if (/[*.?]/.test(s[2])) {
       
  6013 							wat = wat || [];
       
  6014 							ar.nameRE = new RegExp('^' + wildcardToRE(s[2]) + '$');
       
  6015 							wat.push(ar);
       
  6016 						} else {
       
  6017 							ar.name = s[2];
       
  6018 							at.push(ar);
       
  6019 						}
       
  6020 
       
  6021 						va.push(s[2]);
       
  6022 					});
       
  6023 				}
       
  6024 
       
  6025 				// Handle element names
       
  6026 				each(tn, function(s, i) {
       
  6027 					var pr = s.charAt(0), x = 1, ru = {};
       
  6028 
       
  6029 					// Extend with default rule data
       
  6030 					if (dr) {
       
  6031 						if (dr.noEmpty)
       
  6032 							ru.noEmpty = dr.noEmpty;
       
  6033 
       
  6034 						if (dr.fullEnd)
       
  6035 							ru.fullEnd = dr.fullEnd;
       
  6036 
       
  6037 						if (dr.padd)
       
  6038 							ru.padd = dr.padd;
       
  6039 					}
       
  6040 
       
  6041 					// Handle prefixes
       
  6042 					switch (pr) {
       
  6043 						case '-':
       
  6044 							ru.noEmpty = true;
       
  6045 							break;
       
  6046 
       
  6047 						case '+':
       
  6048 							ru.fullEnd = true;
       
  6049 							break;
       
  6050 
       
  6051 						case '#':
       
  6052 							ru.padd = true;
       
  6053 							break;
       
  6054 
       
  6055 						default:
       
  6056 							x = 0;
       
  6057 					}
       
  6058 
       
  6059 					tn[i] = s = s.substring(x);
       
  6060 					t.validElements[s] = 1;
       
  6061 
       
  6062 					// Add element name or element regex
       
  6063 					if (/[*.?]/.test(tn[0])) {
       
  6064 						ru.nameRE = new RegExp('^' + wildcardToRE(tn[0]) + '$');
       
  6065 						t.wildRules = t.wildRules || {};
       
  6066 						t.wildRules.push(ru);
       
  6067 					} else {
       
  6068 						ru.name = tn[0];
       
  6069 
       
  6070 						// Store away default rule
       
  6071 						if (tn[0] == '@')
       
  6072 							dr = ru;
       
  6073 
       
  6074 						t.rules[s] = ru;
       
  6075 					}
       
  6076 
       
  6077 					ru.attribs = at;
       
  6078 
       
  6079 					if (ra)
       
  6080 						ru.requiredAttribs = ra;
       
  6081 
       
  6082 					if (wat) {
       
  6083 						// Build valid attributes regexp
       
  6084 						s = '';
       
  6085 						each(va, function(v) {
       
  6086 							if (s)
       
  6087 								s += '|';
       
  6088 
       
  6089 							s += '(' + wildcardToRE(v) + ')';
       
  6090 						});
       
  6091 						ru.validAttribsRE = new RegExp('^' + s.toLowerCase() + '$');
       
  6092 						ru.wildAttribs = wat;
       
  6093 					}
       
  6094 				});
       
  6095 			});
       
  6096 
       
  6097 			// Build valid elements regexp
       
  6098 			s = '';
       
  6099 			each(t.validElements, function(v, k) {
       
  6100 				if (s)
       
  6101 					s += '|';
       
  6102 
       
  6103 				if (k != '@')
       
  6104 					s += k;
       
  6105 			});
       
  6106 			t.validElementsRE = new RegExp('^(' + wildcardToRE(s.toLowerCase()) + ')$');
       
  6107 
       
  6108 			//console.debug(t.validElementsRE.toString());
       
  6109 			//console.dir(t.rules);
       
  6110 			//console.dir(t.wildRules);
       
  6111 		},
       
  6112 
       
  6113 		findRule : function(n) {
       
  6114 			var t = this, rl = t.rules, i, r;
       
  6115 
       
  6116 			t._setup();
       
  6117 
       
  6118 			// Exact match
       
  6119 			r = rl[n];
       
  6120 			if (r)
       
  6121 				return r;
       
  6122 
       
  6123 			// Try wildcards
       
  6124 			rl = t.wildRules;
       
  6125 			for (i = 0; i < rl.length; i++) {
       
  6126 				if (rl[i].nameRE.test(n))
       
  6127 					return rl[i];
       
  6128 			}
       
  6129 
       
  6130 			return null;
       
  6131 		},
       
  6132 
       
  6133 		findAttribRule : function(ru, n) {
       
  6134 			var i, wa = ru.wildAttribs;
       
  6135 
       
  6136 			for (i = 0; i < wa.length; i++) {
       
  6137 				if (wa[i].nameRE.test(n))
       
  6138 					return wa[i];
       
  6139 			}
       
  6140 
       
  6141 			return null;
       
  6142 		},
       
  6143 
       
  6144 		serialize : function(n, o) {
       
  6145 			var h, t = this, doc, oldDoc, impl, selected;
       
  6146 
       
  6147 			t._setup();
       
  6148 			o = o || {};
       
  6149 			o.format = o.format || 'html';
       
  6150 			t.processObj = o;
       
  6151 
       
  6152 			// IE looses the selected attribute on option elements so we need to store it
       
  6153 			// See: http://support.microsoft.com/kb/829907
       
  6154 			if (isIE) {
       
  6155 				selected = [];
       
  6156 				each(n.getElementsByTagName('option'), function(n) {
       
  6157 					var v = t.dom.getAttrib(n, 'selected');
       
  6158 
       
  6159 					selected.push(v ? v : null);
       
  6160 				});
       
  6161 			}
       
  6162 
       
  6163 			n = n.cloneNode(true);
       
  6164 
       
  6165 			// IE looses the selected attribute on option elements so we need to restore it
       
  6166 			if (isIE) {
       
  6167 				each(n.getElementsByTagName('option'), function(n, i) {
       
  6168 					t.dom.setAttrib(n, 'selected', selected[i]);
       
  6169 				});
       
  6170 			}
       
  6171 
       
  6172 			// Nodes needs to be attached to something in WebKit/Opera
       
  6173 			// Older builds of Opera crashes if you attach the node to an document created dynamically
       
  6174 			// and since we can't feature detect a crash we need to sniff the acutal build number
       
  6175 			// This fix will make DOM ranges and make Sizzle happy!
       
  6176 			impl = n.ownerDocument.implementation;
       
  6177 			if (impl.createHTMLDocument && (tinymce.isOpera && opera.buildNumber() >= 1767)) {
       
  6178 				// Create an empty HTML document
       
  6179 				doc = impl.createHTMLDocument("");
       
  6180 
       
  6181 				// Add the element or it's children if it's a body element to the new document
       
  6182 				each(n.nodeName == 'BODY' ? n.childNodes : [n], function(node) {
       
  6183 					doc.body.appendChild(doc.importNode(node, true));
       
  6184 				});
       
  6185 
       
  6186 				// Grab first child or body element for serialization
       
  6187 				if (n.nodeName != 'BODY')
       
  6188 					n = doc.body.firstChild;
       
  6189 				else
       
  6190 					n = doc.body;
       
  6191 
       
  6192 				// set the new document in DOMUtils so createElement etc works
       
  6193 				oldDoc = t.dom.doc;
       
  6194 				t.dom.doc = doc;
       
  6195 			}
       
  6196 
       
  6197 			t.key = '' + (parseInt(t.key) + 1);
       
  6198 
       
  6199 			// Pre process
       
  6200 			if (!o.no_events) {
       
  6201 				o.node = n;
       
  6202 				t.onPreProcess.dispatch(t, o);
       
  6203 			}
       
  6204 
       
  6205 			// Serialize HTML DOM into a string
       
  6206 			t.writer.reset();
       
  6207 			t._serializeNode(n, o.getInner);
       
  6208 
       
  6209 			// Post process
       
  6210 			o.content = t.writer.getContent();
       
  6211 
       
  6212 			// Restore the old document if it was changed
       
  6213 			if (oldDoc)
       
  6214 				t.dom.doc = oldDoc;
       
  6215 
       
  6216 			if (!o.no_events)
       
  6217 				t.onPostProcess.dispatch(t, o);
       
  6218 
       
  6219 			t._postProcess(o);
       
  6220 			o.node = null;
       
  6221 
       
  6222 			return tinymce.trim(o.content);
       
  6223 		},
       
  6224 
       
  6225 		// Internal functions
       
  6226 
       
  6227 		_postProcess : function(o) {
       
  6228 			var t = this, s = t.settings, h = o.content, sc = [], p;
       
  6229 
       
  6230 			if (o.format == 'html') {
       
  6231 				// Protect some elements
       
  6232 				p = t._protect({
       
  6233 					content : h,
       
  6234 					patterns : [
       
  6235 						{pattern : /(<script[^>]*>)(.*?)(<\/script>)/g},
       
  6236 						{pattern : /(<noscript[^>]*>)(.*?)(<\/noscript>)/g},
       
  6237 						{pattern : /(<style[^>]*>)(.*?)(<\/style>)/g},
       
  6238 						{pattern : /(<pre[^>]*>)(.*?)(<\/pre>)/g, encode : 1},
       
  6239 						{pattern : /(<!--\[CDATA\[)(.*?)(\]\]-->)/g}
       
  6240 					]
       
  6241 				});
       
  6242 
       
  6243 				h = p.content;
       
  6244 
       
  6245 				// Entity encode
       
  6246 				if (s.entity_encoding !== 'raw')
       
  6247 					h = t._encode(h);
       
  6248 
       
  6249 				// Use BR instead of &nbsp; padded P elements inside editor and use <p>&nbsp;</p> outside editor
       
  6250 /*				if (o.set)
       
  6251 					h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p><br /></p>');
       
  6252 				else
       
  6253 					h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p>$1</p>');*/
       
  6254 
       
  6255 				// Since Gecko and Safari keeps whitespace in the DOM we need to
       
  6256 				// remove it inorder to match other browsers. But I think Gecko and Safari is right.
       
  6257 				// This process is only done when getting contents out from the editor.
       
  6258 				if (!o.set) {
       
  6259 					// We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char
       
  6260 					h = h.replace(/<p>\s+<\/p>|<p([^>]+)>\s+<\/p>/g, s.entity_encoding == 'numeric' ? '<p$1>&#160;</p>' : '<p$1>&nbsp;</p>');
       
  6261 
       
  6262 					if (s.remove_linebreaks) {
       
  6263 						h = h.replace(/\r?\n|\r/g, ' ');
       
  6264 						h = h.replace(/(<[^>]+>)\s+/g, '$1 ');
       
  6265 						h = h.replace(/\s+(<\/[^>]+>)/g, ' $1');
       
  6266 						h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g, '<$1 $2>'); // Trim block start
       
  6267 						h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g, '<$1>'); // Trim block start
       
  6268 						h = h.replace(/\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g, '</$1>'); // Trim block end
       
  6269 					}
       
  6270 
       
  6271 					// Simple indentation
       
  6272 					if (s.apply_source_formatting && s.indent_mode == 'simple') {
       
  6273 						// Add line breaks before and after block elements
       
  6274 						h = h.replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n');
       
  6275 						h = h.replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>');
       
  6276 						h = h.replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '</$1>\n');
       
  6277 						h = h.replace(/\n\n/g, '\n');
       
  6278 					}
       
  6279 				}
       
  6280 
       
  6281 				h = t._unprotect(h, p);
       
  6282 
       
  6283 				// Restore CDATA sections
       
  6284 				h = h.replace(/<!--\[CDATA\[([\s\S]+)\]\]-->/g, '<![CDATA[$1]]>');
       
  6285 
       
  6286 				// Restore the \u00a0 character if raw mode is enabled
       
  6287 				if (s.entity_encoding == 'raw')
       
  6288 					h = h.replace(/<p>&nbsp;<\/p>|<p([^>]+)>&nbsp;<\/p>/g, '<p$1>\u00a0</p>');
       
  6289 
       
  6290 				// Restore noscript elements
       
  6291 				h = h.replace(/<noscript([^>]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) {
       
  6292 					return '<noscript' + attribs + '>' + t.dom.decode(text.replace(/<!--|-->/g, '')) + '</noscript>';
       
  6293 				});
       
  6294 			}
       
  6295 
       
  6296 			o.content = h;
       
  6297 		},
       
  6298 
       
  6299 		_serializeNode : function(n, inn) {
       
  6300 			var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv, closed;
       
  6301 
       
  6302 			if (!s.node_filter || s.node_filter(n)) {
       
  6303 				switch (n.nodeType) {
       
  6304 					case 1: // Element
       
  6305 						if (n.hasAttribute ? n.hasAttribute('mce_bogus') : n.getAttribute('mce_bogus'))
       
  6306 							return;
       
  6307 
       
  6308 						iv = false;
       
  6309 						hc = n.hasChildNodes();
       
  6310 						nn = n.getAttribute('mce_name') || n.nodeName.toLowerCase();
       
  6311 
       
  6312 						// Add correct prefix on IE
       
  6313 						if (isIE) {
       
  6314 							if (n.scopeName !== 'HTML' && n.scopeName !== 'html')
       
  6315 								nn = n.scopeName + ':' + nn;
       
  6316 						}
       
  6317 
       
  6318 						// Remove mce prefix on IE needed for the abbr element
       
  6319 						if (nn.indexOf('mce:') === 0)
       
  6320 							nn = nn.substring(4);
       
  6321 
       
  6322 						// Check if valid
       
  6323 						if (!t.validElementsRE || !t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) {
       
  6324 							iv = true;
       
  6325 							break;
       
  6326 						}
       
  6327 
       
  6328 						if (isIE) {
       
  6329 							// Fix IE content duplication (DOM can have multiple copies of the same node)
       
  6330 							if (s.fix_content_duplication) {
       
  6331 								if (n.mce_serialized == t.key)
       
  6332 									return;
       
  6333 
       
  6334 								n.mce_serialized = t.key;
       
  6335 							}
       
  6336 
       
  6337 							// IE sometimes adds a / infront of the node name
       
  6338 							if (nn.charAt(0) == '/')
       
  6339 								nn = nn.substring(1);
       
  6340 						} else if (isGecko) {
       
  6341 							// Ignore br elements
       
  6342 							if (n.nodeName === 'BR' && n.getAttribute('type') == '_moz')
       
  6343 								return;
       
  6344 						}
       
  6345 
       
  6346 						// Check if valid child
       
  6347 						if (t.childRules) {
       
  6348 							if (t.parentElementsRE.test(t.elementName)) {
       
  6349 								if (!t.childRules[t.elementName].test(nn)) {
       
  6350 									iv = true;
       
  6351 									break;
       
  6352 								}
       
  6353 							}
       
  6354 
       
  6355 							t.elementName = nn;
       
  6356 						}
       
  6357 
       
  6358 						ru = t.findRule(nn);
       
  6359 						nn = ru.name || nn;
       
  6360 						closed = s.closed.test(nn);
       
  6361 
       
  6362 						// Skip empty nodes or empty node name in IE
       
  6363 						if ((!hc && ru.noEmpty) || (isIE && !nn)) {
       
  6364 							iv = true;
       
  6365 							break;
       
  6366 						}
       
  6367 
       
  6368 						// Check required
       
  6369 						if (ru.requiredAttribs) {
       
  6370 							a = ru.requiredAttribs;
       
  6371 
       
  6372 							for (i = a.length - 1; i >= 0; i--) {
       
  6373 								if (this.dom.getAttrib(n, a[i]) !== '')
       
  6374 									break;
       
  6375 							}
       
  6376 
       
  6377 							// None of the required was there
       
  6378 							if (i == -1) {
       
  6379 								iv = true;
       
  6380 								break;
       
  6381 							}
       
  6382 						}
       
  6383 
       
  6384 						w.writeStartElement(nn);
       
  6385 
       
  6386 						// Add ordered attributes
       
  6387 						if (ru.attribs) {
       
  6388 							for (i=0, at = ru.attribs, l = at.length; i<l; i++) {
       
  6389 								a = at[i];
       
  6390 								v = t._getAttrib(n, a);
       
  6391 
       
  6392 								if (v !== null)
       
  6393 									w.writeAttribute(a.name, v);
       
  6394 							}
       
  6395 						}
       
  6396 
       
  6397 						// Add wild attributes
       
  6398 						if (ru.validAttribsRE) {
       
  6399 							at = t.dom.getAttribs(n);
       
  6400 							for (i=at.length-1; i>-1; i--) {
       
  6401 								no = at[i];
       
  6402 
       
  6403 								if (no.specified) {
       
  6404 									a = no.nodeName.toLowerCase();
       
  6405 
       
  6406 									if (s.invalid_attrs.test(a) || !ru.validAttribsRE.test(a))
       
  6407 										continue;
       
  6408 
       
  6409 									ar = t.findAttribRule(ru, a);
       
  6410 									v = t._getAttrib(n, ar, a);
       
  6411 
       
  6412 									if (v !== null)
       
  6413 										w.writeAttribute(a, v);
       
  6414 								}
       
  6415 							}
       
  6416 						}
       
  6417 
       
  6418 						// Write text from script
       
  6419 						if (nn === 'script' && tinymce.trim(n.innerHTML)) {
       
  6420 							w.writeText('// '); // Padd it with a comment so it will parse on older browsers
       
  6421 							w.writeCDATA(n.innerHTML.replace(/<!--|-->|<\[CDATA\[|\]\]>/g, '')); // Remove comments and cdata stuctures
       
  6422 							hc = false;
       
  6423 							break;
       
  6424 						}
       
  6425 
       
  6426 						// Padd empty nodes with a &nbsp;
       
  6427 						if (ru.padd) {
       
  6428 							// If it has only one bogus child, padd it anyway workaround for <td><br /></td> bug
       
  6429 							if (hc && (cn = n.firstChild) && cn.nodeType === 1 && n.childNodes.length === 1) {
       
  6430 								if (cn.hasAttribute ? cn.hasAttribute('mce_bogus') : cn.getAttribute('mce_bogus'))
       
  6431 									w.writeText('\u00a0');
       
  6432 							} else if (!hc)
       
  6433 								w.writeText('\u00a0'); // No children then padd it
       
  6434 						}
       
  6435 
       
  6436 						break;
       
  6437 
       
  6438 					case 3: // Text
       
  6439 						// Check if valid child
       
  6440 						if (t.childRules && t.parentElementsRE.test(t.elementName)) {
       
  6441 							if (!t.childRules[t.elementName].test(n.nodeName))
       
  6442 								return;
       
  6443 						}
       
  6444 
       
  6445 						return w.writeText(n.nodeValue);
       
  6446 
       
  6447 					case 4: // CDATA
       
  6448 						return w.writeCDATA(n.nodeValue);
       
  6449 
       
  6450 					case 8: // Comment
       
  6451 						return w.writeComment(n.nodeValue);
       
  6452 				}
       
  6453 			} else if (n.nodeType == 1)
       
  6454 				hc = n.hasChildNodes();
       
  6455 
       
  6456 			if (hc && !closed) {
       
  6457 				cn = n.firstChild;
       
  6458 
       
  6459 				while (cn) {
       
  6460 					t._serializeNode(cn);
       
  6461 					t.elementName = nn;
       
  6462 					cn = cn.nextSibling;
       
  6463 				}
       
  6464 			}
       
  6465 
       
  6466 			// Write element end
       
  6467 			if (!iv) {
       
  6468 				if (!closed)
       
  6469 					w.writeFullEndElement();
       
  6470 				else
       
  6471 					w.writeEndElement();
       
  6472 			}
       
  6473 		},
       
  6474 
       
  6475 		_protect : function(o) {
       
  6476 			var t = this;
       
  6477 
       
  6478 			o.items = o.items || [];
       
  6479 
       
  6480 			function enc(s) {
       
  6481 				return s.replace(/[\r\n\\]/g, function(c) {
       
  6482 					if (c === '\n')
       
  6483 						return '\\n';
       
  6484 					else if (c === '\\')
       
  6485 						return '\\\\';
       
  6486 
       
  6487 					return '\\r';
       
  6488 				});
       
  6489 			};
       
  6490 
       
  6491 			function dec(s) {
       
  6492 				return s.replace(/\\[\\rn]/g, function(c) {
       
  6493 					if (c === '\\n')
       
  6494 						return '\n';
       
  6495 					else if (c === '\\\\')
       
  6496 						return '\\';
       
  6497 
       
  6498 					return '\r';
       
  6499 				});
       
  6500 			};
       
  6501 
       
  6502 			each(o.patterns, function(p) {
       
  6503 				o.content = dec(enc(o.content).replace(p.pattern, function(x, a, b, c) {
       
  6504 					b = dec(b);
       
  6505 
       
  6506 					if (p.encode)
       
  6507 						b = t._encode(b);
       
  6508 
       
  6509 					o.items.push(b);
       
  6510 					return a + '<!--mce:' + (o.items.length - 1) + '-->' + c;
       
  6511 				}));
       
  6512 			});
       
  6513 
       
  6514 			return o;
       
  6515 		},
       
  6516 
       
  6517 		_unprotect : function(h, o) {
       
  6518 			h = h.replace(/\<!--mce:([0-9]+)--\>/g, function(a, b) {
       
  6519 				return o.items[parseInt(b)];
       
  6520 			});
       
  6521 
       
  6522 			o.items = [];
       
  6523 
       
  6524 			return h;
       
  6525 		},
       
  6526 
       
  6527 		_encode : function(h) {
       
  6528 			var t = this, s = t.settings, l;
       
  6529 
       
  6530 			// Entity encode
       
  6531 			if (s.entity_encoding !== 'raw') {
       
  6532 				if (s.entity_encoding.indexOf('named') != -1) {
       
  6533 					t.setEntities(s.entities);
       
  6534 					l = t.entityLookup;
       
  6535 
       
  6536 					h = h.replace(t.entitiesRE, function(a) {
       
  6537 						var v;
       
  6538 
       
  6539 						if (v = l[a])
       
  6540 							a = '&' + v + ';';
       
  6541 
       
  6542 						return a;
       
  6543 					});
       
  6544 				}
       
  6545 
       
  6546 				if (s.entity_encoding.indexOf('numeric') != -1) {
       
  6547 					h = h.replace(/[\u007E-\uFFFF]/g, function(a) {
       
  6548 						return '&#' + a.charCodeAt(0) + ';';
       
  6549 					});
       
  6550 				}
       
  6551 			}
       
  6552 
       
  6553 			return h;
       
  6554 		},
       
  6555 
       
  6556 		_setup : function() {
       
  6557 			var t = this, s = this.settings;
       
  6558 
       
  6559 			if (t.done)
       
  6560 				return;
       
  6561 
       
  6562 			t.done = 1;
       
  6563 
       
  6564 			t.setRules(s.valid_elements);
       
  6565 			t.addRules(s.extended_valid_elements);
       
  6566 			t.addValidChildRules(s.valid_child_elements);
       
  6567 
       
  6568 			if (s.invalid_elements)
       
  6569 				t.invalidElementsRE = new RegExp('^(' + wildcardToRE(s.invalid_elements.replace(/,/g, '|').toLowerCase()) + ')$');
       
  6570 
       
  6571 			if (s.attrib_value_filter)
       
  6572 				t.attribValueFilter = s.attribValueFilter;
       
  6573 		},
       
  6574 
       
  6575 		_getAttrib : function(n, a, na) {
       
  6576 			var i, v;
       
  6577 
       
  6578 			na = na || a.name;
       
  6579 
       
  6580 			if (a.forcedVal && (v = a.forcedVal)) {
       
  6581 				if (v === '{$uid}')
       
  6582 					return this.dom.uniqueId();
       
  6583 
       
  6584 				return v;
       
  6585 			}
       
  6586 
       
  6587 			v = this.dom.getAttrib(n, na);
       
  6588 
       
  6589 			switch (na) {
       
  6590 				case 'rowspan':
       
  6591 				case 'colspan':
       
  6592 					// Whats the point? Remove usless attribute value
       
  6593 					if (v == '1')
       
  6594 						v = '';
       
  6595 
       
  6596 					break;
       
  6597 			}
       
  6598 
       
  6599 			if (this.attribValueFilter)
       
  6600 				v = this.attribValueFilter(na, v, n);
       
  6601 
       
  6602 			if (a.validVals) {
       
  6603 				for (i = a.validVals.length - 1; i >= 0; i--) {
       
  6604 					if (v == a.validVals[i])
       
  6605 						break;
       
  6606 				}
       
  6607 
       
  6608 				if (i == -1)
       
  6609 					return null;
       
  6610 			}
       
  6611 
       
  6612 			if (v === '' && typeof(a.defaultVal) != 'undefined') {
       
  6613 				v = a.defaultVal;
       
  6614 
       
  6615 				if (v === '{$uid}')
       
  6616 					return this.dom.uniqueId();
       
  6617 
       
  6618 				return v;
       
  6619 			} else {
       
  6620 				// Remove internal mceItemXX classes when content is extracted from editor
       
  6621 				if (na == 'class' && this.processObj.get)
       
  6622 					v = v.replace(/\s?mceItem\w+\s?/g, '');
       
  6623 			}
       
  6624 
       
  6625 			if (v === '')
       
  6626 				return null;
       
  6627 
       
  6628 
       
  6629 			return v;
       
  6630 		}
       
  6631 	});
       
  6632 })(tinymce);
       
  6633 (function(tinymce) {
       
  6634 	var each = tinymce.each, Event = tinymce.dom.Event;
       
  6635 
       
  6636 	tinymce.create('tinymce.dom.ScriptLoader', {
       
  6637 		ScriptLoader : function(s) {
       
  6638 			this.settings = s || {};
       
  6639 			this.queue = [];
       
  6640 			this.lookup = {};
       
  6641 		},
       
  6642 
       
  6643 		isDone : function(u) {
       
  6644 			return this.lookup[u] ? this.lookup[u].state == 2 : 0;
       
  6645 		},
       
  6646 
       
  6647 		markDone : function(u) {
       
  6648 			this.lookup[u] = {state : 2, url : u};
       
  6649 		},
       
  6650 
       
  6651 		add : function(u, cb, s, pr) {
       
  6652 			var t = this, lo = t.lookup, o;
       
  6653 
       
  6654 			if (o = lo[u]) {
       
  6655 				// Is loaded fire callback
       
  6656 				if (cb && o.state == 2)
       
  6657 					cb.call(s || this);
       
  6658 
       
  6659 				return o;
       
  6660 			}
       
  6661 
       
  6662 			o = {state : 0, url : u, func : cb, scope : s || this};
       
  6663 
       
  6664 			if (pr)
       
  6665 				t.queue.unshift(o);
       
  6666 			else
       
  6667 				t.queue.push(o);
       
  6668 
       
  6669 			lo[u] = o;
       
  6670 
       
  6671 			return o;
       
  6672 		},
       
  6673 
       
  6674 		load : function(u, cb, s) {
       
  6675 			var t = this, o;
       
  6676 
       
  6677 			if (o = t.lookup[u]) {
       
  6678 				// Is loaded fire callback
       
  6679 				if (cb && o.state == 2)
       
  6680 					cb.call(s || t);
       
  6681 
       
  6682 				return o;
       
  6683 			}
       
  6684 
       
  6685 			function loadScript(u) {
       
  6686 				if (Event.domLoaded || t.settings.strict_mode) {
       
  6687 					tinymce.util.XHR.send({
       
  6688 						url : tinymce._addVer(u),
       
  6689 						error : t.settings.error,
       
  6690 						async : false,
       
  6691 						success : function(co) {
       
  6692 							t.eval(co);
       
  6693 						}
       
  6694 					});
       
  6695 				} else
       
  6696 					document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"></script>');
       
  6697 			};
       
  6698 
       
  6699 			if (!tinymce.is(u, 'string')) {
       
  6700 				each(u, function(u) {
       
  6701 					loadScript(u);
       
  6702 				});
       
  6703 
       
  6704 				if (cb)
       
  6705 					cb.call(s || t);
       
  6706 			} else {
       
  6707 				loadScript(u);
       
  6708 
       
  6709 				if (cb)
       
  6710 					cb.call(s || t);
       
  6711 			}
       
  6712 		},
       
  6713 
       
  6714 		loadQueue : function(cb, s) {
       
  6715 			var t = this;
       
  6716 
       
  6717 			if (!t.queueLoading) {
       
  6718 				t.queueLoading = 1;
       
  6719 				t.queueCallbacks = [];
       
  6720 
       
  6721 				t.loadScripts(t.queue, function() {
       
  6722 					t.queueLoading = 0;
       
  6723 
       
  6724 					if (cb)
       
  6725 						cb.call(s || t);
       
  6726 
       
  6727 					each(t.queueCallbacks, function(o) {
       
  6728 						o.func.call(o.scope);
       
  6729 					});
       
  6730 				});
       
  6731 			} else if (cb)
       
  6732 				t.queueCallbacks.push({func : cb, scope : s || t});
       
  6733 		},
       
  6734 
       
  6735 		eval : function(co) {
       
  6736 			var w = window;
       
  6737 
       
  6738 			// Evaluate script
       
  6739 			if (!w.execScript) {
       
  6740 				try {
       
  6741 					eval.call(w, co);
       
  6742 				} catch (ex) {
       
  6743 					eval(co, w); // Firefox 3.0a8
       
  6744 				}
       
  6745 			} else
       
  6746 				w.execScript(co); // IE
       
  6747 		},
       
  6748 
       
  6749 		loadScripts : function(sc, cb, s) {
       
  6750 			var t = this, lo = t.lookup;
       
  6751 
       
  6752 			function done(o) {
       
  6753 				o.state = 2; // Has been loaded
       
  6754 
       
  6755 				// Run callback
       
  6756 				if (o.func)
       
  6757 					o.func.call(o.scope || t);
       
  6758 			};
       
  6759 
       
  6760 			function allDone() {
       
  6761 				var l;
       
  6762 
       
  6763 				// Check if all files are loaded
       
  6764 				l = sc.length;
       
  6765 				each(sc, function(o) {
       
  6766 					o = lo[o.url];
       
  6767 
       
  6768 					if (o.state === 2) {// It has finished loading
       
  6769 						done(o);
       
  6770 						l--;
       
  6771 					} else
       
  6772 						load(o);
       
  6773 				});
       
  6774 
       
  6775 				// They are all loaded
       
  6776 				if (l === 0 && cb) {
       
  6777 					cb.call(s || t);
       
  6778 					cb = 0;
       
  6779 				}
       
  6780 			};
       
  6781 
       
  6782 			function load(o) {
       
  6783 				if (o.state > 0)
       
  6784 					return;
       
  6785 
       
  6786 				o.state = 1; // Is loading
       
  6787 
       
  6788 				tinymce.dom.ScriptLoader.loadScript(o.url, function() {
       
  6789 					done(o);
       
  6790 					allDone();
       
  6791 				});
       
  6792 
       
  6793 				/*
       
  6794 				tinymce.util.XHR.send({
       
  6795 					url : o.url,
       
  6796 					error : t.settings.error,
       
  6797 					success : function(co) {
       
  6798 						t.eval(co);
       
  6799 						done(o);
       
  6800 						allDone();
       
  6801 					}
       
  6802 				});
       
  6803 				*/
       
  6804 			};
       
  6805 
       
  6806 			each(sc, function(o) {
       
  6807 				var u = o.url;
       
  6808 
       
  6809 				// Add to queue if needed
       
  6810 				if (!lo[u]) {
       
  6811 					lo[u] = o;
       
  6812 					t.queue.push(o);
       
  6813 				} else
       
  6814 					o = lo[u];
       
  6815 
       
  6816 				// Is already loading or has been loaded
       
  6817 				if (o.state > 0)
       
  6818 					return;
       
  6819 
       
  6820 				if (!Event.domLoaded && !t.settings.strict_mode) {
       
  6821 					var ix, ol = '';
       
  6822 
       
  6823 					// Add onload events
       
  6824 					if (cb || o.func) {
       
  6825 						o.state = 1; // Is loading
       
  6826 
       
  6827 						ix = tinymce.dom.ScriptLoader._addOnLoad(function() {
       
  6828 							done(o);
       
  6829 							allDone();
       
  6830 						});
       
  6831 
       
  6832 						if (tinymce.isIE)
       
  6833 							ol = ' onreadystatechange="';
       
  6834 						else
       
  6835 							ol = ' onload="';
       
  6836 
       
  6837 						ol += 'tinymce.dom.ScriptLoader._onLoad(this,\'' + u + '\',' + ix + ');"';
       
  6838 					}
       
  6839 
       
  6840 					document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"' + ol + '></script>');
       
  6841 
       
  6842 					if (!o.func)
       
  6843 						done(o);
       
  6844 				} else
       
  6845 					load(o);
       
  6846 			});
       
  6847 
       
  6848 			allDone();
       
  6849 		},
       
  6850 
       
  6851 		// Static methods
       
  6852 		'static' : {
       
  6853 			_addOnLoad : function(f) {
       
  6854 				var t = this;
       
  6855 
       
  6856 				t._funcs = t._funcs || [];
       
  6857 				t._funcs.push(f);
       
  6858 
       
  6859 				return t._funcs.length - 1;
       
  6860 			},
       
  6861 
       
  6862 			_onLoad : function(e, u, ix) {
       
  6863 				if (!tinymce.isIE || e.readyState == 'complete')
       
  6864 					this._funcs[ix].call(this);
       
  6865 			},
       
  6866 
       
  6867 			loadScript : function(u, cb) {
       
  6868 				var id = tinymce.DOM.uniqueId(), e;
       
  6869 
       
  6870 				function done() {
       
  6871 					Event.clear(id);
       
  6872 					tinymce.DOM.remove(id);
       
  6873 
       
  6874 					if (cb) {
       
  6875 						cb.call(document, u);
       
  6876 						cb = 0;
       
  6877 					}
       
  6878 				};
       
  6879 
       
  6880 				if (tinymce.isIE) {
       
  6881 /*					Event.add(e, 'readystatechange', function(e) {
       
  6882 						if (e.target && e.target.readyState == 'complete')
       
  6883 							done();
       
  6884 					});*/
       
  6885 
       
  6886 					tinymce.util.XHR.send({
       
  6887 						url : tinymce._addVer(u),
       
  6888 						async : false,
       
  6889 						success : function(co) {
       
  6890 							window.execScript(co);
       
  6891 							done();
       
  6892 						}
       
  6893 					});
       
  6894 				} else {
       
  6895 					e = tinymce.DOM.create('script', {id : id, type : 'text/javascript', src : tinymce._addVer(u)});
       
  6896 					Event.add(e, 'load', done);
       
  6897 
       
  6898 					// Check for head or body
       
  6899 					(document.getElementsByTagName('head')[0] || document.body).appendChild(e);
       
  6900 				}
       
  6901 			}
       
  6902 		}
       
  6903 	});
       
  6904 
       
  6905 	// Global script loader
       
  6906 	tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
       
  6907 })(tinymce);
       
  6908 (function(tinymce) {
       
  6909 	// Shorten class names
       
  6910 	var DOM = tinymce.DOM, is = tinymce.is;
       
  6911 
       
  6912 	tinymce.create('tinymce.ui.Control', {
       
  6913 		Control : function(id, s) {
       
  6914 			this.id = id;
       
  6915 			this.settings = s = s || {};
       
  6916 			this.rendered = false;
       
  6917 			this.onRender = new tinymce.util.Dispatcher(this);
       
  6918 			this.classPrefix = '';
       
  6919 			this.scope = s.scope || this;
       
  6920 			this.disabled = 0;
       
  6921 			this.active = 0;
       
  6922 		},
       
  6923 
       
  6924 		setDisabled : function(s) {
       
  6925 			var e;
       
  6926 
       
  6927 			if (s != this.disabled) {
       
  6928 				e = DOM.get(this.id);
       
  6929 
       
  6930 				// Add accessibility title for unavailable actions
       
  6931 				if (e && this.settings.unavailable_prefix) {
       
  6932 					if (s) {
       
  6933 						this.prevTitle = e.title;
       
  6934 						e.title = this.settings.unavailable_prefix + ": " + e.title;
       
  6935 					} else
       
  6936 						e.title = this.prevTitle;
       
  6937 				}
       
  6938 
       
  6939 				this.setState('Disabled', s);
       
  6940 				this.setState('Enabled', !s);
       
  6941 				this.disabled = s;
       
  6942 			}
       
  6943 		},
       
  6944 
       
  6945 		isDisabled : function() {
       
  6946 			return this.disabled;
       
  6947 		},
       
  6948 
       
  6949 		setActive : function(s) {
       
  6950 			if (s != this.active) {
       
  6951 				this.setState('Active', s);
       
  6952 				this.active = s;
       
  6953 			}
       
  6954 		},
       
  6955 
       
  6956 		isActive : function() {
       
  6957 			return this.active;
       
  6958 		},
       
  6959 
       
  6960 		setState : function(c, s) {
       
  6961 			var n = DOM.get(this.id);
       
  6962 
       
  6963 			c = this.classPrefix + c;
       
  6964 
       
  6965 			if (s)
       
  6966 				DOM.addClass(n, c);
       
  6967 			else
       
  6968 				DOM.removeClass(n, c);
       
  6969 		},
       
  6970 
       
  6971 		isRendered : function() {
       
  6972 			return this.rendered;
       
  6973 		},
       
  6974 
       
  6975 		renderHTML : function() {
       
  6976 		},
       
  6977 
       
  6978 		renderTo : function(n) {
       
  6979 			DOM.setHTML(n, this.renderHTML());
       
  6980 		},
       
  6981 
       
  6982 		postRender : function() {
       
  6983 			var t = this, b;
       
  6984 
       
  6985 			// Set pending states
       
  6986 			if (is(t.disabled)) {
       
  6987 				b = t.disabled;
       
  6988 				t.disabled = -1;
       
  6989 				t.setDisabled(b);
       
  6990 			}
       
  6991 
       
  6992 			if (is(t.active)) {
       
  6993 				b = t.active;
       
  6994 				t.active = -1;
       
  6995 				t.setActive(b);
       
  6996 			}
       
  6997 		},
       
  6998 
       
  6999 		remove : function() {
       
  7000 			DOM.remove(this.id);
       
  7001 			this.destroy();
       
  7002 		},
       
  7003 
       
  7004 		destroy : function() {
       
  7005 			tinymce.dom.Event.clear(this.id);
       
  7006 		}
       
  7007 	});
       
  7008 })(tinymce);tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {
       
  7009 	Container : function(id, s) {
       
  7010 		this.parent(id, s);
       
  7011 
       
  7012 		this.controls = [];
       
  7013 
       
  7014 		this.lookup = {};
       
  7015 	},
       
  7016 
       
  7017 	add : function(c) {
       
  7018 		this.lookup[c.id] = c;
       
  7019 		this.controls.push(c);
       
  7020 
       
  7021 		return c;
       
  7022 	},
       
  7023 
       
  7024 	get : function(n) {
       
  7025 		return this.lookup[n];
       
  7026 	}
       
  7027 });
       
  7028 
       
  7029 tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
       
  7030 	Separator : function(id, s) {
       
  7031 		this.parent(id, s);
       
  7032 		this.classPrefix = 'mceSeparator';
       
  7033 	},
       
  7034 
       
  7035 	renderHTML : function() {
       
  7036 		return tinymce.DOM.createHTML('span', {'class' : this.classPrefix});
       
  7037 	}
       
  7038 });
       
  7039 (function(tinymce) {
       
  7040 	var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
       
  7041 
       
  7042 	tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {
       
  7043 		MenuItem : function(id, s) {
       
  7044 			this.parent(id, s);
       
  7045 			this.classPrefix = 'mceMenuItem';
       
  7046 		},
       
  7047 
       
  7048 		setSelected : function(s) {
       
  7049 			this.setState('Selected', s);
       
  7050 			this.selected = s;
       
  7051 		},
       
  7052 
       
  7053 		isSelected : function() {
       
  7054 			return this.selected;
       
  7055 		},
       
  7056 
       
  7057 		postRender : function() {
       
  7058 			var t = this;
       
  7059 			
       
  7060 			t.parent();
       
  7061 
       
  7062 			// Set pending state
       
  7063 			if (is(t.selected))
       
  7064 				t.setSelected(t.selected);
       
  7065 		}
       
  7066 	});
       
  7067 })(tinymce);
       
  7068 (function(tinymce) {
       
  7069 	var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
       
  7070 
       
  7071 	tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {
       
  7072 		Menu : function(id, s) {
       
  7073 			var t = this;
       
  7074 
       
  7075 			t.parent(id, s);
       
  7076 			t.items = {};
       
  7077 			t.collapsed = false;
       
  7078 			t.menuCount = 0;
       
  7079 			t.onAddItem = new tinymce.util.Dispatcher(this);
       
  7080 		},
       
  7081 
       
  7082 		expand : function(d) {
       
  7083 			var t = this;
       
  7084 
       
  7085 			if (d) {
       
  7086 				walk(t, function(o) {
       
  7087 					if (o.expand)
       
  7088 						o.expand();
       
  7089 				}, 'items', t);
       
  7090 			}
       
  7091 
       
  7092 			t.collapsed = false;
       
  7093 		},
       
  7094 
       
  7095 		collapse : function(d) {
       
  7096 			var t = this;
       
  7097 
       
  7098 			if (d) {
       
  7099 				walk(t, function(o) {
       
  7100 					if (o.collapse)
       
  7101 						o.collapse();
       
  7102 				}, 'items', t);
       
  7103 			}
       
  7104 
       
  7105 			t.collapsed = true;
       
  7106 		},
       
  7107 
       
  7108 		isCollapsed : function() {
       
  7109 			return this.collapsed;
       
  7110 		},
       
  7111 
       
  7112 		add : function(o) {
       
  7113 			if (!o.settings)
       
  7114 				o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);
       
  7115 
       
  7116 			this.onAddItem.dispatch(this, o);
       
  7117 
       
  7118 			return this.items[o.id] = o;
       
  7119 		},
       
  7120 
       
  7121 		addSeparator : function() {
       
  7122 			return this.add({separator : true});
       
  7123 		},
       
  7124 
       
  7125 		addMenu : function(o) {
       
  7126 			if (!o.collapse)
       
  7127 				o = this.createMenu(o);
       
  7128 
       
  7129 			this.menuCount++;
       
  7130 
       
  7131 			return this.add(o);
       
  7132 		},
       
  7133 
       
  7134 		hasMenus : function() {
       
  7135 			return this.menuCount !== 0;
       
  7136 		},
       
  7137 
       
  7138 		remove : function(o) {
       
  7139 			delete this.items[o.id];
       
  7140 		},
       
  7141 
       
  7142 		removeAll : function() {
       
  7143 			var t = this;
       
  7144 
       
  7145 			walk(t, function(o) {
       
  7146 				if (o.removeAll)
       
  7147 					o.removeAll();
       
  7148 				else
       
  7149 					o.remove();
       
  7150 
       
  7151 				o.destroy();
       
  7152 			}, 'items', t);
       
  7153 
       
  7154 			t.items = {};
       
  7155 		},
       
  7156 
       
  7157 		createMenu : function(o) {
       
  7158 			var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);
       
  7159 
       
  7160 			m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);
       
  7161 
       
  7162 			return m;
       
  7163 		}
       
  7164 	});
       
  7165 })(tinymce);(function(tinymce) {
       
  7166 	var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;
       
  7167 
       
  7168 	tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {
       
  7169 		DropMenu : function(id, s) {
       
  7170 			s = s || {};
       
  7171 			s.container = s.container || DOM.doc.body;
       
  7172 			s.offset_x = s.offset_x || 0;
       
  7173 			s.offset_y = s.offset_y || 0;
       
  7174 			s.vp_offset_x = s.vp_offset_x || 0;
       
  7175 			s.vp_offset_y = s.vp_offset_y || 0;
       
  7176 
       
  7177 			if (is(s.icons) && !s.icons)
       
  7178 				s['class'] += ' mceNoIcons';
       
  7179 
       
  7180 			this.parent(id, s);
       
  7181 			this.onShowMenu = new tinymce.util.Dispatcher(this);
       
  7182 			this.onHideMenu = new tinymce.util.Dispatcher(this);
       
  7183 			this.classPrefix = 'mceMenu';
       
  7184 		},
       
  7185 
       
  7186 		createMenu : function(s) {
       
  7187 			var t = this, cs = t.settings, m;
       
  7188 
       
  7189 			s.container = s.container || cs.container;
       
  7190 			s.parent = t;
       
  7191 			s.constrain = s.constrain || cs.constrain;
       
  7192 			s['class'] = s['class'] || cs['class'];
       
  7193 			s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;
       
  7194 			s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;
       
  7195 			m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);
       
  7196 
       
  7197 			m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);
       
  7198 
       
  7199 			return m;
       
  7200 		},
       
  7201 
       
  7202 		update : function() {
       
  7203 			var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
       
  7204 
       
  7205 			tw = s.max_width ? Math.min(tb.clientWidth, s.max_width) : tb.clientWidth;
       
  7206 			th = s.max_height ? Math.min(tb.clientHeight, s.max_height) : tb.clientHeight;
       
  7207 
       
  7208 			if (!DOM.boxModel)
       
  7209 				t.element.setStyles({width : tw + 2, height : th + 2});
       
  7210 			else
       
  7211 				t.element.setStyles({width : tw, height : th});
       
  7212 
       
  7213 			if (s.max_width)
       
  7214 				DOM.setStyle(co, 'width', tw);
       
  7215 
       
  7216 			if (s.max_height) {
       
  7217 				DOM.setStyle(co, 'height', th);
       
  7218 
       
  7219 				if (tb.clientHeight < s.max_height)
       
  7220 					DOM.setStyle(co, 'overflow', 'hidden');
       
  7221 			}
       
  7222 		},
       
  7223 
       
  7224 		showMenu : function(x, y, px) {
       
  7225 			var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;
       
  7226 
       
  7227 			t.collapse(1);
       
  7228 
       
  7229 			if (t.isMenuVisible)
       
  7230 				return;
       
  7231 
       
  7232 			if (!t.rendered) {
       
  7233 				co = DOM.add(t.settings.container, t.renderNode());
       
  7234 
       
  7235 				each(t.items, function(o) {
       
  7236 					o.postRender();
       
  7237 				});
       
  7238 
       
  7239 				t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
       
  7240 			} else
       
  7241 				co = DOM.get('menu_' + t.id);
       
  7242 
       
  7243 			// Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
       
  7244 			if (!tinymce.isOpera)
       
  7245 				DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});
       
  7246 
       
  7247 			DOM.show(co);
       
  7248 			t.update();
       
  7249 
       
  7250 			x += s.offset_x || 0;
       
  7251 			y += s.offset_y || 0;
       
  7252 			vp.w -= 4;
       
  7253 			vp.h -= 4;
       
  7254 
       
  7255 			// Move inside viewport if not submenu
       
  7256 			if (s.constrain) {
       
  7257 				w = co.clientWidth - ot;
       
  7258 				h = co.clientHeight - ot;
       
  7259 				mx = vp.x + vp.w;
       
  7260 				my = vp.y + vp.h;
       
  7261 
       
  7262 				if ((x + s.vp_offset_x + w) > mx)
       
  7263 					x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);
       
  7264 
       
  7265 				if ((y + s.vp_offset_y + h) > my)
       
  7266 					y = Math.max(0, (my - s.vp_offset_y) - h);
       
  7267 			}
       
  7268 
       
  7269 			DOM.setStyles(co, {left : x , top : y});
       
  7270 			t.element.update();
       
  7271 
       
  7272 			t.isMenuVisible = 1;
       
  7273 			t.mouseClickFunc = Event.add(co, 'click', function(e) {
       
  7274 				var m;
       
  7275 
       
  7276 				e = e.target;
       
  7277 
       
  7278 				if (e && (e = DOM.getParent(e, 'tr')) && !DOM.hasClass(e, cp + 'ItemSub')) {
       
  7279 					m = t.items[e.id];
       
  7280 
       
  7281 					if (m.isDisabled())
       
  7282 						return;
       
  7283 
       
  7284 					dm = t;
       
  7285 
       
  7286 					while (dm) {
       
  7287 						if (dm.hideMenu)
       
  7288 							dm.hideMenu();
       
  7289 
       
  7290 						dm = dm.settings.parent;
       
  7291 					}
       
  7292 
       
  7293 					if (m.settings.onclick)
       
  7294 						m.settings.onclick(e);
       
  7295 
       
  7296 					return Event.cancel(e); // Cancel to fix onbeforeunload problem
       
  7297 				}
       
  7298 			});
       
  7299 
       
  7300 			if (t.hasMenus()) {
       
  7301 				t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {
       
  7302 					var m, r, mi;
       
  7303 
       
  7304 					e = e.target;
       
  7305 					if (e && (e = DOM.getParent(e, 'tr'))) {
       
  7306 						m = t.items[e.id];
       
  7307 
       
  7308 						if (t.lastMenu)
       
  7309 							t.lastMenu.collapse(1);
       
  7310 
       
  7311 						if (m.isDisabled())
       
  7312 							return;
       
  7313 
       
  7314 						if (e && DOM.hasClass(e, cp + 'ItemSub')) {
       
  7315 							//p = DOM.getPos(s.container);
       
  7316 							r = DOM.getRect(e);
       
  7317 							m.showMenu((r.x + r.w - ot), r.y - ot, r.x);
       
  7318 							t.lastMenu = m;
       
  7319 							DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');
       
  7320 						}
       
  7321 					}
       
  7322 				});
       
  7323 			}
       
  7324 
       
  7325 			t.onShowMenu.dispatch(t);
       
  7326 
       
  7327 			if (s.keyboard_focus) {
       
  7328 				Event.add(co, 'keydown', t._keyHandler, t);
       
  7329 				DOM.select('a', 'menu_' + t.id)[0].focus(); // Select first link
       
  7330 				t._focusIdx = 0;
       
  7331 			}
       
  7332 		},
       
  7333 
       
  7334 		hideMenu : function(c) {
       
  7335 			var t = this, co = DOM.get('menu_' + t.id), e;
       
  7336 
       
  7337 			if (!t.isMenuVisible)
       
  7338 				return;
       
  7339 
       
  7340 			Event.remove(co, 'mouseover', t.mouseOverFunc);
       
  7341 			Event.remove(co, 'click', t.mouseClickFunc);
       
  7342 			Event.remove(co, 'keydown', t._keyHandler);
       
  7343 			DOM.hide(co);
       
  7344 			t.isMenuVisible = 0;
       
  7345 
       
  7346 			if (!c)
       
  7347 				t.collapse(1);
       
  7348 
       
  7349 			if (t.element)
       
  7350 				t.element.hide();
       
  7351 
       
  7352 			if (e = DOM.get(t.id))
       
  7353 				DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');
       
  7354 
       
  7355 			t.onHideMenu.dispatch(t);
       
  7356 		},
       
  7357 
       
  7358 		add : function(o) {
       
  7359 			var t = this, co;
       
  7360 
       
  7361 			o = t.parent(o);
       
  7362 
       
  7363 			if (t.isRendered && (co = DOM.get('menu_' + t.id)))
       
  7364 				t._add(DOM.select('tbody', co)[0], o);
       
  7365 
       
  7366 			return o;
       
  7367 		},
       
  7368 
       
  7369 		collapse : function(d) {
       
  7370 			this.parent(d);
       
  7371 			this.hideMenu(1);
       
  7372 		},
       
  7373 
       
  7374 		remove : function(o) {
       
  7375 			DOM.remove(o.id);
       
  7376 			this.destroy();
       
  7377 
       
  7378 			return this.parent(o);
       
  7379 		},
       
  7380 
       
  7381 		destroy : function() {
       
  7382 			var t = this, co = DOM.get('menu_' + t.id);
       
  7383 
       
  7384 			Event.remove(co, 'mouseover', t.mouseOverFunc);
       
  7385 			Event.remove(co, 'click', t.mouseClickFunc);
       
  7386 
       
  7387 			if (t.element)
       
  7388 				t.element.remove();
       
  7389 
       
  7390 			DOM.remove(co);
       
  7391 		},
       
  7392 
       
  7393 		renderNode : function() {
       
  7394 			var t = this, s = t.settings, n, tb, co, w;
       
  7395 
       
  7396 			w = DOM.create('div', {id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000'});
       
  7397 			co = DOM.add(w, 'div', {id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});
       
  7398 			t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
       
  7399 
       
  7400 			if (s.menu_line)
       
  7401 				DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});
       
  7402 
       
  7403 //			n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
       
  7404 			n = DOM.add(co, 'table', {id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});
       
  7405 			tb = DOM.add(n, 'tbody');
       
  7406 
       
  7407 			each(t.items, function(o) {
       
  7408 				t._add(tb, o);
       
  7409 			});
       
  7410 
       
  7411 			t.rendered = true;
       
  7412 
       
  7413 			return w;
       
  7414 		},
       
  7415 
       
  7416 		// Internal functions
       
  7417 
       
  7418 		_keyHandler : function(e) {
       
  7419 			var t = this, kc = e.keyCode;
       
  7420 
       
  7421 			function focus(d) {
       
  7422 				var i = t._focusIdx + d, e = DOM.select('a', 'menu_' + t.id)[i];
       
  7423 
       
  7424 				if (e) {
       
  7425 					t._focusIdx = i;
       
  7426 					e.focus();
       
  7427 				}
       
  7428 			};
       
  7429 
       
  7430 			switch (kc) {
       
  7431 				case 38:
       
  7432 					focus(-1); // Select first link
       
  7433 					return;
       
  7434 
       
  7435 				case 40:
       
  7436 					focus(1);
       
  7437 					return;
       
  7438 
       
  7439 				case 13:
       
  7440 					return;
       
  7441 
       
  7442 				case 27:
       
  7443 					return this.hideMenu();
       
  7444 			}
       
  7445 		},
       
  7446 
       
  7447 		_add : function(tb, o) {
       
  7448 			var n, s = o.settings, a, ro, it, cp = this.classPrefix, ic;
       
  7449 
       
  7450 			if (s.separator) {
       
  7451 				ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});
       
  7452 				DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});
       
  7453 
       
  7454 				if (n = ro.previousSibling)
       
  7455 					DOM.addClass(n, 'mceLast');
       
  7456 
       
  7457 				return;
       
  7458 			}
       
  7459 
       
  7460 			n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});
       
  7461 			n = it = DOM.add(n, 'td');
       
  7462 			n = a = DOM.add(n, 'a', {href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});
       
  7463 
       
  7464 			DOM.addClass(it, s['class']);
       
  7465 //			n = DOM.add(n, 'span', {'class' : 'item'});
       
  7466 
       
  7467 			ic = DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});
       
  7468 
       
  7469 			if (s.icon_src)
       
  7470 				DOM.add(ic, 'img', {src : s.icon_src});
       
  7471 
       
  7472 			n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);
       
  7473 
       
  7474 			if (o.settings.style)
       
  7475 				DOM.setAttrib(n, 'style', o.settings.style);
       
  7476 
       
  7477 			if (tb.childNodes.length == 1)
       
  7478 				DOM.addClass(ro, 'mceFirst');
       
  7479 
       
  7480 			if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))
       
  7481 				DOM.addClass(ro, 'mceFirst');
       
  7482 
       
  7483 			if (o.collapse)
       
  7484 				DOM.addClass(ro, cp + 'ItemSub');
       
  7485 
       
  7486 			if (n = ro.previousSibling)
       
  7487 				DOM.removeClass(n, 'mceLast');
       
  7488 
       
  7489 			DOM.addClass(ro, 'mceLast');
       
  7490 		}
       
  7491 	});
       
  7492 })(tinymce);(function(tinymce) {
       
  7493 	var DOM = tinymce.DOM;
       
  7494 
       
  7495 	tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {
       
  7496 		Button : function(id, s) {
       
  7497 			this.parent(id, s);
       
  7498 			this.classPrefix = 'mceButton';
       
  7499 		},
       
  7500 
       
  7501 		renderHTML : function() {
       
  7502 			var cp = this.classPrefix, s = this.settings, h, l;
       
  7503 
       
  7504 			l = DOM.encode(s.label || '');
       
  7505 			h = '<a id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + (l ? ' ' + cp + 'Labeled' : '') +'" onmousedown="return false;" onclick="return false;" title="' + DOM.encode(s.title) + '">';
       
  7506 
       
  7507 			if (s.image)
       
  7508 				h += '<img class="mceIcon" src="' + s.image + '" />' + l + '</a>';
       
  7509 			else
       
  7510 				h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '') + '</a>';
       
  7511 
       
  7512 			return h;
       
  7513 		},
       
  7514 
       
  7515 		postRender : function() {
       
  7516 			var t = this, s = t.settings;
       
  7517 
       
  7518 			tinymce.dom.Event.add(t.id, 'click', function(e) {
       
  7519 				if (!t.isDisabled())
       
  7520 					return s.onclick.call(s.scope, e);
       
  7521 			});
       
  7522 		}
       
  7523 	});
       
  7524 })(tinymce);
       
  7525 (function(tinymce) {
       
  7526 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
       
  7527 
       
  7528 	tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {
       
  7529 		ListBox : function(id, s) {
       
  7530 			var t = this;
       
  7531 
       
  7532 			t.parent(id, s);
       
  7533 
       
  7534 			t.items = [];
       
  7535 
       
  7536 			t.onChange = new Dispatcher(t);
       
  7537 
       
  7538 			t.onPostRender = new Dispatcher(t);
       
  7539 
       
  7540 			t.onAdd = new Dispatcher(t);
       
  7541 
       
  7542 			t.onRenderMenu = new tinymce.util.Dispatcher(this);
       
  7543 
       
  7544 			t.classPrefix = 'mceListBox';
       
  7545 		},
       
  7546 
       
  7547 		select : function(va) {
       
  7548 			var t = this, fv, f;
       
  7549 
       
  7550 			if (va == undefined)
       
  7551 				return t.selectByIndex(-1);
       
  7552 
       
  7553 			// Is string or number make function selector
       
  7554 			if (va && va.call)
       
  7555 				f = va;
       
  7556 			else {
       
  7557 				f = function(v) {
       
  7558 					return v == va;
       
  7559 				};
       
  7560 			}
       
  7561 
       
  7562 			// Do we need to do something?
       
  7563 			if (va != t.selectedValue) {
       
  7564 				// Find item
       
  7565 				each(t.items, function(o, i) {
       
  7566 					if (f(o.value)) {
       
  7567 						fv = 1;
       
  7568 						t.selectByIndex(i);
       
  7569 						return false;
       
  7570 					}
       
  7571 				});
       
  7572 
       
  7573 				if (!fv)
       
  7574 					t.selectByIndex(-1);
       
  7575 			}
       
  7576 		},
       
  7577 
       
  7578 		selectByIndex : function(idx) {
       
  7579 			var t = this, e, o;
       
  7580 
       
  7581 			if (idx != t.selectedIndex) {
       
  7582 				e = DOM.get(t.id + '_text');
       
  7583 				o = t.items[idx];
       
  7584 
       
  7585 				if (o) {
       
  7586 					t.selectedValue = o.value;
       
  7587 					t.selectedIndex = idx;
       
  7588 					DOM.setHTML(e, DOM.encode(o.title));
       
  7589 					DOM.removeClass(e, 'mceTitle');
       
  7590 				} else {
       
  7591 					DOM.setHTML(e, DOM.encode(t.settings.title));
       
  7592 					DOM.addClass(e, 'mceTitle');
       
  7593 					t.selectedValue = t.selectedIndex = null;
       
  7594 				}
       
  7595 
       
  7596 				e = 0;
       
  7597 			}
       
  7598 		},
       
  7599 
       
  7600 		add : function(n, v, o) {
       
  7601 			var t = this;
       
  7602 
       
  7603 			o = o || {};
       
  7604 			o = tinymce.extend(o, {
       
  7605 				title : n,
       
  7606 				value : v
       
  7607 			});
       
  7608 
       
  7609 			t.items.push(o);
       
  7610 			t.onAdd.dispatch(t, o);
       
  7611 		},
       
  7612 
       
  7613 		getLength : function() {
       
  7614 			return this.items.length;
       
  7615 		},
       
  7616 
       
  7617 		renderHTML : function() {
       
  7618 			var h = '', t = this, s = t.settings, cp = t.classPrefix;
       
  7619 
       
  7620 			h = '<table id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';
       
  7621 			h += '<td>' + DOM.createHTML('a', {id : t.id + '_text', href : 'javascript:;', 'class' : 'mceText', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '</td>';
       
  7622 			h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span></span>') + '</td>';
       
  7623 			h += '</tr></tbody></table>';
       
  7624 
       
  7625 			return h;
       
  7626 		},
       
  7627 
       
  7628 		showMenu : function() {
       
  7629 			var t = this, p1, p2, e = DOM.get(this.id), m;
       
  7630 
       
  7631 			if (t.isDisabled() || t.items.length == 0)
       
  7632 				return;
       
  7633 
       
  7634 			if (t.menu && t.menu.isMenuVisible)
       
  7635 				return t.hideMenu();
       
  7636 
       
  7637 			if (!t.isMenuRendered) {
       
  7638 				t.renderMenu();
       
  7639 				t.isMenuRendered = true;
       
  7640 			}
       
  7641 
       
  7642 			p1 = DOM.getPos(this.settings.menu_container);
       
  7643 			p2 = DOM.getPos(e);
       
  7644 
       
  7645 			m = t.menu;
       
  7646 			m.settings.offset_x = p2.x;
       
  7647 			m.settings.offset_y = p2.y;
       
  7648 			m.settings.keyboard_focus = !tinymce.isOpera; // Opera is buggy when it comes to auto focus
       
  7649 
       
  7650 			// Select in menu
       
  7651 			if (t.oldID)
       
  7652 				m.items[t.oldID].setSelected(0);
       
  7653 
       
  7654 			each(t.items, function(o) {
       
  7655 				if (o.value === t.selectedValue) {
       
  7656 					m.items[o.id].setSelected(1);
       
  7657 					t.oldID = o.id;
       
  7658 				}
       
  7659 			});
       
  7660 
       
  7661 			m.showMenu(0, e.clientHeight);
       
  7662 
       
  7663 			Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
       
  7664 			DOM.addClass(t.id, t.classPrefix + 'Selected');
       
  7665 
       
  7666 			//DOM.get(t.id + '_text').focus();
       
  7667 		},
       
  7668 
       
  7669 		hideMenu : function(e) {
       
  7670 			var t = this;
       
  7671 
       
  7672 			// Prevent double toogles by canceling the mouse click event to the button
       
  7673 			if (e && e.type == "mousedown" && (e.target.id == t.id + '_text' || e.target.id == t.id + '_open'))
       
  7674 				return;
       
  7675 
       
  7676 			if (!e || !DOM.getParent(e.target, '.mceMenu')) {
       
  7677 				DOM.removeClass(t.id, t.classPrefix + 'Selected');
       
  7678 				Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
       
  7679 
       
  7680 				if (t.menu)
       
  7681 					t.menu.hideMenu();
       
  7682 			}
       
  7683 		},
       
  7684 
       
  7685 		renderMenu : function() {
       
  7686 			var t = this, m;
       
  7687 
       
  7688 			m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
       
  7689 				menu_line : 1,
       
  7690 				'class' : t.classPrefix + 'Menu mceNoIcons',
       
  7691 				max_width : 150,
       
  7692 				max_height : 150
       
  7693 			});
       
  7694 
       
  7695 			m.onHideMenu.add(t.hideMenu, t);
       
  7696 
       
  7697 			m.add({
       
  7698 				title : t.settings.title,
       
  7699 				'class' : 'mceMenuItemTitle',
       
  7700 				onclick : function() {
       
  7701 					if (t.settings.onselect('') !== false)
       
  7702 						t.select(''); // Must be runned after
       
  7703 				}
       
  7704 			});
       
  7705 
       
  7706 			each(t.items, function(o) {
       
  7707 				o.id = DOM.uniqueId();
       
  7708 				o.onclick = function() {
       
  7709 					if (t.settings.onselect(o.value) !== false)
       
  7710 						t.select(o.value); // Must be runned after
       
  7711 				};
       
  7712 
       
  7713 				m.add(o);
       
  7714 			});
       
  7715 
       
  7716 			t.onRenderMenu.dispatch(t, m);
       
  7717 			t.menu = m;
       
  7718 		},
       
  7719 
       
  7720 		postRender : function() {
       
  7721 			var t = this, cp = t.classPrefix;
       
  7722 
       
  7723 			Event.add(t.id, 'click', t.showMenu, t);
       
  7724 			Event.add(t.id + '_text', 'focus', function(e) {
       
  7725 				if (!t._focused) {
       
  7726 					t.keyDownHandler = Event.add(t.id + '_text', 'keydown', function(e) {
       
  7727 						var idx = -1, v, kc = e.keyCode;
       
  7728 
       
  7729 						// Find current index
       
  7730 						each(t.items, function(v, i) {
       
  7731 							if (t.selectedValue == v.value)
       
  7732 								idx = i;
       
  7733 						});
       
  7734 
       
  7735 						// Move up/down
       
  7736 						if (kc == 38)
       
  7737 							v = t.items[idx - 1];
       
  7738 						else if (kc == 40)
       
  7739 							v = t.items[idx + 1];
       
  7740 						else if (kc == 13) {
       
  7741 							// Fake select on enter
       
  7742 							v = t.selectedValue;
       
  7743 							t.selectedValue = null; // Needs to be null to fake change
       
  7744 							t.settings.onselect(v);
       
  7745 							return Event.cancel(e);
       
  7746 						}
       
  7747 
       
  7748 						if (v) {
       
  7749 							t.hideMenu();
       
  7750 							t.select(v.value);
       
  7751 						}
       
  7752 					});
       
  7753 				}
       
  7754 
       
  7755 				t._focused = 1;
       
  7756 			});
       
  7757 			Event.add(t.id + '_text', 'blur', function() {Event.remove(t.id + '_text', 'keydown', t.keyDownHandler); t._focused = 0;});
       
  7758 
       
  7759 			// Old IE doesn't have hover on all elements
       
  7760 			if (tinymce.isIE6 || !DOM.boxModel) {
       
  7761 				Event.add(t.id, 'mouseover', function() {
       
  7762 					if (!DOM.hasClass(t.id, cp + 'Disabled'))
       
  7763 						DOM.addClass(t.id, cp + 'Hover');
       
  7764 				});
       
  7765 
       
  7766 				Event.add(t.id, 'mouseout', function() {
       
  7767 					if (!DOM.hasClass(t.id, cp + 'Disabled'))
       
  7768 						DOM.removeClass(t.id, cp + 'Hover');
       
  7769 				});
       
  7770 			}
       
  7771 
       
  7772 			t.onPostRender.dispatch(t, DOM.get(t.id));
       
  7773 		},
       
  7774 
       
  7775 		destroy : function() {
       
  7776 			this.parent();
       
  7777 
       
  7778 			Event.clear(this.id + '_text');
       
  7779 			Event.clear(this.id + '_open');
       
  7780 		}
       
  7781 	});
       
  7782 })(tinymce);(function(tinymce) {
       
  7783 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
       
  7784 
       
  7785 	tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {
       
  7786 		NativeListBox : function(id, s) {
       
  7787 			this.parent(id, s);
       
  7788 			this.classPrefix = 'mceNativeListBox';
       
  7789 		},
       
  7790 
       
  7791 		setDisabled : function(s) {
       
  7792 			DOM.get(this.id).disabled = s;
       
  7793 		},
       
  7794 
       
  7795 		isDisabled : function() {
       
  7796 			return DOM.get(this.id).disabled;
       
  7797 		},
       
  7798 
       
  7799 		select : function(va) {
       
  7800 			var t = this, fv, f;
       
  7801 
       
  7802 			if (va == undefined)
       
  7803 				return t.selectByIndex(-1);
       
  7804 
       
  7805 			// Is string or number make function selector
       
  7806 			if (va && va.call)
       
  7807 				f = va;
       
  7808 			else {
       
  7809 				f = function(v) {
       
  7810 					return v == va;
       
  7811 				};
       
  7812 			}
       
  7813 
       
  7814 			// Do we need to do something?
       
  7815 			if (va != t.selectedValue) {
       
  7816 				// Find item
       
  7817 				each(t.items, function(o, i) {
       
  7818 					if (f(o.value)) {
       
  7819 						fv = 1;
       
  7820 						t.selectByIndex(i);
       
  7821 						return false;
       
  7822 					}
       
  7823 				});
       
  7824 
       
  7825 				if (!fv)
       
  7826 					t.selectByIndex(-1);
       
  7827 			}
       
  7828 		},
       
  7829 
       
  7830 		selectByIndex : function(idx) {
       
  7831 			DOM.get(this.id).selectedIndex = idx + 1;
       
  7832 			this.selectedValue = this.items[idx] ? this.items[idx].value : null;
       
  7833 		},
       
  7834 
       
  7835 		add : function(n, v, a) {
       
  7836 			var o, t = this;
       
  7837 
       
  7838 			a = a || {};
       
  7839 			a.value = v;
       
  7840 
       
  7841 			if (t.isRendered())
       
  7842 				DOM.add(DOM.get(this.id), 'option', a, n);
       
  7843 
       
  7844 			o = {
       
  7845 				title : n,
       
  7846 				value : v,
       
  7847 				attribs : a
       
  7848 			};
       
  7849 
       
  7850 			t.items.push(o);
       
  7851 			t.onAdd.dispatch(t, o);
       
  7852 		},
       
  7853 
       
  7854 		getLength : function() {
       
  7855 			return DOM.get(this.id).options.length - 1;
       
  7856 		},
       
  7857 
       
  7858 		renderHTML : function() {
       
  7859 			var h, t = this;
       
  7860 
       
  7861 			h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');
       
  7862 
       
  7863 			each(t.items, function(it) {
       
  7864 				h += DOM.createHTML('option', {value : it.value}, it.title);
       
  7865 			});
       
  7866 
       
  7867 			h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox'}, h);
       
  7868 
       
  7869 			return h;
       
  7870 		},
       
  7871 
       
  7872 		postRender : function() {
       
  7873 			var t = this, ch;
       
  7874 
       
  7875 			t.rendered = true;
       
  7876 
       
  7877 			function onChange(e) {
       
  7878 				var v = t.items[e.target.selectedIndex - 1];
       
  7879 
       
  7880 				if (v && (v = v.value)) {
       
  7881 					t.onChange.dispatch(t, v);
       
  7882 
       
  7883 					if (t.settings.onselect)
       
  7884 						t.settings.onselect(v);
       
  7885 				}
       
  7886 			};
       
  7887 
       
  7888 			Event.add(t.id, 'change', onChange);
       
  7889 
       
  7890 			// Accessibility keyhandler
       
  7891 			Event.add(t.id, 'keydown', function(e) {
       
  7892 				var bf;
       
  7893 
       
  7894 				Event.remove(t.id, 'change', ch);
       
  7895 
       
  7896 				bf = Event.add(t.id, 'blur', function() {
       
  7897 					Event.add(t.id, 'change', onChange);
       
  7898 					Event.remove(t.id, 'blur', bf);
       
  7899 				});
       
  7900 
       
  7901 				if (e.keyCode == 13 || e.keyCode == 32) {
       
  7902 					onChange(e);
       
  7903 					return Event.cancel(e);
       
  7904 				}
       
  7905 			});
       
  7906 
       
  7907 			t.onPostRender.dispatch(t, DOM.get(t.id));
       
  7908 		}
       
  7909 	});
       
  7910 })(tinymce);(function(tinymce) {
       
  7911 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
       
  7912 
       
  7913 	tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {
       
  7914 		MenuButton : function(id, s) {
       
  7915 			this.parent(id, s);
       
  7916 
       
  7917 			this.onRenderMenu = new tinymce.util.Dispatcher(this);
       
  7918 
       
  7919 			s.menu_container = s.menu_container || DOM.doc.body;
       
  7920 		},
       
  7921 
       
  7922 		showMenu : function() {
       
  7923 			var t = this, p1, p2, e = DOM.get(t.id), m;
       
  7924 
       
  7925 			if (t.isDisabled())
       
  7926 				return;
       
  7927 
       
  7928 			if (!t.isMenuRendered) {
       
  7929 				t.renderMenu();
       
  7930 				t.isMenuRendered = true;
       
  7931 			}
       
  7932 
       
  7933 			if (t.isMenuVisible)
       
  7934 				return t.hideMenu();
       
  7935 
       
  7936 			p1 = DOM.getPos(t.settings.menu_container);
       
  7937 			p2 = DOM.getPos(e);
       
  7938 
       
  7939 			m = t.menu;
       
  7940 			m.settings.offset_x = p2.x;
       
  7941 			m.settings.offset_y = p2.y;
       
  7942 			m.settings.vp_offset_x = p2.x;
       
  7943 			m.settings.vp_offset_y = p2.y;
       
  7944 			m.settings.keyboard_focus = t._focused;
       
  7945 			m.showMenu(0, e.clientHeight);
       
  7946 
       
  7947 			Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
       
  7948 			t.setState('Selected', 1);
       
  7949 
       
  7950 			t.isMenuVisible = 1;
       
  7951 		},
       
  7952 
       
  7953 		renderMenu : function() {
       
  7954 			var t = this, m;
       
  7955 
       
  7956 			m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
       
  7957 				menu_line : 1,
       
  7958 				'class' : this.classPrefix + 'Menu',
       
  7959 				icons : t.settings.icons
       
  7960 			});
       
  7961 
       
  7962 			m.onHideMenu.add(t.hideMenu, t);
       
  7963 
       
  7964 			t.onRenderMenu.dispatch(t, m);
       
  7965 			t.menu = m;
       
  7966 		},
       
  7967 
       
  7968 		hideMenu : function(e) {
       
  7969 			var t = this;
       
  7970 
       
  7971 			// Prevent double toogles by canceling the mouse click event to the button
       
  7972 			if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id || e.id === t.id + '_open';}))
       
  7973 				return;
       
  7974 
       
  7975 			if (!e || !DOM.getParent(e.target, '.mceMenu')) {
       
  7976 				t.setState('Selected', 0);
       
  7977 				Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
       
  7978 				if (t.menu)
       
  7979 					t.menu.hideMenu();
       
  7980 			}
       
  7981 
       
  7982 			t.isMenuVisible = 0;
       
  7983 		},
       
  7984 
       
  7985 		postRender : function() {
       
  7986 			var t = this, s = t.settings;
       
  7987 
       
  7988 			Event.add(t.id, 'click', function() {
       
  7989 				if (!t.isDisabled()) {
       
  7990 					if (s.onclick)
       
  7991 						s.onclick(t.value);
       
  7992 
       
  7993 					t.showMenu();
       
  7994 				}
       
  7995 			});
       
  7996 		}
       
  7997 	});
       
  7998 })(tinymce);
       
  7999 (function(tinymce) {
       
  8000 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
       
  8001 
       
  8002 	tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {
       
  8003 		SplitButton : function(id, s) {
       
  8004 			this.parent(id, s);
       
  8005 			this.classPrefix = 'mceSplitButton';
       
  8006 		},
       
  8007 
       
  8008 		renderHTML : function() {
       
  8009 			var h, t = this, s = t.settings, h1;
       
  8010 
       
  8011 			h = '<tbody><tr>';
       
  8012 
       
  8013 			if (s.image)
       
  8014 				h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'mceAction ' + s['class']});
       
  8015 			else
       
  8016 				h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');
       
  8017 
       
  8018 			h += '<td>' + DOM.createHTML('a', {id : t.id + '_action', href : 'javascript:;', 'class' : 'mceAction ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
       
  8019 	
       
  8020 			h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']});
       
  8021 			h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'mceOpen ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
       
  8022 
       
  8023 			h += '</tr></tbody>';
       
  8024 
       
  8025 			return DOM.createHTML('table', {id : t.id, 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', onmousedown : 'return false;', title : s.title}, h);
       
  8026 		},
       
  8027 
       
  8028 		postRender : function() {
       
  8029 			var t = this, s = t.settings;
       
  8030 
       
  8031 			if (s.onclick) {
       
  8032 				Event.add(t.id + '_action', 'click', function() {
       
  8033 					if (!t.isDisabled())
       
  8034 						s.onclick(t.value);
       
  8035 				});
       
  8036 			}
       
  8037 
       
  8038 			Event.add(t.id + '_open', 'click', t.showMenu, t);
       
  8039 			Event.add(t.id + '_open', 'focus', function() {t._focused = 1;});
       
  8040 			Event.add(t.id + '_open', 'blur', function() {t._focused = 0;});
       
  8041 
       
  8042 			// Old IE doesn't have hover on all elements
       
  8043 			if (tinymce.isIE6 || !DOM.boxModel) {
       
  8044 				Event.add(t.id, 'mouseover', function() {
       
  8045 					if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
       
  8046 						DOM.addClass(t.id, 'mceSplitButtonHover');
       
  8047 				});
       
  8048 
       
  8049 				Event.add(t.id, 'mouseout', function() {
       
  8050 					if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
       
  8051 						DOM.removeClass(t.id, 'mceSplitButtonHover');
       
  8052 				});
       
  8053 			}
       
  8054 		},
       
  8055 
       
  8056 		destroy : function() {
       
  8057 			this.parent();
       
  8058 
       
  8059 			Event.clear(this.id + '_action');
       
  8060 			Event.clear(this.id + '_open');
       
  8061 		}
       
  8062 	});
       
  8063 })(tinymce);
       
  8064 (function(tinymce) {
       
  8065 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
       
  8066 
       
  8067 	tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
       
  8068 		ColorSplitButton : function(id, s) {
       
  8069 			var t = this;
       
  8070 
       
  8071 			t.parent(id, s);
       
  8072 
       
  8073 			t.settings = s = tinymce.extend({
       
  8074 				colors : '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF',
       
  8075 				grid_width : 8,
       
  8076 				default_color : '#888888'
       
  8077 			}, t.settings);
       
  8078 
       
  8079 			t.onShowMenu = new tinymce.util.Dispatcher(t);
       
  8080 
       
  8081 			t.onHideMenu = new tinymce.util.Dispatcher(t);
       
  8082 
       
  8083 			t.value = s.default_color;
       
  8084 		},
       
  8085 
       
  8086 		showMenu : function() {
       
  8087 			var t = this, r, p, e, p2;
       
  8088 
       
  8089 			if (t.isDisabled())
       
  8090 				return;
       
  8091 
       
  8092 			if (!t.isMenuRendered) {
       
  8093 				t.renderMenu();
       
  8094 				t.isMenuRendered = true;
       
  8095 			}
       
  8096 
       
  8097 			if (t.isMenuVisible)
       
  8098 				return t.hideMenu();
       
  8099 
       
  8100 			e = DOM.get(t.id);
       
  8101 			DOM.show(t.id + '_menu');
       
  8102 			DOM.addClass(e, 'mceSplitButtonSelected');
       
  8103 			p2 = DOM.getPos(e);
       
  8104 			DOM.setStyles(t.id + '_menu', {
       
  8105 				left : p2.x,
       
  8106 				top : p2.y + e.clientHeight,
       
  8107 				zIndex : 200000
       
  8108 			});
       
  8109 			e = 0;
       
  8110 
       
  8111 			Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
       
  8112 			t.onShowMenu.dispatch(t);
       
  8113 
       
  8114 			if (t._focused) {
       
  8115 				t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
       
  8116 					if (e.keyCode == 27)
       
  8117 						t.hideMenu();
       
  8118 				});
       
  8119 
       
  8120 				DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
       
  8121 			}
       
  8122 
       
  8123 			t.isMenuVisible = 1;
       
  8124 		},
       
  8125 
       
  8126 		hideMenu : function(e) {
       
  8127 			var t = this;
       
  8128 
       
  8129 			// Prevent double toogles by canceling the mouse click event to the button
       
  8130 			if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))
       
  8131 				return;
       
  8132 
       
  8133 			if (!e || !DOM.getParent(e.target, '.mceSplitButtonMenu')) {
       
  8134 				DOM.removeClass(t.id, 'mceSplitButtonSelected');
       
  8135 				Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
       
  8136 				Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
       
  8137 				DOM.hide(t.id + '_menu');
       
  8138 			}
       
  8139 
       
  8140 			t.onHideMenu.dispatch(t);
       
  8141 
       
  8142 			t.isMenuVisible = 0;
       
  8143 		},
       
  8144 
       
  8145 		renderMenu : function() {
       
  8146 			var t = this, m, i = 0, s = t.settings, n, tb, tr, w;
       
  8147 
       
  8148 			w = DOM.add(s.menu_container, 'div', {id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
       
  8149 			m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
       
  8150 			DOM.add(m, 'span', {'class' : 'mceMenuLine'});
       
  8151 
       
  8152 			n = DOM.add(m, 'table', {'class' : 'mceColorSplitMenu'});
       
  8153 			tb = DOM.add(n, 'tbody');
       
  8154 
       
  8155 			// Generate color grid
       
  8156 			i = 0;
       
  8157 			each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
       
  8158 				c = c.replace(/^#/, '');
       
  8159 
       
  8160 				if (!i--) {
       
  8161 					tr = DOM.add(tb, 'tr');
       
  8162 					i = s.grid_width - 1;
       
  8163 				}
       
  8164 
       
  8165 				n = DOM.add(tr, 'td');
       
  8166 
       
  8167 				n = DOM.add(n, 'a', {
       
  8168 					href : 'javascript:;',
       
  8169 					style : {
       
  8170 						backgroundColor : '#' + c
       
  8171 					},
       
  8172 					mce_color : '#' + c
       
  8173 				});
       
  8174 			});
       
  8175 
       
  8176 			if (s.more_colors_func) {
       
  8177 				n = DOM.add(tb, 'tr');
       
  8178 				n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
       
  8179 				n = DOM.add(n, 'a', {id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
       
  8180 
       
  8181 				Event.add(n, 'click', function(e) {
       
  8182 					s.more_colors_func.call(s.more_colors_scope || this);
       
  8183 					return Event.cancel(e); // Cancel to fix onbeforeunload problem
       
  8184 				});
       
  8185 			}
       
  8186 
       
  8187 			DOM.addClass(m, 'mceColorSplitMenu');
       
  8188 
       
  8189 			Event.add(t.id + '_menu', 'click', function(e) {
       
  8190 				var c;
       
  8191 
       
  8192 				e = e.target;
       
  8193 
       
  8194 				if (e.nodeName == 'A' && (c = e.getAttribute('mce_color')))
       
  8195 					t.setColor(c);
       
  8196 
       
  8197 				return Event.cancel(e); // Prevent IE auto save warning
       
  8198 			});
       
  8199 
       
  8200 			return w;
       
  8201 		},
       
  8202 
       
  8203 		setColor : function(c) {
       
  8204 			var t = this;
       
  8205 
       
  8206 			DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
       
  8207 
       
  8208 			t.value = c;
       
  8209 			t.hideMenu();
       
  8210 			t.settings.onselect(c);
       
  8211 		},
       
  8212 
       
  8213 		postRender : function() {
       
  8214 			var t = this, id = t.id;
       
  8215 
       
  8216 			t.parent();
       
  8217 			DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
       
  8218 			DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);
       
  8219 		},
       
  8220 
       
  8221 		destroy : function() {
       
  8222 			this.parent();
       
  8223 
       
  8224 			Event.clear(this.id + '_menu');
       
  8225 			Event.clear(this.id + '_more');
       
  8226 			DOM.remove(this.id + '_menu');
       
  8227 		}
       
  8228 	});
       
  8229 })(tinymce);
       
  8230 tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
       
  8231 	renderHTML : function() {
       
  8232 		var t = this, h = '', c, co, dom = tinymce.DOM, s = t.settings, i, pr, nx, cl;
       
  8233 
       
  8234 		cl = t.controls;
       
  8235 		for (i=0; i<cl.length; i++) {
       
  8236 			// Get current control, prev control, next control and if the control is a list box or not
       
  8237 			co = cl[i];
       
  8238 			pr = cl[i - 1];
       
  8239 			nx = cl[i + 1];
       
  8240 
       
  8241 			// Add toolbar start
       
  8242 			if (i === 0) {
       
  8243 				c = 'mceToolbarStart';
       
  8244 
       
  8245 				if (co.Button)
       
  8246 					c += ' mceToolbarStartButton';
       
  8247 				else if (co.SplitButton)
       
  8248 					c += ' mceToolbarStartSplitButton';
       
  8249 				else if (co.ListBox)
       
  8250 					c += ' mceToolbarStartListBox';
       
  8251 
       
  8252 				h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
       
  8253 			}
       
  8254 
       
  8255 			// Add toolbar end before list box and after the previous button
       
  8256 			// This is to fix the o2k7 editor skins
       
  8257 			if (pr && co.ListBox) {
       
  8258 				if (pr.Button || pr.SplitButton)
       
  8259 					h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));
       
  8260 			}
       
  8261 
       
  8262 			// Render control HTML
       
  8263 
       
  8264 			// IE 8 quick fix, needed to propertly generate a hit area for anchors
       
  8265 			if (dom.stdMode)
       
  8266 				h += '<td style="position: relative">' + co.renderHTML() + '</td>';
       
  8267 			else
       
  8268 				h += '<td>' + co.renderHTML() + '</td>';
       
  8269 
       
  8270 			// Add toolbar start after list box and before the next button
       
  8271 			// This is to fix the o2k7 editor skins
       
  8272 			if (nx && co.ListBox) {
       
  8273 				if (nx.Button || nx.SplitButton)
       
  8274 					h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));
       
  8275 			}
       
  8276 		}
       
  8277 
       
  8278 		c = 'mceToolbarEnd';
       
  8279 
       
  8280 		if (co.Button)
       
  8281 			c += ' mceToolbarEndButton';
       
  8282 		else if (co.SplitButton)
       
  8283 			c += ' mceToolbarEndSplitButton';
       
  8284 		else if (co.ListBox)
       
  8285 			c += ' mceToolbarEndListBox';
       
  8286 
       
  8287 		h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
       
  8288 
       
  8289 		return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || ''}, '<tbody><tr>' + h + '</tr></tbody>');
       
  8290 	}
       
  8291 });
       
  8292 (function(tinymce) {
       
  8293 	var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
       
  8294 
       
  8295 	tinymce.create('tinymce.AddOnManager', {
       
  8296 		items : [],
       
  8297 		urls : {},
       
  8298 		lookup : {},
       
  8299 
       
  8300 		onAdd : new Dispatcher(this),
       
  8301 
       
  8302 		get : function(n) {
       
  8303 			return this.lookup[n];
       
  8304 		},
       
  8305 
       
  8306 		requireLangPack : function(n) {
       
  8307 			var u, s = tinymce.EditorManager.settings;
       
  8308 
       
  8309 			if (s && s.language) {
       
  8310 				u = this.urls[n] + '/langs/' + s.language + '.js';
       
  8311 
       
  8312 				if (!tinymce.dom.Event.domLoaded && !s.strict_mode)
       
  8313 					tinymce.ScriptLoader.load(u);
       
  8314 				else
       
  8315 					tinymce.ScriptLoader.add(u);
       
  8316 			}
       
  8317 		},
       
  8318 
       
  8319 		add : function(id, o) {
       
  8320 			this.items.push(o);
       
  8321 			this.lookup[id] = o;
       
  8322 			this.onAdd.dispatch(this, id, o);
       
  8323 
       
  8324 			return o;
       
  8325 		},
       
  8326 
       
  8327 		load : function(n, u, cb, s) {
       
  8328 			var t = this;
       
  8329 
       
  8330 			if (t.urls[n])
       
  8331 				return;
       
  8332 
       
  8333 			if (u.indexOf('/') != 0 && u.indexOf('://') == -1)
       
  8334 				u = tinymce.baseURL + '/' +  u;
       
  8335 
       
  8336 			t.urls[n] = u.substring(0, u.lastIndexOf('/'));
       
  8337 			tinymce.ScriptLoader.add(u, cb, s);
       
  8338 		}
       
  8339 	});
       
  8340 
       
  8341 	// Create plugin and theme managers
       
  8342 	tinymce.PluginManager = new tinymce.AddOnManager();
       
  8343 	tinymce.ThemeManager = new tinymce.AddOnManager();
       
  8344 }(tinymce));
       
  8345 
       
  8346 (function(tinymce) {
       
  8347 	// Shorten names
       
  8348 	var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode;
       
  8349 
       
  8350 	tinymce.create('static tinymce.EditorManager', {
       
  8351 		editors : {},
       
  8352 
       
  8353 		i18n : {},
       
  8354 	
       
  8355 		activeEditor : null,
       
  8356 
       
  8357 		preInit : function() {
       
  8358 			var t = this, lo = window.location;
       
  8359 
       
  8360 			// Setup some URLs where the editor API is located and where the document is
       
  8361 			tinymce.documentBaseURL = lo.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
       
  8362 			if (!/[\/\\]$/.test(tinymce.documentBaseURL))
       
  8363 				tinymce.documentBaseURL += '/';
       
  8364 
       
  8365 			tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);
       
  8366 			tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL);
       
  8367 
       
  8368 			// Add before unload listener
       
  8369 			// This was required since IE was leaking memory if you added and removed beforeunload listeners
       
  8370 			// with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
       
  8371 			t.onBeforeUnload = new tinymce.util.Dispatcher(t);
       
  8372 
       
  8373 			// Must be on window or IE will leak if the editor is placed in frame or iframe
       
  8374 			Event.add(window, 'beforeunload', function(e) {
       
  8375 				t.onBeforeUnload.dispatch(t, e);
       
  8376 			});
       
  8377 		},
       
  8378 
       
  8379 		init : function(s) {
       
  8380 			var t = this, pl, sl = tinymce.ScriptLoader, c, e, el = [], ed;
       
  8381 
       
  8382 			function execCallback(se, n, s) {
       
  8383 				var f = se[n];
       
  8384 
       
  8385 				if (!f)
       
  8386 					return;
       
  8387 
       
  8388 				if (tinymce.is(f, 'string')) {
       
  8389 					s = f.replace(/\.\w+$/, '');
       
  8390 					s = s ? tinymce.resolve(s) : 0;
       
  8391 					f = tinymce.resolve(f);
       
  8392 				}
       
  8393 
       
  8394 				return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
       
  8395 			};
       
  8396 
       
  8397 			s = extend({
       
  8398 				theme : "simple",
       
  8399 				language : "en",
       
  8400 				strict_loading_mode : document.contentType == 'application/xhtml+xml'
       
  8401 			}, s);
       
  8402 
       
  8403 			t.settings = s;
       
  8404 
       
  8405 			// If page not loaded and strict mode isn't enabled then load them
       
  8406 			if (!Event.domLoaded && !s.strict_loading_mode) {
       
  8407 				// Load language
       
  8408 				if (s.language)
       
  8409 					sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
       
  8410 
       
  8411 				// Load theme
       
  8412 				if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
       
  8413 					ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
       
  8414 
       
  8415 				// Load plugins
       
  8416 				if (s.plugins) {
       
  8417 					pl = explode(s.plugins);
       
  8418 
       
  8419 					// Load rest if plugins
       
  8420 					each(pl, function(v) {
       
  8421 						if (v && v.charAt(0) != '-' && !PluginManager.urls[v]) {
       
  8422 							// Skip safari plugin for other browsers
       
  8423 							if (!tinymce.isWebKit && v == 'safari')
       
  8424 								return;
       
  8425 
       
  8426 							PluginManager.load(v, 'plugins/' + v + '/editor_plugin' + tinymce.suffix + '.js');
       
  8427 						}
       
  8428 					});
       
  8429 				}
       
  8430 
       
  8431 				sl.loadQueue();
       
  8432 			}
       
  8433 
       
  8434 			// Legacy call
       
  8435 			Event.add(document, 'init', function() {
       
  8436 				var l, co;
       
  8437 
       
  8438 				execCallback(s, 'onpageload');
       
  8439 
       
  8440 				// Verify that it's a valid browser
       
  8441 				if (s.browsers) {
       
  8442 					l = false;
       
  8443 
       
  8444 					each(explode(s.browsers), function(v) {
       
  8445 						switch (v) {
       
  8446 							case 'ie':
       
  8447 							case 'msie':
       
  8448 								if (tinymce.isIE)
       
  8449 									l = true;
       
  8450 								break;
       
  8451 
       
  8452 							case 'gecko':
       
  8453 								if (tinymce.isGecko)
       
  8454 									l = true;
       
  8455 								break;
       
  8456 
       
  8457 							case 'safari':
       
  8458 							case 'webkit':
       
  8459 								if (tinymce.isWebKit)
       
  8460 									l = true;
       
  8461 								break;
       
  8462 
       
  8463 							case 'opera':
       
  8464 								if (tinymce.isOpera)
       
  8465 									l = true;
       
  8466 
       
  8467 								break;
       
  8468 						}
       
  8469 					});
       
  8470 
       
  8471 					// Not a valid one
       
  8472 					if (!l)
       
  8473 						return;
       
  8474 				}
       
  8475 
       
  8476 				switch (s.mode) {
       
  8477 					case "exact":
       
  8478 						l = s.elements || '';
       
  8479 
       
  8480 						if(l.length > 0) {
       
  8481 							each(explode(l), function(v) {
       
  8482 								if (DOM.get(v)) {
       
  8483 									ed = new tinymce.Editor(v, s);
       
  8484 									el.push(ed);
       
  8485 									ed.render(1);
       
  8486 								} else {
       
  8487 									c = 0;
       
  8488 
       
  8489 									each(document.forms, function(f) {
       
  8490 										each(f.elements, function(e) {
       
  8491 											if (e.name === v) {
       
  8492 												v = 'mce_editor_' + c;
       
  8493 												DOM.setAttrib(e, 'id', v);
       
  8494 
       
  8495 												ed = new tinymce.Editor(v, s);
       
  8496 												el.push(ed);
       
  8497 												ed.render(1);
       
  8498 											}
       
  8499 										});
       
  8500 									});
       
  8501 								}
       
  8502 							});
       
  8503 						}
       
  8504 						break;
       
  8505 
       
  8506 					case "textareas":
       
  8507 					case "specific_textareas":
       
  8508 						function hasClass(n, c) {
       
  8509 							return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
       
  8510 						};
       
  8511 
       
  8512 						each(DOM.select('textarea'), function(v) {
       
  8513 							if (s.editor_deselector && hasClass(v, s.editor_deselector))
       
  8514 								return;
       
  8515 
       
  8516 							if (!s.editor_selector || hasClass(v, s.editor_selector)) {
       
  8517 								// Can we use the name
       
  8518 								e = DOM.get(v.name);
       
  8519 								if (!v.id && !e)
       
  8520 									v.id = v.name;
       
  8521 
       
  8522 								// Generate unique name if missing or already exists
       
  8523 								if (!v.id || t.get(v.id))
       
  8524 									v.id = DOM.uniqueId();
       
  8525 
       
  8526 								ed = new tinymce.Editor(v.id, s);
       
  8527 								el.push(ed);
       
  8528 								ed.render(1);
       
  8529 							}
       
  8530 						});
       
  8531 						break;
       
  8532 				}
       
  8533 
       
  8534 				// Call onInit when all editors are initialized
       
  8535 				if (s.oninit) {
       
  8536 					l = co = 0;
       
  8537 
       
  8538 					each (el, function(ed) {
       
  8539 						co++;
       
  8540 
       
  8541 						if (!ed.initialized) {
       
  8542 							// Wait for it
       
  8543 							ed.onInit.add(function() {
       
  8544 								l++;
       
  8545 
       
  8546 								// All done
       
  8547 								if (l == co)
       
  8548 									execCallback(s, 'oninit');
       
  8549 							});
       
  8550 						} else
       
  8551 							l++;
       
  8552 
       
  8553 						// All done
       
  8554 						if (l == co)
       
  8555 							execCallback(s, 'oninit');					
       
  8556 					});
       
  8557 				}
       
  8558 			});
       
  8559 		},
       
  8560 
       
  8561 		get : function(id) {
       
  8562 			return this.editors[id];
       
  8563 		},
       
  8564 
       
  8565 		getInstanceById : function(id) {
       
  8566 			return this.get(id);
       
  8567 		},
       
  8568 
       
  8569 		add : function(e) {
       
  8570 			this.editors[e.id] = e;
       
  8571 			this._setActive(e);
       
  8572 
       
  8573 			return e;
       
  8574 		},
       
  8575 
       
  8576 		remove : function(e) {
       
  8577 			var t = this;
       
  8578 
       
  8579 			// Not in the collection
       
  8580 			if (!t.editors[e.id])
       
  8581 				return null;
       
  8582 
       
  8583 			delete t.editors[e.id];
       
  8584 
       
  8585 			// Select another editor since the active one was removed
       
  8586 			if (t.activeEditor == e) {
       
  8587 				t._setActive(null);
       
  8588 
       
  8589 				each(t.editors, function(e) {
       
  8590 					t._setActive(e);
       
  8591 					return false; // Break
       
  8592 				});
       
  8593 			}
       
  8594 
       
  8595 			e.destroy();
       
  8596 
       
  8597 			return e;
       
  8598 		},
       
  8599 
       
  8600 		execCommand : function(c, u, v) {
       
  8601 			var t = this, ed = t.get(v), w;
       
  8602 
       
  8603 			// Manager commands
       
  8604 			switch (c) {
       
  8605 				case "mceFocus":
       
  8606 					ed.focus();
       
  8607 					return true;
       
  8608 
       
  8609 				case "mceAddEditor":
       
  8610 				case "mceAddControl":
       
  8611 					if (!t.get(v))
       
  8612 						new tinymce.Editor(v, t.settings).render();
       
  8613 
       
  8614 					return true;
       
  8615 
       
  8616 				case "mceAddFrameControl":
       
  8617 					w = v.window;
       
  8618 
       
  8619 					// Add tinyMCE global instance and tinymce namespace to specified window
       
  8620 					w.tinyMCE = tinyMCE;
       
  8621 					w.tinymce = tinymce;
       
  8622 
       
  8623 					tinymce.DOM.doc = w.document;
       
  8624 					tinymce.DOM.win = w;
       
  8625 
       
  8626 					ed = new tinymce.Editor(v.element_id, v);
       
  8627 					ed.render();
       
  8628 
       
  8629 					// Fix IE memory leaks
       
  8630 					if (tinymce.isIE) {
       
  8631 						function clr() {
       
  8632 							ed.destroy();
       
  8633 							w.detachEvent('onunload', clr);
       
  8634 							w = w.tinyMCE = w.tinymce = null; // IE leak
       
  8635 						};
       
  8636 
       
  8637 						w.attachEvent('onunload', clr);
       
  8638 					}
       
  8639 
       
  8640 					v.page_window = null;
       
  8641 
       
  8642 					return true;
       
  8643 
       
  8644 				case "mceRemoveEditor":
       
  8645 				case "mceRemoveControl":
       
  8646 					if (ed)
       
  8647 						ed.remove();
       
  8648 
       
  8649 					return true;
       
  8650 
       
  8651 				case 'mceToggleEditor':
       
  8652 					if (!ed) {
       
  8653 						t.execCommand('mceAddControl', 0, v);
       
  8654 						return true;
       
  8655 					}
       
  8656 
       
  8657 					if (ed.isHidden())
       
  8658 						ed.show();
       
  8659 					else
       
  8660 						ed.hide();
       
  8661 
       
  8662 					return true;
       
  8663 			}
       
  8664 
       
  8665 			// Run command on active editor
       
  8666 			if (t.activeEditor)
       
  8667 				return t.activeEditor.execCommand(c, u, v);
       
  8668 
       
  8669 			return false;
       
  8670 		},
       
  8671 
       
  8672 		execInstanceCommand : function(id, c, u, v) {
       
  8673 			var ed = this.get(id);
       
  8674 
       
  8675 			if (ed)
       
  8676 				return ed.execCommand(c, u, v);
       
  8677 
       
  8678 			return false;
       
  8679 		},
       
  8680 
       
  8681 		triggerSave : function() {
       
  8682 			each(this.editors, function(e) {
       
  8683 				e.save();
       
  8684 			});
       
  8685 		},
       
  8686 
       
  8687 		addI18n : function(p, o) {
       
  8688 			var lo, i18n = this.i18n;
       
  8689 
       
  8690 			if (!tinymce.is(p, 'string')) {
       
  8691 				each(p, function(o, lc) {
       
  8692 					each(o, function(o, g) {
       
  8693 						each(o, function(o, k) {
       
  8694 							if (g === 'common')
       
  8695 								i18n[lc + '.' + k] = o;
       
  8696 							else
       
  8697 								i18n[lc + '.' + g + '.' + k] = o;
       
  8698 						});
       
  8699 					});
       
  8700 				});
       
  8701 			} else {
       
  8702 				each(o, function(o, k) {
       
  8703 					i18n[p + '.' + k] = o;
       
  8704 				});
       
  8705 			}
       
  8706 		},
       
  8707 
       
  8708 		// Private methods
       
  8709 
       
  8710 		_setActive : function(e) {
       
  8711 			this.selectedInstance = this.activeEditor = e;
       
  8712 		}
       
  8713 	});
       
  8714 
       
  8715 	tinymce.EditorManager.preInit();
       
  8716 })(tinymce);
       
  8717 
       
  8718 var tinyMCE = window.tinyMCE = tinymce.EditorManager;
       
  8719 (function(tinymce) {
       
  8720 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, Dispatcher = tinymce.util.Dispatcher;
       
  8721 	var each = tinymce.each, isGecko = tinymce.isGecko, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit;
       
  8722 	var is = tinymce.is, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, EditorManager = tinymce.EditorManager;
       
  8723 	var inArray = tinymce.inArray, grep = tinymce.grep, explode = tinymce.explode;
       
  8724 
       
  8725 	tinymce.create('tinymce.Editor', {
       
  8726 		Editor : function(id, s) {
       
  8727 			var t = this;
       
  8728 
       
  8729 			t.id = t.editorId = id;
       
  8730 
       
  8731 			t.execCommands = {};
       
  8732 			t.queryStateCommands = {};
       
  8733 			t.queryValueCommands = {};
       
  8734 
       
  8735 			t.isNotDirty = false;
       
  8736 
       
  8737 			t.plugins = {};
       
  8738 
       
  8739 			// Add events to the editor
       
  8740 			each([
       
  8741 				'onPreInit',
       
  8742 
       
  8743 				'onBeforeRenderUI',
       
  8744 
       
  8745 				'onPostRender',
       
  8746 
       
  8747 				'onInit',
       
  8748 
       
  8749 				'onRemove',
       
  8750 
       
  8751 				'onActivate',
       
  8752 
       
  8753 				'onDeactivate',
       
  8754 
       
  8755 				'onClick',
       
  8756 
       
  8757 				'onEvent',
       
  8758 
       
  8759 				'onMouseUp',
       
  8760 
       
  8761 				'onMouseDown',
       
  8762 
       
  8763 				'onDblClick',
       
  8764 
       
  8765 				'onKeyDown',
       
  8766 
       
  8767 				'onKeyUp',
       
  8768 
       
  8769 				'onKeyPress',
       
  8770 
       
  8771 				'onContextMenu',
       
  8772 
       
  8773 				'onSubmit',
       
  8774 
       
  8775 				'onReset',
       
  8776 
       
  8777 				'onPaste',
       
  8778 
       
  8779 				'onPreProcess',
       
  8780 
       
  8781 				'onPostProcess',
       
  8782 
       
  8783 				'onBeforeSetContent',
       
  8784 
       
  8785 				'onBeforeGetContent',
       
  8786 
       
  8787 				'onSetContent',
       
  8788 
       
  8789 				'onGetContent',
       
  8790 
       
  8791 				'onLoadContent',
       
  8792 
       
  8793 				'onSaveContent',
       
  8794 
       
  8795 				'onNodeChange',
       
  8796 
       
  8797 				'onChange',
       
  8798 
       
  8799 				'onBeforeExecCommand',
       
  8800 
       
  8801 				'onExecCommand',
       
  8802 
       
  8803 				'onUndo',
       
  8804 
       
  8805 				'onRedo',
       
  8806 
       
  8807 				'onVisualAid',
       
  8808 
       
  8809 				'onSetProgressState'
       
  8810 			], function(e) {
       
  8811 				t[e] = new Dispatcher(t);
       
  8812 			});
       
  8813 
       
  8814 			t.settings = s = extend({
       
  8815 				id : id,
       
  8816 				language : 'en',
       
  8817 				docs_language : 'en',
       
  8818 				theme : 'simple',
       
  8819 				skin : 'default',
       
  8820 				delta_width : 0,
       
  8821 				delta_height : 0,
       
  8822 				popup_css : '',
       
  8823 				plugins : '',
       
  8824 				document_base_url : tinymce.documentBaseURL,
       
  8825 				add_form_submit_trigger : 1,
       
  8826 				submit_patch : 1,
       
  8827 				add_unload_trigger : 1,
       
  8828 				convert_urls : 1,
       
  8829 				relative_urls : 1,
       
  8830 				remove_script_host : 1,
       
  8831 				table_inline_editing : 0,
       
  8832 				object_resizing : 1,
       
  8833 				cleanup : 1,
       
  8834 				accessibility_focus : 1,
       
  8835 				custom_shortcuts : 1,
       
  8836 				custom_undo_redo_keyboard_shortcuts : 1,
       
  8837 				custom_undo_redo_restore_selection : 1,
       
  8838 				custom_undo_redo : 1,
       
  8839 				doctype : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">',
       
  8840 				visual_table_class : 'mceItemTable',
       
  8841 				visual : 1,
       
  8842 				inline_styles : true,
       
  8843 				convert_fonts_to_spans : true,
       
  8844 				font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large',
       
  8845 				apply_source_formatting : 1,
       
  8846 				directionality : 'ltr',
       
  8847 				forced_root_block : 'p',
       
  8848 				valid_elements : '@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong/b,em/i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big',
       
  8849 				hidden_input : 1,
       
  8850 				padd_empty_editor : 1,
       
  8851 				render_ui : 1,
       
  8852 				init_theme : 1,
       
  8853 				force_p_newlines : 1,
       
  8854 				indentation : '30px',
       
  8855 				keep_styles : 1,
       
  8856 				fix_table_elements : 1,
       
  8857 				removeformat_selector : 'span,b,strong,em,i,font,u,strike'
       
  8858 			}, s);
       
  8859 
       
  8860 			t.documentBaseURI = new tinymce.util.URI(s.document_base_url || tinymce.documentBaseURL, {
       
  8861 				base_uri : tinyMCE.baseURI
       
  8862 			});
       
  8863 
       
  8864 			t.baseURI = EditorManager.baseURI;
       
  8865 
       
  8866 			// Call setup
       
  8867 			t.execCallback('setup', t);
       
  8868 		},
       
  8869 
       
  8870 		render : function(nst) {
       
  8871 			var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader;
       
  8872 
       
  8873 			// Page is not loaded yet, wait for it
       
  8874 			if (!Event.domLoaded) {
       
  8875 				Event.add(document, 'init', function() {
       
  8876 					t.render();
       
  8877 				});
       
  8878 				return;
       
  8879 			}
       
  8880 
       
  8881 			// Force strict loading mode if render us called by user and not internally
       
  8882 			if (!nst) {
       
  8883 				s.strict_loading_mode = 1;
       
  8884 				tinyMCE.settings = s;
       
  8885 			}
       
  8886 
       
  8887 			// Element not found, then skip initialization
       
  8888 			if (!t.getElement())
       
  8889 				return;
       
  8890 
       
  8891 			if (s.strict_loading_mode) {
       
  8892 				sl.settings.strict_mode = s.strict_loading_mode;
       
  8893 				tinymce.DOM.settings.strict = 1;
       
  8894 			}
       
  8895 
       
  8896 			// Add hidden input for non input elements inside form elements
       
  8897 			if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
       
  8898 				DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
       
  8899 
       
  8900 			if (tinymce.WindowManager)
       
  8901 				t.windowManager = new tinymce.WindowManager(t);
       
  8902 
       
  8903 			if (s.encoding == 'xml') {
       
  8904 				t.onGetContent.add(function(ed, o) {
       
  8905 					if (o.save)
       
  8906 						o.content = DOM.encode(o.content);
       
  8907 				});
       
  8908 			}
       
  8909 
       
  8910 			if (s.add_form_submit_trigger) {
       
  8911 				t.onSubmit.addToTop(function() {
       
  8912 					if (t.initialized) {
       
  8913 						t.save();
       
  8914 						t.isNotDirty = 1;
       
  8915 					}
       
  8916 				});
       
  8917 			}
       
  8918 
       
  8919 			if (s.add_unload_trigger) {
       
  8920 				t._beforeUnload = tinyMCE.onBeforeUnload.add(function() {
       
  8921 					if (t.initialized && !t.destroyed && !t.isHidden())
       
  8922 						t.save({format : 'raw', no_events : true});
       
  8923 				});
       
  8924 			}
       
  8925 
       
  8926 			tinymce.addUnload(t.destroy, t);
       
  8927 
       
  8928 			if (s.submit_patch) {
       
  8929 				t.onBeforeRenderUI.add(function() {
       
  8930 					var n = t.getElement().form;
       
  8931 
       
  8932 					if (!n)
       
  8933 						return;
       
  8934 
       
  8935 					// Already patched
       
  8936 					if (n._mceOldSubmit)
       
  8937 						return;
       
  8938 
       
  8939 					// Check page uses id="submit" or name="submit" for it's submit button
       
  8940 					if (!n.submit.nodeType && !n.submit.length) {
       
  8941 						t.formElement = n;
       
  8942 						n._mceOldSubmit = n.submit;
       
  8943 						n.submit = function() {
       
  8944 							// Save all instances
       
  8945 							EditorManager.triggerSave();
       
  8946 							t.isNotDirty = 1;
       
  8947 
       
  8948 							return t.formElement._mceOldSubmit(t.formElement);
       
  8949 						};
       
  8950 					}
       
  8951 
       
  8952 					n = null;
       
  8953 				});
       
  8954 			}
       
  8955 
       
  8956 			// Load scripts
       
  8957 			function loadScripts() {
       
  8958 				if (s.language)
       
  8959 					sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
       
  8960 
       
  8961 				if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
       
  8962 					ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
       
  8963 
       
  8964 				each(explode(s.plugins), function(p) {
       
  8965 					if (p && p.charAt(0) != '-' && !PluginManager.urls[p]) {
       
  8966 						// Skip safari plugin for other browsers
       
  8967 						if (!isWebKit && p == 'safari')
       
  8968 							return;
       
  8969 
       
  8970 						PluginManager.load(p, 'plugins/' + p + '/editor_plugin' + tinymce.suffix + '.js');
       
  8971 					}
       
  8972 				});
       
  8973 
       
  8974 				// Init when que is loaded
       
  8975 				sl.loadQueue(function() {
       
  8976 					if (!t.removed)
       
  8977 						t.init();
       
  8978 				});
       
  8979 			};
       
  8980 
       
  8981 			loadScripts();
       
  8982 		},
       
  8983 
       
  8984 		init : function() {
       
  8985 			var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u, bi, bc, re;
       
  8986 
       
  8987 			EditorManager.add(t);
       
  8988 
       
  8989 			if (s.theme) {
       
  8990 				s.theme = s.theme.replace(/-/, '');
       
  8991 				o = ThemeManager.get(s.theme);
       
  8992 				t.theme = new o();
       
  8993 
       
  8994 				if (t.theme.init && s.init_theme)
       
  8995 					t.theme.init(t, ThemeManager.urls[s.theme] || tinymce.documentBaseURL.replace(/\/$/, ''));
       
  8996 			}
       
  8997 
       
  8998 			// Create all plugins
       
  8999 			each(explode(s.plugins.replace(/\-/g, '')), function(p) {
       
  9000 				var c = PluginManager.get(p), u = PluginManager.urls[p] || tinymce.documentBaseURL.replace(/\/$/, ''), po;
       
  9001 
       
  9002 				if (c) {
       
  9003 					po = new c(t, u);
       
  9004 
       
  9005 					t.plugins[p] = po;
       
  9006 
       
  9007 					if (po.init)
       
  9008 						po.init(t, u);
       
  9009 				}
       
  9010 			});
       
  9011 
       
  9012 			// Setup popup CSS path(s)
       
  9013 			if (s.popup_css !== false) {
       
  9014 				if (s.popup_css)
       
  9015 					s.popup_css = t.documentBaseURI.toAbsolute(s.popup_css);
       
  9016 				else
       
  9017 					s.popup_css = t.baseURI.toAbsolute("themes/" + s.theme + "/skins/" + s.skin + "/dialog.css");
       
  9018 			}
       
  9019 
       
  9020 			if (s.popup_css_add)
       
  9021 				s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add);
       
  9022 
       
  9023 			t.controlManager = new tinymce.ControlManager(t);
       
  9024 
       
  9025 			t.undoManager = new tinymce.UndoManager(t);
       
  9026 
       
  9027 			// Pass through
       
  9028 			t.undoManager.onAdd.add(function(um, l) {
       
  9029 				if (!l.initial)
       
  9030 					return t.onChange.dispatch(t, l, um);
       
  9031 			});
       
  9032 
       
  9033 			t.undoManager.onUndo.add(function(um, l) {
       
  9034 				return t.onUndo.dispatch(t, l, um);
       
  9035 			});
       
  9036 
       
  9037 			t.undoManager.onRedo.add(function(um, l) {
       
  9038 				return t.onRedo.dispatch(t, l, um);
       
  9039 			});
       
  9040 
       
  9041 			if (s.custom_undo_redo) {
       
  9042 				t.onExecCommand.add(function(ed, cmd, ui, val, a) {
       
  9043 					if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!a || !a.skip_undo))
       
  9044 						t.undoManager.add();
       
  9045 				});
       
  9046 			}
       
  9047 
       
  9048 			t.onExecCommand.add(function(ed, c) {
       
  9049 				// Don't refresh the select lists until caret move
       
  9050 				if (!/^(FontName|FontSize)$/.test(c))
       
  9051 					t.nodeChanged();
       
  9052 			});
       
  9053 
       
  9054 			// Remove ghost selections on images and tables in Gecko
       
  9055 			if (isGecko) {
       
  9056 				function repaint(a, o) {
       
  9057 					if (!o || !o.initial)
       
  9058 						t.execCommand('mceRepaint');
       
  9059 				};
       
  9060 
       
  9061 				t.onUndo.add(repaint);
       
  9062 				t.onRedo.add(repaint);
       
  9063 				t.onSetContent.add(repaint);
       
  9064 			}
       
  9065 
       
  9066 			// Enables users to override the control factory
       
  9067 			t.onBeforeRenderUI.dispatch(t, t.controlManager);
       
  9068 
       
  9069 			// Measure box
       
  9070 			if (s.render_ui) {
       
  9071 				w = s.width || e.style.width || e.offsetWidth;
       
  9072 				h = s.height || e.style.height || e.offsetHeight;
       
  9073 				t.orgDisplay = e.style.display;
       
  9074 				re = /^[0-9\.]+(|px)$/i;
       
  9075 
       
  9076 				if (re.test('' + w))
       
  9077 					w = Math.max(parseInt(w) + (o.deltaWidth || 0), 100);
       
  9078 
       
  9079 				if (re.test('' + h))
       
  9080 					h = Math.max(parseInt(h) + (o.deltaHeight || 0), 100);
       
  9081 
       
  9082 				// Render UI
       
  9083 				o = t.theme.renderUI({
       
  9084 					targetNode : e,
       
  9085 					width : w,
       
  9086 					height : h,
       
  9087 					deltaWidth : s.delta_width,
       
  9088 					deltaHeight : s.delta_height
       
  9089 				});
       
  9090 
       
  9091 				t.editorContainer = o.editorContainer;
       
  9092 			}
       
  9093 
       
  9094 
       
  9095 			// User specified a document.domain value
       
  9096 			if (document.domain && location.hostname != document.domain)
       
  9097 				tinymce.relaxedDomain = document.domain;
       
  9098 
       
  9099 			// Resize editor
       
  9100 			DOM.setStyles(o.sizeContainer || o.editorContainer, {
       
  9101 				width : w,
       
  9102 				height : h
       
  9103 			});
       
  9104 
       
  9105 			h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');
       
  9106 			if (h < 100)
       
  9107 				h = 100;
       
  9108 
       
  9109 			t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml">';
       
  9110 
       
  9111 			// We only need to override paths if we have to
       
  9112 			// IE has a bug where it remove site absolute urls to relative ones if this is specified
       
  9113 			if (s.document_base_url != tinymce.documentBaseURL)
       
  9114 				t.iframeHTML += '<base href="' + t.documentBaseURI.getURI() + '" />';
       
  9115 
       
  9116 			t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
       
  9117 
       
  9118 			if (tinymce.relaxedDomain)
       
  9119 				t.iframeHTML += '<script type="text/javascript">document.domain = "' + tinymce.relaxedDomain + '";</script>';
       
  9120 
       
  9121 			bi = s.body_id || 'tinymce';
       
  9122 			if (bi.indexOf('=') != -1) {
       
  9123 				bi = t.getParam('body_id', '', 'hash');
       
  9124 				bi = bi[t.id] || bi;
       
  9125 			}
       
  9126 
       
  9127 			bc = s.body_class || '';
       
  9128 			if (bc.indexOf('=') != -1) {
       
  9129 				bc = t.getParam('body_class', '', 'hash');
       
  9130 				bc = bc[t.id] || '';
       
  9131 			}
       
  9132 
       
  9133 			t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';
       
  9134 
       
  9135 			// Domain relaxing enabled, then set document domain
       
  9136 			if (tinymce.relaxedDomain) {
       
  9137 				// We need to write the contents here in IE since multiple writes messes up refresh button and back button
       
  9138 				if (isIE || (tinymce.isOpera && parseFloat(opera.version()) >= 9.5))
       
  9139 					u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()';
       
  9140 				else if (tinymce.isOpera)
       
  9141 					u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()';					
       
  9142 			}
       
  9143 
       
  9144 			// Create iframe
       
  9145 			n = DOM.add(o.iframeContainer, 'iframe', {
       
  9146 				id : t.id + "_ifr",
       
  9147 				src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7
       
  9148 				frameBorder : '0',
       
  9149 				style : {
       
  9150 					width : '100%',
       
  9151 					height : h
       
  9152 				}
       
  9153 			});
       
  9154 
       
  9155 			t.contentAreaContainer = o.iframeContainer;
       
  9156 			DOM.get(o.editorContainer).style.display = t.orgDisplay;
       
  9157 			DOM.get(t.id).style.display = 'none';
       
  9158 
       
  9159 			if (!isIE || !tinymce.relaxedDomain)
       
  9160 				t.setupIframe();
       
  9161 
       
  9162 			e = n = o = null; // Cleanup
       
  9163 		},
       
  9164 
       
  9165 		setupIframe : function() {
       
  9166 			var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b;
       
  9167 
       
  9168 			// Setup iframe body
       
  9169 			if (!isIE || !tinymce.relaxedDomain) {
       
  9170 				d.open();
       
  9171 				d.write(t.iframeHTML);
       
  9172 				d.close();
       
  9173 			}
       
  9174 
       
  9175 			// Design mode needs to be added here Ctrl+A will fail otherwise
       
  9176 			if (!isIE) {
       
  9177 				try {
       
  9178 					if (!s.readonly)
       
  9179 						d.designMode = 'On';
       
  9180 				} catch (ex) {
       
  9181 					// Will fail on Gecko if the editor is placed in an hidden container element
       
  9182 					// The design mode will be set ones the editor is focused
       
  9183 				}
       
  9184 			}
       
  9185 
       
  9186 			// IE needs to use contentEditable or it will display non secure items for HTTPS
       
  9187 			if (isIE) {
       
  9188 				// It will not steal focus if we hide it while setting contentEditable
       
  9189 				b = t.getBody();
       
  9190 				DOM.hide(b);
       
  9191 
       
  9192 				if (!s.readonly)
       
  9193 					b.contentEditable = true;
       
  9194 
       
  9195 				DOM.show(b);
       
  9196 			}
       
  9197 
       
  9198 			t.dom = new tinymce.dom.DOMUtils(t.getDoc(), {
       
  9199 				keep_values : true,
       
  9200 				url_converter : t.convertURL,
       
  9201 				url_converter_scope : t,
       
  9202 				hex_colors : s.force_hex_style_colors,
       
  9203 				class_filter : s.class_filter,
       
  9204 				update_styles : 1,
       
  9205 				fix_ie_paragraphs : 1
       
  9206 			});
       
  9207 
       
  9208 			t.serializer = new tinymce.dom.Serializer(extend(s, {
       
  9209 				valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements,
       
  9210 				dom : t.dom
       
  9211 			}));
       
  9212 
       
  9213 			t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer);
       
  9214 
       
  9215 			t.forceBlocks = new tinymce.ForceBlocks(t, {
       
  9216 				forced_root_block : s.forced_root_block
       
  9217 			});
       
  9218 			t.editorCommands = new tinymce.EditorCommands(t);
       
  9219 
       
  9220 			// Pass through
       
  9221 			t.serializer.onPreProcess.add(function(se, o) {
       
  9222 				return t.onPreProcess.dispatch(t, o, se);
       
  9223 			});
       
  9224 
       
  9225 			t.serializer.onPostProcess.add(function(se, o) {
       
  9226 				return t.onPostProcess.dispatch(t, o, se);
       
  9227 			});
       
  9228 
       
  9229 			t.onPreInit.dispatch(t);
       
  9230 
       
  9231 			if (!s.gecko_spellcheck)
       
  9232 				t.getBody().spellcheck = 0;
       
  9233 
       
  9234 			if (!s.readonly)
       
  9235 				t._addEvents();
       
  9236 
       
  9237 			t.controlManager.onPostRender.dispatch(t, t.controlManager);
       
  9238 			t.onPostRender.dispatch(t);
       
  9239 
       
  9240 			if (s.directionality)
       
  9241 				t.getBody().dir = s.directionality;
       
  9242 
       
  9243 			if (s.nowrap)
       
  9244 				t.getBody().style.whiteSpace = "nowrap";
       
  9245 
       
  9246 			if (s.custom_elements) {
       
  9247 				function handleCustom(ed, o) {
       
  9248 					each(explode(s.custom_elements), function(v) {
       
  9249 						var n;
       
  9250 
       
  9251 						if (v.indexOf('~') === 0) {
       
  9252 							v = v.substring(1);
       
  9253 							n = 'span';
       
  9254 						} else
       
  9255 							n = 'div';
       
  9256 
       
  9257 						o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' mce_name="$1"$2>');
       
  9258 						o.content = o.content.replace(new RegExp('</(' + v + ')>', 'g'), '</' + n + '>');
       
  9259 					});
       
  9260 				};
       
  9261 
       
  9262 				t.onBeforeSetContent.add(handleCustom);
       
  9263 				t.onPostProcess.add(function(ed, o) {
       
  9264 					if (o.set)
       
  9265 						handleCustom(ed, o);
       
  9266 				});
       
  9267 			}
       
  9268 
       
  9269 			if (s.handle_node_change_callback) {
       
  9270 				t.onNodeChange.add(function(ed, cm, n) {
       
  9271 					t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed());
       
  9272 				});
       
  9273 			}
       
  9274 
       
  9275 			if (s.save_callback) {
       
  9276 				t.onSaveContent.add(function(ed, o) {
       
  9277 					var h = t.execCallback('save_callback', t.id, o.content, t.getBody());
       
  9278 
       
  9279 					if (h)
       
  9280 						o.content = h;
       
  9281 				});
       
  9282 			}
       
  9283 
       
  9284 			if (s.onchange_callback) {
       
  9285 				t.onChange.add(function(ed, l) {
       
  9286 					t.execCallback('onchange_callback', t, l);
       
  9287 				});
       
  9288 			}
       
  9289 
       
  9290 			if (s.convert_newlines_to_brs) {
       
  9291 				t.onBeforeSetContent.add(function(ed, o) {
       
  9292 					if (o.initial)
       
  9293 						o.content = o.content.replace(/\r?\n/g, '<br />');
       
  9294 				});
       
  9295 			}
       
  9296 
       
  9297 			if (s.fix_nesting && isIE) {
       
  9298 				t.onBeforeSetContent.add(function(ed, o) {
       
  9299 					o.content = t._fixNesting(o.content);
       
  9300 				});
       
  9301 			}
       
  9302 
       
  9303 			if (s.preformatted) {
       
  9304 				t.onPostProcess.add(function(ed, o) {
       
  9305 					o.content = o.content.replace(/^\s*<pre.*?>/, '');
       
  9306 					o.content = o.content.replace(/<\/pre>\s*$/, '');
       
  9307 
       
  9308 					if (o.set)
       
  9309 						o.content = '<pre class="mceItemHidden">' + o.content + '</pre>';
       
  9310 				});
       
  9311 			}
       
  9312 
       
  9313 			if (s.verify_css_classes) {
       
  9314 				t.serializer.attribValueFilter = function(n, v) {
       
  9315 					var s, cl;
       
  9316 
       
  9317 					if (n == 'class') {
       
  9318 						// Build regexp for classes
       
  9319 						if (!t.classesRE) {
       
  9320 							cl = t.dom.getClasses();
       
  9321 
       
  9322 							if (cl.length > 0) {
       
  9323 								s = '';
       
  9324 
       
  9325 								each (cl, function(o) {
       
  9326 									s += (s ? '|' : '') + o['class'];
       
  9327 								});
       
  9328 
       
  9329 								t.classesRE = new RegExp('(' + s + ')', 'gi');
       
  9330 							}
       
  9331 						}
       
  9332 
       
  9333 						return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : '';
       
  9334 					}
       
  9335 
       
  9336 					return v;
       
  9337 				};
       
  9338 			}
       
  9339 
       
  9340 			if (s.convert_fonts_to_spans)
       
  9341 				t._convertFonts();
       
  9342 
       
  9343 			if (s.inline_styles)
       
  9344 				t._convertInlineElements();
       
  9345 
       
  9346 			if (s.cleanup_callback) {
       
  9347 				t.onBeforeSetContent.add(function(ed, o) {
       
  9348 					o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
       
  9349 				});
       
  9350 
       
  9351 				t.onPreProcess.add(function(ed, o) {
       
  9352 					if (o.set)
       
  9353 						t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o);
       
  9354 
       
  9355 					if (o.get)
       
  9356 						t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o);
       
  9357 				});
       
  9358 
       
  9359 				t.onPostProcess.add(function(ed, o) {
       
  9360 					if (o.set)
       
  9361 						o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
       
  9362 
       
  9363 					if (o.get)						
       
  9364 						o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o);
       
  9365 				});
       
  9366 			}
       
  9367 
       
  9368 			if (s.save_callback) {
       
  9369 				t.onGetContent.add(function(ed, o) {
       
  9370 					if (o.save)
       
  9371 						o.content = t.execCallback('save_callback', t.id, o.content, t.getBody());
       
  9372 				});
       
  9373 			}
       
  9374 
       
  9375 			if (s.handle_event_callback) {
       
  9376 				t.onEvent.add(function(ed, e, o) {
       
  9377 					if (t.execCallback('handle_event_callback', e, ed, o) === false)
       
  9378 						Event.cancel(e);
       
  9379 				});
       
  9380 			}
       
  9381 
       
  9382 			// Add visual aids when new contents is added
       
  9383 			t.onSetContent.add(function() {
       
  9384 				t.addVisual(t.getBody());
       
  9385 			});
       
  9386 
       
  9387 			// Remove empty contents
       
  9388 			if (s.padd_empty_editor) {
       
  9389 				t.onPostProcess.add(function(ed, o) {
       
  9390 					o.content = o.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/, '');
       
  9391 				});
       
  9392 			}
       
  9393 
       
  9394 			if (isGecko) {
       
  9395 				// Fix gecko link bug, when a link is placed at the end of block elements there is
       
  9396 				// no way to move the caret behind the link. This fix adds a bogus br element after the link
       
  9397 				function fixLinks(ed, o) {
       
  9398 					each(ed.dom.select('a'), function(n) {
       
  9399 						var pn = n.parentNode;
       
  9400 
       
  9401 						if (ed.dom.isBlock(pn) && pn.lastChild === n)
       
  9402 							ed.dom.add(pn, 'br', {'mce_bogus' : 1});
       
  9403 					});
       
  9404 				};
       
  9405 
       
  9406 				t.onExecCommand.add(function(ed, cmd) {
       
  9407 					if (cmd === 'CreateLink')
       
  9408 						fixLinks(ed);
       
  9409 				});
       
  9410 
       
  9411 				t.onSetContent.add(t.selection.onSetContent.add(fixLinks));
       
  9412 
       
  9413 				if (!s.readonly) {
       
  9414 					try {
       
  9415 						// Design mode must be set here once again to fix a bug where
       
  9416 						// Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again
       
  9417 						d.designMode = 'Off';
       
  9418 						d.designMode = 'On';
       
  9419 					} catch (ex) {
       
  9420 						// Will fail on Gecko if the editor is placed in an hidden container element
       
  9421 						// The design mode will be set ones the editor is focused
       
  9422 					}
       
  9423 				}
       
  9424 			}
       
  9425 
       
  9426 			// A small timeout was needed since firefox will remove. Bug: #1838304
       
  9427 			setTimeout(function () {
       
  9428 				if (t.removed)
       
  9429 					return;
       
  9430 
       
  9431 				t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')});
       
  9432 				t.startContent = t.getContent({format : 'raw'});
       
  9433 				t.undoManager.add({initial : true});
       
  9434 				t.initialized = true;
       
  9435 
       
  9436 				t.onInit.dispatch(t);
       
  9437 				t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc());
       
  9438 				t.execCallback('init_instance_callback', t);
       
  9439 				t.focus(true);
       
  9440 				t.nodeChanged({initial : 1});
       
  9441 
       
  9442 				// Load specified content CSS last
       
  9443 				if (s.content_css) {
       
  9444 					tinymce.each(explode(s.content_css), function(u) {
       
  9445 						t.dom.loadCSS(t.documentBaseURI.toAbsolute(u));
       
  9446 					});
       
  9447 				}
       
  9448 
       
  9449 				// Handle auto focus
       
  9450 				if (s.auto_focus) {
       
  9451 					setTimeout(function () {
       
  9452 						var ed = EditorManager.get(s.auto_focus);
       
  9453 
       
  9454 						ed.selection.select(ed.getBody(), 1);
       
  9455 						ed.selection.collapse(1);
       
  9456 						ed.getWin().focus();
       
  9457 					}, 100);
       
  9458 				}
       
  9459 			}, 1);
       
  9460 	
       
  9461 			e = null;
       
  9462 		},
       
  9463 
       
  9464 
       
  9465 		focus : function(sf) {
       
  9466 			var oed, t = this, ce = t.settings.content_editable;
       
  9467 
       
  9468 			if (!sf) {
       
  9469 				// Is not content editable or the selection is outside the area in IE
       
  9470 				// the IE statement is needed to avoid bluring if element selections inside layers since
       
  9471 				// the layer is like it's own document in IE
       
  9472 				if (!ce && (!isIE || t.selection.getNode().ownerDocument != t.getDoc()))
       
  9473 					t.getWin().focus();
       
  9474 
       
  9475 			}
       
  9476 
       
  9477 			if (EditorManager.activeEditor != t) {
       
  9478 				if ((oed = EditorManager.activeEditor) != null)
       
  9479 					oed.onDeactivate.dispatch(oed, t);
       
  9480 
       
  9481 				t.onActivate.dispatch(t, oed);
       
  9482 			}
       
  9483 
       
  9484 			EditorManager._setActive(t);
       
  9485 		},
       
  9486 
       
  9487 		execCallback : function(n) {
       
  9488 			var t = this, f = t.settings[n], s;
       
  9489 
       
  9490 			if (!f)
       
  9491 				return;
       
  9492 
       
  9493 			// Look through lookup
       
  9494 			if (t.callbackLookup && (s = t.callbackLookup[n])) {
       
  9495 				f = s.func;
       
  9496 				s = s.scope;
       
  9497 			}
       
  9498 
       
  9499 			if (is(f, 'string')) {
       
  9500 				s = f.replace(/\.\w+$/, '');
       
  9501 				s = s ? tinymce.resolve(s) : 0;
       
  9502 				f = tinymce.resolve(f);
       
  9503 				t.callbackLookup = t.callbackLookup || {};
       
  9504 				t.callbackLookup[n] = {func : f, scope : s};
       
  9505 			}
       
  9506 
       
  9507 			return f.apply(s || t, Array.prototype.slice.call(arguments, 1));
       
  9508 		},
       
  9509 
       
  9510 		translate : function(s) {
       
  9511 			var c = this.settings.language || 'en', i18n = EditorManager.i18n;
       
  9512 
       
  9513 			if (!s)
       
  9514 				return '';
       
  9515 
       
  9516 			return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) {
       
  9517 				return i18n[c + '.' + b] || '{#' + b + '}';
       
  9518 			});
       
  9519 		},
       
  9520 
       
  9521 		getLang : function(n, dv) {
       
  9522 			return EditorManager.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}');
       
  9523 		},
       
  9524 
       
  9525 		getParam : function(n, dv, ty) {
       
  9526 			var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o;
       
  9527 
       
  9528 			if (ty === 'hash') {
       
  9529 				o = {};
       
  9530 
       
  9531 				if (is(v, 'string')) {
       
  9532 					each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) {
       
  9533 						v = v.split('=');
       
  9534 
       
  9535 						if (v.length > 1)
       
  9536 							o[tr(v[0])] = tr(v[1]);
       
  9537 						else
       
  9538 							o[tr(v[0])] = tr(v);
       
  9539 					});
       
  9540 				} else
       
  9541 					o = v;
       
  9542 
       
  9543 				return o;
       
  9544 			}
       
  9545 
       
  9546 			return v;
       
  9547 		},
       
  9548 
       
  9549 		nodeChanged : function(o) {
       
  9550 			var t = this, s = t.selection, n = s.getNode() || t.getBody();
       
  9551 
       
  9552 			// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
       
  9553 			if (t.initialized) {
       
  9554 				t.onNodeChange.dispatch(
       
  9555 					t,
       
  9556 					o ? o.controlManager || t.controlManager : t.controlManager,
       
  9557 					isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n, // Fix for IE initial state
       
  9558 					s.isCollapsed(),
       
  9559 					o
       
  9560 				);
       
  9561 			}
       
  9562 		},
       
  9563 
       
  9564 		addButton : function(n, s) {
       
  9565 			var t = this;
       
  9566 
       
  9567 			t.buttons = t.buttons || {};
       
  9568 			t.buttons[n] = s;
       
  9569 		},
       
  9570 
       
  9571 		addCommand : function(n, f, s) {
       
  9572 			this.execCommands[n] = {func : f, scope : s || this};
       
  9573 		},
       
  9574 
       
  9575 		addQueryStateHandler : function(n, f, s) {
       
  9576 			this.queryStateCommands[n] = {func : f, scope : s || this};
       
  9577 		},
       
  9578 
       
  9579 		addQueryValueHandler : function(n, f, s) {
       
  9580 			this.queryValueCommands[n] = {func : f, scope : s || this};
       
  9581 		},
       
  9582 
       
  9583 		addShortcut : function(pa, desc, cmd_func, sc) {
       
  9584 			var t = this, c;
       
  9585 
       
  9586 			if (!t.settings.custom_shortcuts)
       
  9587 				return false;
       
  9588 
       
  9589 			t.shortcuts = t.shortcuts || {};
       
  9590 
       
  9591 			if (is(cmd_func, 'string')) {
       
  9592 				c = cmd_func;
       
  9593 
       
  9594 				cmd_func = function() {
       
  9595 					t.execCommand(c, false, null);
       
  9596 				};
       
  9597 			}
       
  9598 
       
  9599 			if (is(cmd_func, 'object')) {
       
  9600 				c = cmd_func;
       
  9601 
       
  9602 				cmd_func = function() {
       
  9603 					t.execCommand(c[0], c[1], c[2]);
       
  9604 				};
       
  9605 			}
       
  9606 
       
  9607 			each(explode(pa), function(pa) {
       
  9608 				var o = {
       
  9609 					func : cmd_func,
       
  9610 					scope : sc || this,
       
  9611 					desc : desc,
       
  9612 					alt : false,
       
  9613 					ctrl : false,
       
  9614 					shift : false
       
  9615 				};
       
  9616 
       
  9617 				each(explode(pa, '+'), function(v) {
       
  9618 					switch (v) {
       
  9619 						case 'alt':
       
  9620 						case 'ctrl':
       
  9621 						case 'shift':
       
  9622 							o[v] = true;
       
  9623 							break;
       
  9624 
       
  9625 						default:
       
  9626 							o.charCode = v.charCodeAt(0);
       
  9627 							o.keyCode = v.toUpperCase().charCodeAt(0);
       
  9628 					}
       
  9629 				});
       
  9630 
       
  9631 				t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o;
       
  9632 			});
       
  9633 
       
  9634 			return true;
       
  9635 		},
       
  9636 
       
  9637 		execCommand : function(cmd, ui, val, a) {
       
  9638 			var t = this, s = 0, o, st;
       
  9639 
       
  9640 			if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus))
       
  9641 				t.focus();
       
  9642 
       
  9643 			o = {};
       
  9644 			t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o);
       
  9645 			if (o.terminate)
       
  9646 				return false;
       
  9647 
       
  9648 			// Command callback
       
  9649 			if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) {
       
  9650 				t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9651 				return true;
       
  9652 			}
       
  9653 
       
  9654 			// Registred commands
       
  9655 			if (o = t.execCommands[cmd]) {
       
  9656 				st = o.func.call(o.scope, ui, val);
       
  9657 
       
  9658 				// Fall through on true
       
  9659 				if (st !== true) {
       
  9660 					t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9661 					return st;
       
  9662 				}
       
  9663 			}
       
  9664 
       
  9665 			// Plugin commands
       
  9666 			each(t.plugins, function(p) {
       
  9667 				if (p.execCommand && p.execCommand(cmd, ui, val)) {
       
  9668 					t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9669 					s = 1;
       
  9670 					return false;
       
  9671 				}
       
  9672 			});
       
  9673 
       
  9674 			if (s)
       
  9675 				return true;
       
  9676 
       
  9677 			// Theme commands
       
  9678 			if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) {
       
  9679 				t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9680 				return true;
       
  9681 			}
       
  9682 
       
  9683 			// Execute global commands
       
  9684 			if (tinymce.GlobalCommands.execCommand(t, cmd, ui, val)) {
       
  9685 				t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9686 				return true;
       
  9687 			}
       
  9688 
       
  9689 			// Editor commands
       
  9690 			if (t.editorCommands.execCommand(cmd, ui, val)) {
       
  9691 				t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9692 				return true;
       
  9693 			}
       
  9694 
       
  9695 			// Browser commands
       
  9696 			t.getDoc().execCommand(cmd, ui, val);
       
  9697 			t.onExecCommand.dispatch(t, cmd, ui, val, a);
       
  9698 		},
       
  9699 
       
  9700 		queryCommandState : function(c) {
       
  9701 			var t = this, o, s;
       
  9702 
       
  9703 			// Is hidden then return undefined
       
  9704 			if (t._isHidden())
       
  9705 				return;
       
  9706 
       
  9707 			// Registred commands
       
  9708 			if (o = t.queryStateCommands[c]) {
       
  9709 				s = o.func.call(o.scope);
       
  9710 
       
  9711 				// Fall though on true
       
  9712 				if (s !== true)
       
  9713 					return s;
       
  9714 			}
       
  9715 
       
  9716 			// Registred commands
       
  9717 			o = t.editorCommands.queryCommandState(c);
       
  9718 			if (o !== -1)
       
  9719 				return o;
       
  9720 
       
  9721 			// Browser commands
       
  9722 			try {
       
  9723 				return this.getDoc().queryCommandState(c);
       
  9724 			} catch (ex) {
       
  9725 				// Fails sometimes see bug: 1896577
       
  9726 			}
       
  9727 		},
       
  9728 
       
  9729 		queryCommandValue : function(c) {
       
  9730 			var t = this, o, s;
       
  9731 
       
  9732 			// Is hidden then return undefined
       
  9733 			if (t._isHidden())
       
  9734 				return;
       
  9735 
       
  9736 			// Registred commands
       
  9737 			if (o = t.queryValueCommands[c]) {
       
  9738 				s = o.func.call(o.scope);
       
  9739 
       
  9740 				// Fall though on true
       
  9741 				if (s !== true)
       
  9742 					return s;
       
  9743 			}
       
  9744 
       
  9745 			// Registred commands
       
  9746 			o = t.editorCommands.queryCommandValue(c);
       
  9747 			if (is(o))
       
  9748 				return o;
       
  9749 
       
  9750 			// Browser commands
       
  9751 			try {
       
  9752 				return this.getDoc().queryCommandValue(c);
       
  9753 			} catch (ex) {
       
  9754 				// Fails sometimes see bug: 1896577
       
  9755 			}
       
  9756 		},
       
  9757 
       
  9758 		show : function() {
       
  9759 			var t = this;
       
  9760 
       
  9761 			DOM.show(t.getContainer());
       
  9762 			DOM.hide(t.id);
       
  9763 			t.load();
       
  9764 		},
       
  9765 
       
  9766 		hide : function() {
       
  9767 			var t = this, d = t.getDoc();
       
  9768 
       
  9769 			// Fixed bug where IE has a blinking cursor left from the editor
       
  9770 			if (isIE && d)
       
  9771 				d.execCommand('SelectAll');
       
  9772 
       
  9773 			// We must save before we hide so Safari doesn't crash
       
  9774 			t.save();
       
  9775 			DOM.hide(t.getContainer());
       
  9776 			DOM.setStyle(t.id, 'display', t.orgDisplay);
       
  9777 		},
       
  9778 
       
  9779 		isHidden : function() {
       
  9780 			return !DOM.isHidden(this.id);
       
  9781 		},
       
  9782 
       
  9783 		setProgressState : function(b, ti, o) {
       
  9784 			this.onSetProgressState.dispatch(this, b, ti, o);
       
  9785 
       
  9786 			return b;
       
  9787 		},
       
  9788 
       
  9789 		load : function(o) {
       
  9790 			var t = this, e = t.getElement(), h;
       
  9791 
       
  9792 			if (e) {
       
  9793 				o = o || {};
       
  9794 				o.load = true;
       
  9795 
       
  9796 				// Double encode existing entities in the value
       
  9797 				h = t.setContent(is(e.value) ? e.value : e.innerHTML, o);
       
  9798 				o.element = e;
       
  9799 
       
  9800 				if (!o.no_events)
       
  9801 					t.onLoadContent.dispatch(t, o);
       
  9802 
       
  9803 				o.element = e = null;
       
  9804 
       
  9805 				return h;
       
  9806 			}
       
  9807 		},
       
  9808 
       
  9809 		save : function(o) {
       
  9810 			var t = this, e = t.getElement(), h, f;
       
  9811 
       
  9812 			if (!e || !t.initialized)
       
  9813 				return;
       
  9814 
       
  9815 			o = o || {};
       
  9816 			o.save = true;
       
  9817 
       
  9818 			// Add undo level will trigger onchange event
       
  9819 			if (!o.no_events) {
       
  9820 				t.undoManager.typing = 0;
       
  9821 				t.undoManager.add();
       
  9822 			}
       
  9823 
       
  9824 			o.element = e;
       
  9825 			h = o.content = t.getContent(o);
       
  9826 
       
  9827 			if (!o.no_events)
       
  9828 				t.onSaveContent.dispatch(t, o);
       
  9829 
       
  9830 			h = o.content;
       
  9831 
       
  9832 			if (!/TEXTAREA|INPUT/i.test(e.nodeName)) {
       
  9833 				e.innerHTML = h;
       
  9834 
       
  9835 				// Update hidden form element
       
  9836 				if (f = DOM.getParent(t.id, 'form')) {
       
  9837 					each(f.elements, function(e) {
       
  9838 						if (e.name == t.id) {
       
  9839 							e.value = h;
       
  9840 							return false;
       
  9841 						}
       
  9842 					});
       
  9843 				}
       
  9844 			} else
       
  9845 				e.value = h;
       
  9846 
       
  9847 			o.element = e = null;
       
  9848 
       
  9849 			return h;
       
  9850 		},
       
  9851 
       
  9852 		setContent : function(h, o) {
       
  9853 			var t = this;
       
  9854 
       
  9855 			o = o || {};
       
  9856 			o.format = o.format || 'html';
       
  9857 			o.set = true;
       
  9858 			o.content = h;
       
  9859 
       
  9860 			if (!o.no_events)
       
  9861 				t.onBeforeSetContent.dispatch(t, o);
       
  9862 
       
  9863 			// Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
       
  9864 			// It will also be impossible to place the caret in the editor unless there is a BR element present
       
  9865 			if (!tinymce.isIE && (h.length === 0 || /^\s+$/.test(h))) {
       
  9866 				o.content = t.dom.setHTML(t.getBody(), '<br mce_bogus="1" />');
       
  9867 				o.format = 'raw';
       
  9868 			}
       
  9869 
       
  9870 			o.content = t.dom.setHTML(t.getBody(), tinymce.trim(o.content));
       
  9871 
       
  9872 			if (o.format != 'raw' && t.settings.cleanup) {
       
  9873 				o.getInner = true;
       
  9874 				o.content = t.dom.setHTML(t.getBody(), t.serializer.serialize(t.getBody(), o));
       
  9875 			}
       
  9876 
       
  9877 			if (!o.no_events)
       
  9878 				t.onSetContent.dispatch(t, o);
       
  9879 
       
  9880 			return o.content;
       
  9881 		},
       
  9882 
       
  9883 		getContent : function(o) {
       
  9884 			var t = this, h;
       
  9885 
       
  9886 			o = o || {};
       
  9887 			o.format = o.format || 'html';
       
  9888 			o.get = true;
       
  9889 
       
  9890 			if (!o.no_events)
       
  9891 				t.onBeforeGetContent.dispatch(t, o);
       
  9892 
       
  9893 			if (o.format != 'raw' && t.settings.cleanup) {
       
  9894 				o.getInner = true;
       
  9895 				h = t.serializer.serialize(t.getBody(), o);
       
  9896 			} else
       
  9897 				h = t.getBody().innerHTML;
       
  9898 
       
  9899 			h = h.replace(/^\s*|\s*$/g, '');
       
  9900 			o.content = h;
       
  9901 
       
  9902 			if (!o.no_events)
       
  9903 				t.onGetContent.dispatch(t, o);
       
  9904 
       
  9905 			return o.content;
       
  9906 		},
       
  9907 
       
  9908 		isDirty : function() {
       
  9909 			var t = this;
       
  9910 
       
  9911 			return tinymce.trim(t.startContent) != tinymce.trim(t.getContent({format : 'raw', no_events : 1})) && !t.isNotDirty;
       
  9912 		},
       
  9913 
       
  9914 		getContainer : function() {
       
  9915 			var t = this;
       
  9916 
       
  9917 			if (!t.container)
       
  9918 				t.container = DOM.get(t.editorContainer || t.id + '_parent');
       
  9919 
       
  9920 			return t.container;
       
  9921 		},
       
  9922 
       
  9923 		getContentAreaContainer : function() {
       
  9924 			return this.contentAreaContainer;
       
  9925 		},
       
  9926 
       
  9927 		getElement : function() {
       
  9928 			return DOM.get(this.settings.content_element || this.id);
       
  9929 		},
       
  9930 
       
  9931 		getWin : function() {
       
  9932 			var t = this, e;
       
  9933 
       
  9934 			if (!t.contentWindow) {
       
  9935 				e = DOM.get(t.id + "_ifr");
       
  9936 
       
  9937 				if (e)
       
  9938 					t.contentWindow = e.contentWindow;
       
  9939 			}
       
  9940 
       
  9941 			return t.contentWindow;
       
  9942 		},
       
  9943 
       
  9944 		getDoc : function() {
       
  9945 			var t = this, w;
       
  9946 
       
  9947 			if (!t.contentDocument) {
       
  9948 				w = t.getWin();
       
  9949 
       
  9950 				if (w)
       
  9951 					t.contentDocument = w.document;
       
  9952 			}
       
  9953 
       
  9954 			return t.contentDocument;
       
  9955 		},
       
  9956 
       
  9957 		getBody : function() {
       
  9958 			return this.bodyElement || this.getDoc().body;
       
  9959 		},
       
  9960 
       
  9961 		convertURL : function(u, n, e) {
       
  9962 			var t = this, s = t.settings;
       
  9963 
       
  9964 			// Use callback instead
       
  9965 			if (s.urlconverter_callback)
       
  9966 				return t.execCallback('urlconverter_callback', u, e, true, n);
       
  9967 
       
  9968 			// Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
       
  9969 			if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
       
  9970 				return u;
       
  9971 
       
  9972 			// Convert to relative
       
  9973 			if (s.relative_urls)
       
  9974 				return t.documentBaseURI.toRelative(u);
       
  9975 
       
  9976 			// Convert to absolute
       
  9977 			u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);
       
  9978 
       
  9979 			return u;
       
  9980 		},
       
  9981 
       
  9982 		addVisual : function(e) {
       
  9983 			var t = this, s = t.settings;
       
  9984 
       
  9985 			e = e || t.getBody();
       
  9986 
       
  9987 			if (!is(t.hasVisual))
       
  9988 				t.hasVisual = s.visual;
       
  9989 
       
  9990 			each(t.dom.select('table,a', e), function(e) {
       
  9991 				var v;
       
  9992 
       
  9993 				switch (e.nodeName) {
       
  9994 					case 'TABLE':
       
  9995 						v = t.dom.getAttrib(e, 'border');
       
  9996 
       
  9997 						if (!v || v == '0') {
       
  9998 							if (t.hasVisual)
       
  9999 								t.dom.addClass(e, s.visual_table_class);
       
 10000 							else
       
 10001 								t.dom.removeClass(e, s.visual_table_class);
       
 10002 						}
       
 10003 
       
 10004 						return;
       
 10005 
       
 10006 					case 'A':
       
 10007 						v = t.dom.getAttrib(e, 'name');
       
 10008 
       
 10009 						if (v) {
       
 10010 							if (t.hasVisual)
       
 10011 								t.dom.addClass(e, 'mceItemAnchor');
       
 10012 							else
       
 10013 								t.dom.removeClass(e, 'mceItemAnchor');
       
 10014 						}
       
 10015 
       
 10016 						return;
       
 10017 				}
       
 10018 			});
       
 10019 
       
 10020 			t.onVisualAid.dispatch(t, e, t.hasVisual);
       
 10021 		},
       
 10022 
       
 10023 		remove : function() {
       
 10024 			var t = this, e = t.getContainer();
       
 10025 
       
 10026 			t.removed = 1; // Cancels post remove event execution
       
 10027 			t.hide();
       
 10028 
       
 10029 			t.execCallback('remove_instance_callback', t);
       
 10030 			t.onRemove.dispatch(t);
       
 10031 
       
 10032 			// Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command
       
 10033 			t.onExecCommand.listeners = [];
       
 10034 
       
 10035 			EditorManager.remove(t);
       
 10036 			DOM.remove(e);
       
 10037 		},
       
 10038 
       
 10039 		destroy : function(s) {
       
 10040 			var t = this;
       
 10041 
       
 10042 			// One time is enough
       
 10043 			if (t.destroyed)
       
 10044 				return;
       
 10045 
       
 10046 			if (!s) {
       
 10047 				tinymce.removeUnload(t.destroy);
       
 10048 				tinyMCE.onBeforeUnload.remove(t._beforeUnload);
       
 10049 
       
 10050 				// Manual destroy
       
 10051 				if (t.theme && t.theme.destroy)
       
 10052 					t.theme.destroy();
       
 10053 
       
 10054 				// Destroy controls, selection and dom
       
 10055 				t.controlManager.destroy();
       
 10056 				t.selection.destroy();
       
 10057 				t.dom.destroy();
       
 10058 
       
 10059 				// Remove all events
       
 10060 
       
 10061 				// Don't clear the window or document if content editable
       
 10062 				// is enabled since other instances might still be present
       
 10063 				if (!t.settings.content_editable) {
       
 10064 					Event.clear(t.getWin());
       
 10065 					Event.clear(t.getDoc());
       
 10066 				}
       
 10067 
       
 10068 				Event.clear(t.getBody());
       
 10069 				Event.clear(t.formElement);
       
 10070 			}
       
 10071 
       
 10072 			if (t.formElement) {
       
 10073 				t.formElement.submit = t.formElement._mceOldSubmit;
       
 10074 				t.formElement._mceOldSubmit = null;
       
 10075 			}
       
 10076 
       
 10077 			t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null;
       
 10078 
       
 10079 			if (t.selection)
       
 10080 				t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null;
       
 10081 
       
 10082 			t.destroyed = 1;
       
 10083 		},
       
 10084 
       
 10085 		// Internal functions
       
 10086 
       
 10087 		_addEvents : function() {
       
 10088 			// 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset
       
 10089 			var t = this, i, s = t.settings, lo = {
       
 10090 				mouseup : 'onMouseUp',
       
 10091 				mousedown : 'onMouseDown',
       
 10092 				click : 'onClick',
       
 10093 				keyup : 'onKeyUp',
       
 10094 				keydown : 'onKeyDown',
       
 10095 				keypress : 'onKeyPress',
       
 10096 				submit : 'onSubmit',
       
 10097 				reset : 'onReset',
       
 10098 				contextmenu : 'onContextMenu',
       
 10099 				dblclick : 'onDblClick',
       
 10100 				paste : 'onPaste' // Doesn't work in all browsers yet
       
 10101 			};
       
 10102 
       
 10103 			function eventHandler(e, o) {
       
 10104 				var ty = e.type;
       
 10105 
       
 10106 				// Don't fire events when it's removed
       
 10107 				if (t.removed)
       
 10108 					return;
       
 10109 
       
 10110 				// Generic event handler
       
 10111 				if (t.onEvent.dispatch(t, e, o) !== false) {
       
 10112 					// Specific event handler
       
 10113 					t[lo[e.fakeType || e.type]].dispatch(t, e, o);
       
 10114 				}
       
 10115 			};
       
 10116 
       
 10117 			// Add DOM events
       
 10118 			each(lo, function(v, k) {
       
 10119 				switch (k) {
       
 10120 					case 'contextmenu':
       
 10121 						if (tinymce.isOpera) {
       
 10122 							// Fake contextmenu on Opera
       
 10123 							t.dom.bind(t.getBody(), 'mousedown', function(e) {
       
 10124 								if (e.ctrlKey) {
       
 10125 									e.fakeType = 'contextmenu';
       
 10126 									eventHandler(e);
       
 10127 								}
       
 10128 							});
       
 10129 						} else
       
 10130 							t.dom.bind(t.getBody(), k, eventHandler);
       
 10131 						break;
       
 10132 
       
 10133 					case 'paste':
       
 10134 						t.dom.bind(t.getBody(), k, function(e) {
       
 10135 							eventHandler(e);
       
 10136 						});
       
 10137 						break;
       
 10138 
       
 10139 					case 'submit':
       
 10140 					case 'reset':
       
 10141 						t.dom.bind(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler);
       
 10142 						break;
       
 10143 
       
 10144 					default:
       
 10145 						t.dom.bind(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler);
       
 10146 				}
       
 10147 			});
       
 10148 
       
 10149 			t.dom.bind(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) {
       
 10150 				t.focus(true);
       
 10151 			});
       
 10152 
       
 10153 
       
 10154 			// Fixes bug where a specified document_base_uri could result in broken images
       
 10155 			// This will also fix drag drop of images in Gecko
       
 10156 			if (tinymce.isGecko) {
       
 10157 				// Convert all images to absolute URLs
       
 10158 /*				t.onSetContent.add(function(ed, o) {
       
 10159 					each(ed.dom.select('img'), function(e) {
       
 10160 						var v;
       
 10161 
       
 10162 						if (v = e.getAttribute('mce_src'))
       
 10163 							e.src = t.documentBaseURI.toAbsolute(v);
       
 10164 					})
       
 10165 				});*/
       
 10166 
       
 10167 				t.dom.bind(t.getDoc(), 'DOMNodeInserted', function(e) {
       
 10168 					var v;
       
 10169 
       
 10170 					e = e.target;
       
 10171 
       
 10172 					if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('mce_src')))
       
 10173 						e.src = t.documentBaseURI.toAbsolute(v);
       
 10174 				});
       
 10175 			}
       
 10176 
       
 10177 			// Set various midas options in Gecko
       
 10178 			if (isGecko) {
       
 10179 				function setOpts() {
       
 10180 					var t = this, d = t.getDoc(), s = t.settings;
       
 10181 
       
 10182 					if (isGecko && !s.readonly) {
       
 10183 						if (t._isHidden()) {
       
 10184 							try {
       
 10185 								if (!s.content_editable)
       
 10186 									d.designMode = 'On';
       
 10187 							} catch (ex) {
       
 10188 								// Fails if it's hidden
       
 10189 							}
       
 10190 						}
       
 10191 
       
 10192 						try {
       
 10193 							// Try new Gecko method
       
 10194 							d.execCommand("styleWithCSS", 0, false);
       
 10195 						} catch (ex) {
       
 10196 							// Use old method
       
 10197 							if (!t._isHidden())
       
 10198 								try {d.execCommand("useCSS", 0, true);} catch (ex) {}
       
 10199 						}
       
 10200 
       
 10201 						if (!s.table_inline_editing)
       
 10202 							try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {}
       
 10203 
       
 10204 						if (!s.object_resizing)
       
 10205 							try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {}
       
 10206 					}
       
 10207 				};
       
 10208 
       
 10209 				t.onBeforeExecCommand.add(setOpts);
       
 10210 				t.onMouseDown.add(setOpts);
       
 10211 			}
       
 10212 
       
 10213 			// Add node change handlers
       
 10214 			t.onMouseUp.add(t.nodeChanged);
       
 10215 			t.onClick.add(t.nodeChanged);
       
 10216 			t.onKeyUp.add(function(ed, e) {
       
 10217 				var c = e.keyCode;
       
 10218 
       
 10219 				if ((c >= 33 && c <= 36) || (c >= 37 && c <= 40) || c == 13 || c == 45 || c == 46 || c == 8 || (tinymce.isMac && (c == 91 || c == 93)) || e.ctrlKey)
       
 10220 					t.nodeChanged();
       
 10221 			});
       
 10222 
       
 10223 			// Add reset handler
       
 10224 			t.onReset.add(function() {
       
 10225 				t.setContent(t.startContent, {format : 'raw'});
       
 10226 			});
       
 10227 
       
 10228 			// Add shortcuts
       
 10229 			if (s.custom_shortcuts) {
       
 10230 				if (s.custom_undo_redo_keyboard_shortcuts) {
       
 10231 					t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo');
       
 10232 					t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo');
       
 10233 				}
       
 10234 
       
 10235 				// Add default shortcuts for gecko
       
 10236 				if (isGecko) {
       
 10237 					t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');
       
 10238 					t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');
       
 10239 					t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');
       
 10240 				}
       
 10241 
       
 10242 				// BlockFormat shortcuts keys
       
 10243 				for (i=1; i<=6; i++)
       
 10244 					t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, '<h' + i + '>']);
       
 10245 
       
 10246 				t.addShortcut('ctrl+7', '', ['FormatBlock', false, '<p>']);
       
 10247 				t.addShortcut('ctrl+8', '', ['FormatBlock', false, '<div>']);
       
 10248 				t.addShortcut('ctrl+9', '', ['FormatBlock', false, '<address>']);
       
 10249 
       
 10250 				function find(e) {
       
 10251 					var v = null;
       
 10252 
       
 10253 					if (!e.altKey && !e.ctrlKey && !e.metaKey)
       
 10254 						return v;
       
 10255 
       
 10256 					each(t.shortcuts, function(o) {
       
 10257 						if (tinymce.isMac && o.ctrl != e.metaKey)
       
 10258 							return;
       
 10259 						else if (!tinymce.isMac && o.ctrl != e.ctrlKey)
       
 10260 							return;
       
 10261 
       
 10262 						if (o.alt != e.altKey)
       
 10263 							return;
       
 10264 
       
 10265 						if (o.shift != e.shiftKey)
       
 10266 							return;
       
 10267 
       
 10268 						if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
       
 10269 							v = o;
       
 10270 							return false;
       
 10271 						}
       
 10272 					});
       
 10273 
       
 10274 					return v;
       
 10275 				};
       
 10276 
       
 10277 				t.onKeyUp.add(function(ed, e) {
       
 10278 					var o = find(e);
       
 10279 
       
 10280 					if (o)
       
 10281 						return Event.cancel(e);
       
 10282 				});
       
 10283 
       
 10284 				t.onKeyPress.add(function(ed, e) {
       
 10285 					var o = find(e);
       
 10286 
       
 10287 					if (o)
       
 10288 						return Event.cancel(e);
       
 10289 				});
       
 10290 
       
 10291 				t.onKeyDown.add(function(ed, e) {
       
 10292 					var o = find(e);
       
 10293 
       
 10294 					if (o) {
       
 10295 						o.func.call(o.scope);
       
 10296 						return Event.cancel(e);
       
 10297 					}
       
 10298 				});
       
 10299 			}
       
 10300 
       
 10301 			if (tinymce.isIE) {
       
 10302 				// Fix so resize will only update the width and height attributes not the styles of an image
       
 10303 				// It will also block mceItemNoResize items
       
 10304 				t.dom.bind(t.getDoc(), 'controlselect', function(e) {
       
 10305 					var re = t.resizeInfo, cb;
       
 10306 
       
 10307 					e = e.target;
       
 10308 
       
 10309 					// Don't do this action for non image elements
       
 10310 					if (e.nodeName !== 'IMG')
       
 10311 						return;
       
 10312 
       
 10313 					if (re)
       
 10314 						t.dom.unbind(re.node, re.ev, re.cb);
       
 10315 
       
 10316 					if (!t.dom.hasClass(e, 'mceItemNoResize')) {
       
 10317 						ev = 'resizeend';
       
 10318 						cb = t.dom.bind(e, ev, function(e) {
       
 10319 							var v;
       
 10320 
       
 10321 							e = e.target;
       
 10322 
       
 10323 							if (v = t.dom.getStyle(e, 'width')) {
       
 10324 								t.dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, ''));
       
 10325 								t.dom.setStyle(e, 'width', '');
       
 10326 							}
       
 10327 
       
 10328 							if (v = t.dom.getStyle(e, 'height')) {
       
 10329 								t.dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, ''));
       
 10330 								t.dom.setStyle(e, 'height', '');
       
 10331 							}
       
 10332 						});
       
 10333 					} else {
       
 10334 						ev = 'resizestart';
       
 10335 						cb = t.dom.bind(e, 'resizestart', Event.cancel, Event);
       
 10336 					}
       
 10337 
       
 10338 					re = t.resizeInfo = {
       
 10339 						node : e,
       
 10340 						ev : ev,
       
 10341 						cb : cb
       
 10342 					};
       
 10343 				});
       
 10344 
       
 10345 				t.onKeyDown.add(function(ed, e) {
       
 10346 					switch (e.keyCode) {
       
 10347 						case 8:
       
 10348 							// Fix IE control + backspace browser bug
       
 10349 							if (t.selection.getRng().item) {
       
 10350 								t.selection.getRng().item(0).removeNode();
       
 10351 								return Event.cancel(e);
       
 10352 							}
       
 10353 					}
       
 10354 				});
       
 10355 
       
 10356 				/*if (t.dom.boxModel) {
       
 10357 					t.getBody().style.height = '100%';
       
 10358 
       
 10359 					Event.add(t.getWin(), 'resize', function(e) {
       
 10360 						var docElm = t.getDoc().documentElement;
       
 10361 
       
 10362 						docElm.style.height = (docElm.offsetHeight - 10) + 'px';
       
 10363 					});
       
 10364 				}*/
       
 10365 			}
       
 10366 
       
 10367 			if (tinymce.isOpera) {
       
 10368 				t.onClick.add(function(ed, e) {
       
 10369 					Event.prevent(e);
       
 10370 				});
       
 10371 			}
       
 10372 
       
 10373 			// Add custom undo/redo handlers
       
 10374 			if (s.custom_undo_redo) {
       
 10375 				function addUndo() {
       
 10376 					t.undoManager.typing = 0;
       
 10377 					t.undoManager.add();
       
 10378 				};
       
 10379 
       
 10380 				// Add undo level on editor blur
       
 10381 				if (tinymce.isIE) {
       
 10382 					t.dom.bind(t.getWin(), 'blur', function(e) {
       
 10383 						var n;
       
 10384 
       
 10385 						// Check added for fullscreen bug
       
 10386 						if (t.selection) {
       
 10387 							n = t.selection.getNode();
       
 10388 
       
 10389 							// Add undo level is selection was lost to another document
       
 10390 							if (!t.removed && n.ownerDocument && n.ownerDocument != t.getDoc())
       
 10391 								addUndo();
       
 10392 						}
       
 10393 					});
       
 10394 				} else {
       
 10395 					t.dom.bind(t.getDoc(), 'blur', function() {
       
 10396 						if (t.selection && !t.removed)
       
 10397 							addUndo();
       
 10398 					});
       
 10399 				}
       
 10400 
       
 10401 				t.onMouseDown.add(addUndo);
       
 10402 
       
 10403 				t.onKeyUp.add(function(ed, e) {
       
 10404 					if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) {
       
 10405 						t.undoManager.typing = 0;
       
 10406 						t.undoManager.add();
       
 10407 					}
       
 10408 				});
       
 10409 
       
 10410 				t.onKeyDown.add(function(ed, e) {
       
 10411 					// Is caracter positon keys
       
 10412 					if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {
       
 10413 						if (t.undoManager.typing) {
       
 10414 							t.undoManager.add();
       
 10415 							t.undoManager.typing = 0;
       
 10416 						}
       
 10417 
       
 10418 						return;
       
 10419 					}
       
 10420 
       
 10421 					if (!t.undoManager.typing) {
       
 10422 						t.undoManager.add();
       
 10423 						t.undoManager.typing = 1;
       
 10424 					}
       
 10425 				});
       
 10426 			}
       
 10427 		},
       
 10428 
       
 10429 		_convertInlineElements : function() {
       
 10430 			var t = this, s = t.settings, dom = t.dom, v, e, na, st, sp;
       
 10431 
       
 10432 			function convert(ed, o) {
       
 10433 				if (!s.inline_styles)
       
 10434 					return;
       
 10435 
       
 10436 				if (o.get) {
       
 10437 					each(t.dom.select('table,u,strike', o.node), function(n) {
       
 10438 						switch (n.nodeName) {
       
 10439 							case 'TABLE':
       
 10440 								if (v = dom.getAttrib(n, 'height')) {
       
 10441 									dom.setStyle(n, 'height', v);
       
 10442 									dom.setAttrib(n, 'height', '');
       
 10443 								}
       
 10444 								break;
       
 10445 
       
 10446 							case 'U':
       
 10447 							case 'STRIKE':
       
 10448 								//sp = dom.create('span', {style : dom.getAttrib(n, 'style')});
       
 10449 								n.style.textDecoration = n.nodeName == 'U' ? 'underline' : 'line-through';
       
 10450 								dom.setAttrib(n, 'mce_style', '');
       
 10451 								dom.setAttrib(n, 'mce_name', 'span');
       
 10452 								break;
       
 10453 						}
       
 10454 					});
       
 10455 				} else if (o.set) {
       
 10456 					each(t.dom.select('table,span', o.node).reverse(), function(n) {
       
 10457 						if (n.nodeName == 'TABLE') {
       
 10458 							if (v = dom.getStyle(n, 'height'))
       
 10459 								dom.setAttrib(n, 'height', v.replace(/[^0-9%]+/g, ''));
       
 10460 						} else {
       
 10461 							// Convert spans to elements
       
 10462 							if (n.style.textDecoration == 'underline')
       
 10463 								na = 'u';
       
 10464 							else if (n.style.textDecoration == 'line-through')
       
 10465 								na = 'strike';
       
 10466 							else
       
 10467 								na = '';
       
 10468 
       
 10469 							if (na) {
       
 10470 								n.style.textDecoration = '';
       
 10471 								dom.setAttrib(n, 'mce_style', '');
       
 10472 
       
 10473 								e = dom.create(na, {
       
 10474 									style : dom.getAttrib(n, 'style')
       
 10475 								});
       
 10476 
       
 10477 								dom.replace(e, n, 1);
       
 10478 							}
       
 10479 						}
       
 10480 					});
       
 10481 				}
       
 10482 			};
       
 10483 
       
 10484 			t.onPreProcess.add(convert);
       
 10485 
       
 10486 			if (!s.cleanup_on_startup) {
       
 10487 				t.onSetContent.add(function(ed, o) {
       
 10488 					if (o.initial)
       
 10489 						convert(t, {node : t.getBody(), set : 1});
       
 10490 				});
       
 10491 			}
       
 10492 		},
       
 10493 
       
 10494 		_convertFonts : function() {
       
 10495 			var t = this, s = t.settings, dom = t.dom, fz, fzn, sl, cl;
       
 10496 
       
 10497 			// No need
       
 10498 			if (!s.inline_styles)
       
 10499 				return;
       
 10500 
       
 10501 			// Font pt values and font size names
       
 10502 			fz = [8, 10, 12, 14, 18, 24, 36];
       
 10503 			fzn = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large'];
       
 10504 
       
 10505 			if (sl = s.font_size_style_values)
       
 10506 				sl = explode(sl);
       
 10507 
       
 10508 			if (cl = s.font_size_classes)
       
 10509 				cl = explode(cl);
       
 10510 
       
 10511 			function process(no) {
       
 10512 				var n, sp, nl, x;
       
 10513 
       
 10514 				// Keep unit tests happy
       
 10515 				if (!s.inline_styles)
       
 10516 					return;
       
 10517 
       
 10518 				nl = t.dom.select('font', no);
       
 10519 				for (x = nl.length - 1; x >= 0; x--) {
       
 10520 					n = nl[x];
       
 10521 
       
 10522 					sp = dom.create('span', {
       
 10523 						style : dom.getAttrib(n, 'style'),
       
 10524 						'class' : dom.getAttrib(n, 'class')
       
 10525 					});
       
 10526 
       
 10527 					dom.setStyles(sp, {
       
 10528 						fontFamily : dom.getAttrib(n, 'face'),
       
 10529 						color : dom.getAttrib(n, 'color'),
       
 10530 						backgroundColor : n.style.backgroundColor
       
 10531 					});
       
 10532 
       
 10533 					if (n.size) {
       
 10534 						if (sl)
       
 10535 							dom.setStyle(sp, 'fontSize', sl[parseInt(n.size) - 1]);
       
 10536 						else
       
 10537 							dom.setAttrib(sp, 'class', cl[parseInt(n.size) - 1]);
       
 10538 					}
       
 10539 
       
 10540 					dom.setAttrib(sp, 'mce_style', '');
       
 10541 					dom.replace(sp, n, 1);
       
 10542 				}
       
 10543 			};
       
 10544 
       
 10545 			// Run on cleanup
       
 10546 			t.onPreProcess.add(function(ed, o) {
       
 10547 				if (o.get)
       
 10548 					process(o.node);
       
 10549 			});
       
 10550 
       
 10551 			t.onSetContent.add(function(ed, o) {
       
 10552 				if (o.initial)
       
 10553 					process(o.node);
       
 10554 			});
       
 10555 		},
       
 10556 
       
 10557 		_isHidden : function() {
       
 10558 			var s;
       
 10559 
       
 10560 			if (!isGecko)
       
 10561 				return 0;
       
 10562 
       
 10563 			// Weird, wheres that cursor selection?
       
 10564 			s = this.selection.getSel();
       
 10565 			return (!s || !s.rangeCount || s.rangeCount == 0);
       
 10566 		},
       
 10567 
       
 10568 		// Fix for bug #1867292
       
 10569 		_fixNesting : function(s) {
       
 10570 			var d = [], i;
       
 10571 
       
 10572 			s = s.replace(/<(\/)?([^\s>]+)[^>]*?>/g, function(a, b, c) {
       
 10573 				var e;
       
 10574 
       
 10575 				// Handle end element
       
 10576 				if (b === '/') {
       
 10577 					if (!d.length)
       
 10578 						return '';
       
 10579 
       
 10580 					if (c !== d[d.length - 1].tag) {
       
 10581 						for (i=d.length - 1; i>=0; i--) {
       
 10582 							if (d[i].tag === c) {
       
 10583 								d[i].close = 1;
       
 10584 								break;
       
 10585 							}
       
 10586 						}
       
 10587 
       
 10588 						return '';
       
 10589 					} else {
       
 10590 						d.pop();
       
 10591 
       
 10592 						if (d.length && d[d.length - 1].close) {
       
 10593 							a = a + '</' + d[d.length - 1].tag + '>';
       
 10594 							d.pop();
       
 10595 						}
       
 10596 					}
       
 10597 				} else {
       
 10598 					// Ignore these
       
 10599 					if (/^(br|hr|input|meta|img|link|param)$/i.test(c))
       
 10600 						return a;
       
 10601 
       
 10602 					// Ignore closed ones
       
 10603 					if (/\/>$/.test(a))
       
 10604 						return a;
       
 10605 
       
 10606 					d.push({tag : c}); // Push start element
       
 10607 				}
       
 10608 
       
 10609 				return a;
       
 10610 			});
       
 10611 
       
 10612 			// End all open tags
       
 10613 			for (i=d.length - 1; i>=0; i--)
       
 10614 				s += '</' + d[i].tag + '>';
       
 10615 
       
 10616 			return s;
       
 10617 		}
       
 10618 	});
       
 10619 })(tinymce);
       
 10620 (function(tinymce) {
       
 10621 	var each = tinymce.each, isIE = tinymce.isIE, isGecko = tinymce.isGecko, isOpera = tinymce.isOpera, isWebKit = tinymce.isWebKit;
       
 10622 
       
 10623 	tinymce.create('tinymce.EditorCommands', {
       
 10624 		EditorCommands : function(ed) {
       
 10625 			this.editor = ed;
       
 10626 		},
       
 10627 
       
 10628 		execCommand : function(cmd, ui, val) {
       
 10629 			var t = this, ed = t.editor, f;
       
 10630 
       
 10631 			switch (cmd) {
       
 10632 				// Ignore these
       
 10633 				case 'mceResetDesignMode':
       
 10634 				case 'mceBeginUndoLevel':
       
 10635 					return true;
       
 10636 
       
 10637 				// Ignore these
       
 10638 				case 'unlink':
       
 10639 					t.UnLink();
       
 10640 					return true;
       
 10641 
       
 10642 				// Bundle these together
       
 10643 				case 'JustifyLeft':
       
 10644 				case 'JustifyCenter':
       
 10645 				case 'JustifyRight':
       
 10646 				case 'JustifyFull':
       
 10647 					t.mceJustify(cmd, cmd.substring(7).toLowerCase());
       
 10648 					return true;
       
 10649 
       
 10650 				default:
       
 10651 					f = this[cmd];
       
 10652 
       
 10653 					if (f) {
       
 10654 						f.call(this, ui, val);
       
 10655 						return true;
       
 10656 					}
       
 10657 			}
       
 10658 
       
 10659 			return false;
       
 10660 		},
       
 10661 
       
 10662 		Indent : function() {
       
 10663 			var ed = this.editor, d = ed.dom, s = ed.selection, e, iv, iu;
       
 10664 
       
 10665 			// Setup indent level
       
 10666 			iv = ed.settings.indentation;
       
 10667 			iu = /[a-z%]+$/i.exec(iv);
       
 10668 			iv = parseInt(iv);
       
 10669 
       
 10670 			if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {
       
 10671 				each(s.getSelectedBlocks(), function(e) {
       
 10672 					d.setStyle(e, 'paddingLeft', (parseInt(e.style.paddingLeft || 0) + iv) + iu);
       
 10673 				});
       
 10674 
       
 10675 				return;
       
 10676 			}
       
 10677 
       
 10678 			ed.getDoc().execCommand('Indent', false, null);
       
 10679 
       
 10680 			if (isIE) {
       
 10681 				d.getParent(s.getNode(), function(n) {
       
 10682 					if (n.nodeName == 'BLOCKQUOTE') {
       
 10683 						n.dir = n.style.cssText = '';
       
 10684 					}
       
 10685 				});
       
 10686 			}
       
 10687 		},
       
 10688 
       
 10689 		Outdent : function() {
       
 10690 			var ed = this.editor, d = ed.dom, s = ed.selection, e, v, iv, iu;
       
 10691 
       
 10692 			// Setup indent level
       
 10693 			iv = ed.settings.indentation;
       
 10694 			iu = /[a-z%]+$/i.exec(iv);
       
 10695 			iv = parseInt(iv);
       
 10696 
       
 10697 			if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {
       
 10698 				each(s.getSelectedBlocks(), function(e) {
       
 10699 					v = Math.max(0, parseInt(e.style.paddingLeft || 0) - iv);
       
 10700 					d.setStyle(e, 'paddingLeft', v ? v + iu : '');
       
 10701 				});
       
 10702 
       
 10703 				return;
       
 10704 			}
       
 10705 
       
 10706 			ed.getDoc().execCommand('Outdent', false, null);
       
 10707 		},
       
 10708 
       
 10709 /*
       
 10710 		mceSetAttribute : function(u, v) {
       
 10711 			var ed = this.editor, d = ed.dom, e;
       
 10712 
       
 10713 			if (e = d.getParent(ed.selection.getNode(), d.isBlock))
       
 10714 				d.setAttrib(e, v.name, v.value);
       
 10715 		},
       
 10716 */
       
 10717 		mceSetContent : function(u, v) {
       
 10718 			this.editor.setContent(v);
       
 10719 		},
       
 10720 
       
 10721 		mceToggleVisualAid : function() {
       
 10722 			var ed = this.editor;
       
 10723 
       
 10724 			ed.hasVisual = !ed.hasVisual;
       
 10725 			ed.addVisual();
       
 10726 		},
       
 10727 
       
 10728 		mceReplaceContent : function(u, v) {
       
 10729 			var s = this.editor.selection;
       
 10730 
       
 10731 			s.setContent(v.replace(/\{\$selection\}/g, s.getContent({format : 'text'})));
       
 10732 		},
       
 10733 
       
 10734 		mceInsertLink : function(u, v) {
       
 10735 			var ed = this.editor, s = ed.selection, e = ed.dom.getParent(s.getNode(), 'a');
       
 10736 
       
 10737 			if (tinymce.is(v, 'string'))
       
 10738 				v = {href : v};
       
 10739 
       
 10740 			function set(e) {
       
 10741 				each(v, function(v, k) {
       
 10742 					ed.dom.setAttrib(e, k, v);
       
 10743 				});
       
 10744 			};
       
 10745 
       
 10746 			if (!e) {
       
 10747 				ed.execCommand('CreateLink', false, 'javascript:mctmp(0);');
       
 10748 				each(ed.dom.select('a[href=javascript:mctmp(0);]'), function(e) {
       
 10749 					set(e);
       
 10750 				});
       
 10751 			} else {
       
 10752 				if (v.href)
       
 10753 					set(e);
       
 10754 				else
       
 10755 					ed.dom.remove(e, 1);
       
 10756 			}
       
 10757 		},
       
 10758 
       
 10759 		UnLink : function() {
       
 10760 			var ed = this.editor, s = ed.selection;
       
 10761 
       
 10762 			if (s.isCollapsed())
       
 10763 				s.select(s.getNode());
       
 10764 
       
 10765 			ed.getDoc().execCommand('unlink', false, null);
       
 10766 			s.collapse(0);
       
 10767 		},
       
 10768 
       
 10769 		FontName : function(u, v) {
       
 10770 			var t = this, ed = t.editor, s = ed.selection, e;
       
 10771 
       
 10772 			if (!v) {
       
 10773 				if (s.isCollapsed())
       
 10774 					s.select(s.getNode());
       
 10775 			} else {
       
 10776 				if (ed.settings.convert_fonts_to_spans)
       
 10777 					t._applyInlineStyle('span', {style : {fontFamily : v}});
       
 10778 				else
       
 10779 					ed.getDoc().execCommand('FontName', false, v);
       
 10780 			}
       
 10781 		},
       
 10782 
       
 10783 		FontSize : function(u, v) {
       
 10784 			var ed = this.editor, s = ed.settings, fc, fs;
       
 10785 
       
 10786 			// Use style options instead
       
 10787 			if (s.convert_fonts_to_spans && v >= 1 && v <= 7) {
       
 10788 				fs = tinymce.explode(s.font_size_style_values);
       
 10789 				fc = tinymce.explode(s.font_size_classes);
       
 10790 
       
 10791 				if (fc)
       
 10792 					v = fc[v - 1] || v;
       
 10793 				else
       
 10794 					v = fs[v - 1] || v;
       
 10795 			}
       
 10796 
       
 10797 			if (v >= 1 && v <= 7)
       
 10798 				ed.getDoc().execCommand('FontSize', false, v);
       
 10799 			else
       
 10800 				this._applyInlineStyle('span', {style : {fontSize : v}});
       
 10801 		},
       
 10802 
       
 10803 		queryCommandValue : function(c) {
       
 10804 			var f = this['queryValue' + c];
       
 10805 
       
 10806 			if (f)
       
 10807 				return f.call(this, c);
       
 10808 
       
 10809 			return false;
       
 10810 		},
       
 10811 
       
 10812 		queryCommandState : function(cmd) {
       
 10813 			var f;
       
 10814 
       
 10815 			switch (cmd) {
       
 10816 				// Bundle these together
       
 10817 				case 'JustifyLeft':
       
 10818 				case 'JustifyCenter':
       
 10819 				case 'JustifyRight':
       
 10820 				case 'JustifyFull':
       
 10821 					return this.queryStateJustify(cmd, cmd.substring(7).toLowerCase());
       
 10822 
       
 10823 				default:
       
 10824 					if (f = this['queryState' + cmd])
       
 10825 						return f.call(this, cmd);
       
 10826 			}
       
 10827 
       
 10828 			return -1;
       
 10829 		},
       
 10830 
       
 10831 		_queryState : function(c) {
       
 10832 			try {
       
 10833 				return this.editor.getDoc().queryCommandState(c);
       
 10834 			} catch (ex) {
       
 10835 				// Ignore exception
       
 10836 			}
       
 10837 		},
       
 10838 
       
 10839 		_queryVal : function(c) {
       
 10840 			try {
       
 10841 				return this.editor.getDoc().queryCommandValue(c);
       
 10842 			} catch (ex) {
       
 10843 				// Ignore exception
       
 10844 			}
       
 10845 		},
       
 10846 
       
 10847 		queryValueFontSize : function() {
       
 10848 			var ed = this.editor, v = 0, p;
       
 10849 
       
 10850 			if (p = ed.dom.getParent(ed.selection.getNode(), 'span'))
       
 10851 				v = p.style.fontSize;
       
 10852 
       
 10853 			if (!v && (isOpera || isWebKit)) {
       
 10854 				if (p = ed.dom.getParent(ed.selection.getNode(), 'font'))
       
 10855 					v = p.size;
       
 10856 
       
 10857 				return v;
       
 10858 			}
       
 10859 
       
 10860 			return v || this._queryVal('FontSize');
       
 10861 		},
       
 10862 
       
 10863 		queryValueFontName : function() {
       
 10864 			var ed = this.editor, v = 0, p;
       
 10865 
       
 10866 			if (p = ed.dom.getParent(ed.selection.getNode(), 'font'))
       
 10867 				v = p.face;
       
 10868 
       
 10869 			if (p = ed.dom.getParent(ed.selection.getNode(), 'span'))
       
 10870 				v = p.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
       
 10871 
       
 10872 			if (!v)
       
 10873 				v = this._queryVal('FontName');
       
 10874 
       
 10875 			return v;
       
 10876 		},
       
 10877 
       
 10878 		mceJustify : function(c, v) {
       
 10879 			var ed = this.editor, se = ed.selection, n = se.getNode(), nn = n.nodeName, bl, nb, dom = ed.dom, rm;
       
 10880 
       
 10881 			if (ed.settings.inline_styles && this.queryStateJustify(c, v))
       
 10882 				rm = 1;
       
 10883 
       
 10884 			bl = dom.getParent(n, ed.dom.isBlock);
       
 10885 
       
 10886 			if (nn == 'IMG') {
       
 10887 				if (v == 'full')
       
 10888 					return;
       
 10889 
       
 10890 				if (rm) {
       
 10891 					if (v == 'center')
       
 10892 						dom.setStyle(bl || n.parentNode, 'textAlign', '');
       
 10893 
       
 10894 					dom.setStyle(n, 'float', '');
       
 10895 					this.mceRepaint();
       
 10896 					return;
       
 10897 				}
       
 10898 
       
 10899 				if (v == 'center') {
       
 10900 					// Do not change table elements
       
 10901 					if (bl && /^(TD|TH)$/.test(bl.nodeName))
       
 10902 						bl = 0;
       
 10903 
       
 10904 					if (!bl || bl.childNodes.length > 1) {
       
 10905 						nb = dom.create('p');
       
 10906 						nb.appendChild(n.cloneNode(false));
       
 10907 
       
 10908 						if (bl)
       
 10909 							dom.insertAfter(nb, bl);
       
 10910 						else
       
 10911 							dom.insertAfter(nb, n);
       
 10912 
       
 10913 						dom.remove(n);
       
 10914 						n = nb.firstChild;
       
 10915 						bl = nb;
       
 10916 					}
       
 10917 
       
 10918 					dom.setStyle(bl, 'textAlign', v);
       
 10919 					dom.setStyle(n, 'float', '');
       
 10920 				} else {
       
 10921 					dom.setStyle(n, 'float', v);
       
 10922 					dom.setStyle(bl || n.parentNode, 'textAlign', '');
       
 10923 				}
       
 10924 
       
 10925 				this.mceRepaint();
       
 10926 				return;
       
 10927 			}
       
 10928 
       
 10929 			// Handle the alignment outselfs, less quirks in all browsers
       
 10930 			if (ed.settings.inline_styles && ed.settings.forced_root_block) {
       
 10931 				if (rm)
       
 10932 					v = '';
       
 10933 
       
 10934 				each(se.getSelectedBlocks(dom.getParent(se.getStart(), dom.isBlock), dom.getParent(se.getEnd(), dom.isBlock)), function(e) {
       
 10935 					dom.setAttrib(e, 'align', '');
       
 10936 					dom.setStyle(e, 'textAlign', v == 'full' ? 'justify' : v);
       
 10937 				});
       
 10938 
       
 10939 				return;
       
 10940 			} else if (!rm)
       
 10941 				ed.getDoc().execCommand(c, false, null);
       
 10942 
       
 10943 			if (ed.settings.inline_styles) {
       
 10944 				if (rm) {
       
 10945 					dom.getParent(ed.selection.getNode(), function(n) {
       
 10946 						if (n.style && n.style.textAlign)
       
 10947 							dom.setStyle(n, 'textAlign', '');
       
 10948 					});
       
 10949 
       
 10950 					return;
       
 10951 				}
       
 10952 
       
 10953 				each(dom.select('*'), function(n) {
       
 10954 					var v = n.align;
       
 10955 
       
 10956 					if (v) {
       
 10957 						if (v == 'full')
       
 10958 							v = 'justify';
       
 10959 
       
 10960 						dom.setStyle(n, 'textAlign', v);
       
 10961 						dom.setAttrib(n, 'align', '');
       
 10962 					}
       
 10963 				});
       
 10964 			}
       
 10965 		},
       
 10966 
       
 10967 		mceSetCSSClass : function(u, v) {
       
 10968 			this.mceSetStyleInfo(0, {command : 'setattrib', name : 'class', value : v});
       
 10969 		},
       
 10970 
       
 10971 		getSelectedElement : function() {
       
 10972 			var t = this, ed = t.editor, dom = ed.dom, se = ed.selection, r = se.getRng(), r1, r2, sc, ec, so, eo, e, sp, ep, re;
       
 10973 
       
 10974 			if (se.isCollapsed() || r.item)
       
 10975 				return se.getNode();
       
 10976 
       
 10977 			// Setup regexp
       
 10978 			re = ed.settings.merge_styles_invalid_parents;
       
 10979 			if (tinymce.is(re, 'string'))
       
 10980 				re = new RegExp(re, 'i');
       
 10981 
       
 10982 			if (isIE) {
       
 10983 				r1 = r.duplicate();
       
 10984 				r1.collapse(true);
       
 10985 				sc = r1.parentElement();
       
 10986 
       
 10987 				r2 = r.duplicate();
       
 10988 				r2.collapse(false);
       
 10989 				ec = r2.parentElement();
       
 10990 
       
 10991 				if (sc != ec) {
       
 10992 					r1.move('character', 1);
       
 10993 					sc = r1.parentElement();
       
 10994 				}
       
 10995 
       
 10996 				if (sc == ec) {
       
 10997 					r1 = r.duplicate();
       
 10998 					r1.moveToElementText(sc);
       
 10999 
       
 11000 					if (r1.compareEndPoints('StartToStart', r) == 0 && r1.compareEndPoints('EndToEnd', r) == 0)
       
 11001 						return re && re.test(sc.nodeName) ? null : sc;
       
 11002 				}
       
 11003 			} else {
       
 11004 				function getParent(n) {
       
 11005 					return dom.getParent(n, '*');
       
 11006 				};
       
 11007 
       
 11008 				sc = r.startContainer;
       
 11009 				ec = r.endContainer;
       
 11010 				so = r.startOffset;
       
 11011 				eo = r.endOffset;
       
 11012 
       
 11013 				if (!r.collapsed) {
       
 11014 					if (sc == ec) {
       
 11015 						if (so - eo < 2) {
       
 11016 							if (sc.hasChildNodes()) {
       
 11017 								sp = sc.childNodes[so];
       
 11018 								return re && re.test(sp.nodeName) ? null : sp;
       
 11019 							}
       
 11020 						}
       
 11021 					}
       
 11022 				}
       
 11023 
       
 11024 				if (sc.nodeType != 3 || ec.nodeType != 3)
       
 11025 					return null;
       
 11026 
       
 11027 				if (so == 0) {
       
 11028 					sp = getParent(sc);
       
 11029 
       
 11030 					if (sp && sp.firstChild != sc)
       
 11031 						sp = null;
       
 11032 				}
       
 11033 
       
 11034 				if (so == sc.nodeValue.length) {
       
 11035 					e = sc.nextSibling;
       
 11036 
       
 11037 					if (e && e.nodeType == 1)
       
 11038 						sp = sc.nextSibling;
       
 11039 				}
       
 11040 
       
 11041 				if (eo == 0) {
       
 11042 					e = ec.previousSibling;
       
 11043 
       
 11044 					if (e && e.nodeType == 1)
       
 11045 						ep = e;
       
 11046 				}
       
 11047 
       
 11048 				if (eo == ec.nodeValue.length) {
       
 11049 					ep = getParent(ec);
       
 11050 
       
 11051 					if (ep && ep.lastChild != ec)
       
 11052 						ep = null;
       
 11053 				}
       
 11054 
       
 11055 				// Same element
       
 11056 				if (sp == ep)
       
 11057 					return re && sp && re.test(sp.nodeName) ? null : sp;
       
 11058 			}
       
 11059 
       
 11060 			return null;
       
 11061 		},
       
 11062 
       
 11063 		mceSetStyleInfo : function(u, v) {
       
 11064 			var t = this, ed = t.editor, d = ed.getDoc(), dom = ed.dom, e, b, s = ed.selection, nn = v.wrapper || 'span', b = s.getBookmark(), re;
       
 11065 
       
 11066 			function set(n, e) {
       
 11067 				if (n.nodeType == 1) {
       
 11068 					switch (v.command) {
       
 11069 						case 'setattrib':
       
 11070 							return dom.setAttrib(n, v.name, v.value);
       
 11071 
       
 11072 						case 'setstyle':
       
 11073 							return dom.setStyle(n, v.name, v.value);
       
 11074 
       
 11075 						case 'removeformat':
       
 11076 							return dom.setAttrib(n, 'class', '');
       
 11077 					}
       
 11078 				}
       
 11079 			};
       
 11080 
       
 11081 			// Setup regexp
       
 11082 			re = ed.settings.merge_styles_invalid_parents;
       
 11083 			if (tinymce.is(re, 'string'))
       
 11084 				re = new RegExp(re, 'i');
       
 11085 
       
 11086 			// Set style info on selected element
       
 11087 			if ((e = t.getSelectedElement()) && !ed.settings.force_span_wrappers)
       
 11088 				set(e, 1);
       
 11089 			else {
       
 11090 				// Generate wrappers and set styles on them
       
 11091 				d.execCommand('FontName', false, '__');
       
 11092 				each(dom.select('span,font'), function(n) {
       
 11093 					var sp, e;
       
 11094 
       
 11095 					if (dom.getAttrib(n, 'face') == '__' || n.style.fontFamily === '__') {
       
 11096 						sp = dom.create(nn, {mce_new : '1'});
       
 11097 
       
 11098 						set(sp);
       
 11099 
       
 11100 						each (n.childNodes, function(n) {
       
 11101 							sp.appendChild(n.cloneNode(true));
       
 11102 						});
       
 11103 
       
 11104 						dom.replace(sp, n);
       
 11105 					}
       
 11106 				});
       
 11107 			}
       
 11108 
       
 11109 			// Remove wrappers inside new ones
       
 11110 			each(dom.select(nn).reverse(), function(n) {
       
 11111 				var p = n.parentNode;
       
 11112 
       
 11113 				// Check if it's an old span in a new wrapper
       
 11114 				if (!dom.getAttrib(n, 'mce_new')) {
       
 11115 					// Find new wrapper
       
 11116 					p = dom.getParent(n, '*[mce_new]');
       
 11117 
       
 11118 					if (p)
       
 11119 						dom.remove(n, 1);
       
 11120 				}
       
 11121 			});
       
 11122 
       
 11123 			// Merge wrappers with parent wrappers
       
 11124 			each(dom.select(nn).reverse(), function(n) {
       
 11125 				var p = n.parentNode;
       
 11126 
       
 11127 				if (!p || !dom.getAttrib(n, 'mce_new'))
       
 11128 					return;
       
 11129 
       
 11130 				if (ed.settings.force_span_wrappers && p.nodeName != 'SPAN')
       
 11131 					return;
       
 11132 
       
 11133 				// Has parent of the same type and only child
       
 11134 				if (p.nodeName == nn.toUpperCase() && p.childNodes.length == 1)
       
 11135 					return dom.remove(p, 1);
       
 11136 
       
 11137 				// Has parent that is more suitable to have the class and only child
       
 11138 				if (n.nodeType == 1 && (!re || !re.test(p.nodeName)) && p.childNodes.length == 1) {
       
 11139 					set(p); // Set style info on parent instead
       
 11140 					dom.setAttrib(n, 'class', '');
       
 11141 				}
       
 11142 			});
       
 11143 
       
 11144 			// Remove empty wrappers
       
 11145 			each(dom.select(nn).reverse(), function(n) {
       
 11146 				if (dom.getAttrib(n, 'mce_new') || (dom.getAttribs(n).length <= 1 && n.className === '')) {
       
 11147 					if (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style'))
       
 11148 						return dom.remove(n, 1);
       
 11149 
       
 11150 					dom.setAttrib(n, 'mce_new', ''); // Remove mce_new marker
       
 11151 				}
       
 11152 			});
       
 11153 
       
 11154 			s.moveToBookmark(b);
       
 11155 		},
       
 11156 
       
 11157 		queryStateJustify : function(c, v) {
       
 11158 			var ed = this.editor, n = ed.selection.getNode(), dom = ed.dom;
       
 11159 
       
 11160 			if (n && n.nodeName == 'IMG') {
       
 11161 				if (dom.getStyle(n, 'float') == v)
       
 11162 					return 1;
       
 11163 
       
 11164 				return n.parentNode.style.textAlign == v;
       
 11165 			}
       
 11166 
       
 11167 			n = dom.getParent(ed.selection.getStart(), function(n) {
       
 11168 				return n.nodeType == 1 && n.style.textAlign;
       
 11169 			});
       
 11170 
       
 11171 			if (v == 'full')
       
 11172 				v = 'justify';
       
 11173 
       
 11174 			if (ed.settings.inline_styles)
       
 11175 				return (n && n.style.textAlign == v);
       
 11176 
       
 11177 			return this._queryState(c);
       
 11178 		},
       
 11179 
       
 11180 		ForeColor : function(ui, v) {
       
 11181 			var ed = this.editor;
       
 11182 
       
 11183 			if (ed.settings.convert_fonts_to_spans) {
       
 11184 				this._applyInlineStyle('span', {style : {color : v}});
       
 11185 				return;
       
 11186 			} else
       
 11187 				ed.getDoc().execCommand('ForeColor', false, v);
       
 11188 		},
       
 11189 
       
 11190 		HiliteColor : function(ui, val) {
       
 11191 			var t = this, ed = t.editor, d = ed.getDoc();
       
 11192 
       
 11193 			if (ed.settings.convert_fonts_to_spans) {
       
 11194 				this._applyInlineStyle('span', {style : {backgroundColor : val}});
       
 11195 				return;
       
 11196 			}
       
 11197 
       
 11198 			function set(s) {
       
 11199 				if (!isGecko)
       
 11200 					return;
       
 11201 
       
 11202 				try {
       
 11203 					// Try new Gecko method
       
 11204 					d.execCommand("styleWithCSS", 0, s);
       
 11205 				} catch (ex) {
       
 11206 					// Use old
       
 11207 					d.execCommand("useCSS", 0, !s);
       
 11208 				}
       
 11209 			};
       
 11210 
       
 11211 			if (isGecko || isOpera) {
       
 11212 				set(true);
       
 11213 				d.execCommand('hilitecolor', false, val);
       
 11214 				set(false);
       
 11215 			} else
       
 11216 				d.execCommand('BackColor', false, val);
       
 11217 		},
       
 11218 
       
 11219 		FormatBlock : function(ui, val) {
       
 11220 			var t = this, ed = t.editor, s = ed.selection, dom = ed.dom, bl, nb, b;
       
 11221 
       
 11222 			function isBlock(n) {
       
 11223 				return /^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(n.nodeName);
       
 11224 			};
       
 11225 
       
 11226 			bl = dom.getParent(s.getNode(), function(n) {
       
 11227 				return isBlock(n);
       
 11228 			});
       
 11229 
       
 11230 			// IE has an issue where it removes the parent div if you change format on the paragrah in <div><p>Content</p></div>
       
 11231 			// FF and Opera doesn't change parent DIV elements if you switch format
       
 11232 			if (bl) {
       
 11233 				if ((isIE && isBlock(bl.parentNode)) || bl.nodeName == 'DIV') {
       
 11234 					// Rename block element
       
 11235 					nb = ed.dom.create(val);
       
 11236 
       
 11237 					each(dom.getAttribs(bl), function(v) {
       
 11238 						dom.setAttrib(nb, v.nodeName, dom.getAttrib(bl, v.nodeName));
       
 11239 					});
       
 11240 
       
 11241 					b = s.getBookmark();
       
 11242 					dom.replace(nb, bl, 1);
       
 11243 					s.moveToBookmark(b);
       
 11244 					ed.nodeChanged();
       
 11245 					return;
       
 11246 				}
       
 11247 			}
       
 11248 
       
 11249 			val = ed.settings.forced_root_block ? (val || '<p>') : val;
       
 11250 
       
 11251 			if (val.indexOf('<') == -1)
       
 11252 				val = '<' + val + '>';
       
 11253 
       
 11254 			if (tinymce.isGecko)
       
 11255 				val = val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi, '$1');
       
 11256 
       
 11257 			ed.getDoc().execCommand('FormatBlock', false, val);
       
 11258 		},
       
 11259 
       
 11260 		mceCleanup : function() {
       
 11261 			var ed = this.editor, s = ed.selection, b = s.getBookmark();
       
 11262 			ed.setContent(ed.getContent());
       
 11263 			s.moveToBookmark(b);
       
 11264 		},
       
 11265 
       
 11266 		mceRemoveNode : function(ui, val) {
       
 11267 			var ed = this.editor, s = ed.selection, b, n = val || s.getNode();
       
 11268 
       
 11269 			// Make sure that the body node isn't removed
       
 11270 			if (n == ed.getBody())
       
 11271 				return;
       
 11272 
       
 11273 			b = s.getBookmark();
       
 11274 			ed.dom.remove(n, 1);
       
 11275 			s.moveToBookmark(b);
       
 11276 			ed.nodeChanged();
       
 11277 		},
       
 11278 
       
 11279 		mceSelectNodeDepth : function(ui, val) {
       
 11280 			var ed = this.editor, s = ed.selection, c = 0;
       
 11281 
       
 11282 			ed.dom.getParent(s.getNode(), function(n) {
       
 11283 				if (n.nodeType == 1 && c++ == val) {
       
 11284 					s.select(n);
       
 11285 					ed.nodeChanged();
       
 11286 					return false;
       
 11287 				}
       
 11288 			}, ed.getBody());
       
 11289 		},
       
 11290 
       
 11291 		mceSelectNode : function(u, v) {
       
 11292 			this.editor.selection.select(v);
       
 11293 		},
       
 11294 
       
 11295 		mceInsertContent : function(ui, val) {
       
 11296 			this.editor.selection.setContent(val);
       
 11297 		},
       
 11298 
       
 11299 		mceInsertRawHTML : function(ui, val) {
       
 11300 			var ed = this.editor;
       
 11301 
       
 11302 			ed.selection.setContent('tiny_mce_marker');
       
 11303 			ed.setContent(ed.getContent().replace(/tiny_mce_marker/g, val));
       
 11304 		},
       
 11305 
       
 11306 		mceRepaint : function() {
       
 11307 			var s, b, e = this.editor;
       
 11308 
       
 11309 			if (tinymce.isGecko) {
       
 11310 				try {
       
 11311 					s = e.selection;
       
 11312 					b = s.getBookmark(true);
       
 11313 
       
 11314 					if (s.getSel())
       
 11315 						s.getSel().selectAllChildren(e.getBody());
       
 11316 
       
 11317 					s.collapse(true);
       
 11318 					s.moveToBookmark(b);
       
 11319 				} catch (ex) {
       
 11320 					// Ignore
       
 11321 				}
       
 11322 			}
       
 11323 		},
       
 11324 
       
 11325 		queryStateUnderline : function() {
       
 11326 			var ed = this.editor, n = ed.selection.getNode();
       
 11327 
       
 11328 			if (n && n.nodeName == 'A')
       
 11329 				return false;
       
 11330 
       
 11331 			return this._queryState('Underline');
       
 11332 		},
       
 11333 
       
 11334 		queryStateOutdent : function() {
       
 11335 			var ed = this.editor, n;
       
 11336 
       
 11337 			if (ed.settings.inline_styles) {
       
 11338 				if ((n = ed.dom.getParent(ed.selection.getStart(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)
       
 11339 					return true;
       
 11340 
       
 11341 				if ((n = ed.dom.getParent(ed.selection.getEnd(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)
       
 11342 					return true;
       
 11343 			}
       
 11344 
       
 11345 			return this.queryStateInsertUnorderedList() || this.queryStateInsertOrderedList() || (!ed.settings.inline_styles && !!ed.dom.getParent(ed.selection.getNode(), 'BLOCKQUOTE'));
       
 11346 		},
       
 11347 
       
 11348 		queryStateInsertUnorderedList : function() {
       
 11349 			return this.editor.dom.getParent(this.editor.selection.getNode(), 'UL');
       
 11350 		},
       
 11351 
       
 11352 		queryStateInsertOrderedList : function() {
       
 11353 			return this.editor.dom.getParent(this.editor.selection.getNode(), 'OL');
       
 11354 		},
       
 11355 
       
 11356 		queryStatemceBlockQuote : function() {
       
 11357 			return !!this.editor.dom.getParent(this.editor.selection.getStart(), function(n) {return n.nodeName === 'BLOCKQUOTE';});
       
 11358 		},
       
 11359 
       
 11360 		_applyInlineStyle : function(na, at, op) {
       
 11361 			var t = this, ed = t.editor, dom = ed.dom, bm, lo = {}, kh, found;
       
 11362 
       
 11363 			na = na.toUpperCase();
       
 11364 
       
 11365 			if (op && op.check_classes && at['class'])
       
 11366 				op.check_classes.push(at['class']);
       
 11367 
       
 11368 			function removeEmpty() {
       
 11369 				each(dom.select(na).reverse(), function(n) {
       
 11370 					var c = 0;
       
 11371 
       
 11372 					// Check if there is any attributes
       
 11373 					each(dom.getAttribs(n), function(an) {
       
 11374 						if (an.nodeName.substring(0, 1) != '_' && dom.getAttrib(n, an.nodeName) != '') {
       
 11375 							//console.log(dom.getOuterHTML(n), dom.getAttrib(n, an.nodeName));
       
 11376 							c++;
       
 11377 						}
       
 11378 					});
       
 11379 
       
 11380 					// No attributes then remove the element and keep the children
       
 11381 					if (c == 0)
       
 11382 						dom.remove(n, 1);
       
 11383 				});
       
 11384 			};
       
 11385 
       
 11386 			function replaceFonts() {
       
 11387 				var bm;
       
 11388 
       
 11389 				each(dom.select('span,font'), function(n) {
       
 11390 					if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline') {
       
 11391 						if (!bm)
       
 11392 							bm = ed.selection.getBookmark();
       
 11393 
       
 11394 						at._mce_new = '1';
       
 11395 						dom.replace(dom.create(na, at), n, 1);
       
 11396 					}
       
 11397 				});
       
 11398 
       
 11399 				// Remove redundant elements
       
 11400 				each(dom.select(na + '[_mce_new]'), function(n) {
       
 11401 					function removeStyle(n) {
       
 11402 						if (n.nodeType == 1) {
       
 11403 							each(at.style, function(v, k) {
       
 11404 								dom.setStyle(n, k, '');
       
 11405 							});
       
 11406 
       
 11407 							// Remove spans with the same class or marked classes
       
 11408 							if (at['class'] && n.className && op) {
       
 11409 								each(op.check_classes, function(c) {
       
 11410 									if (dom.hasClass(n, c))
       
 11411 										dom.removeClass(n, c);
       
 11412 								});
       
 11413 							}
       
 11414 						}
       
 11415 					};
       
 11416 
       
 11417 					// Remove specified style information from child elements
       
 11418 					each(dom.select(na, n), removeStyle);
       
 11419 
       
 11420 					// Remove the specified style information on parent if current node is only child (IE)
       
 11421 					if (n.parentNode && n.parentNode.nodeType == 1 && n.parentNode.childNodes.length == 1)
       
 11422 						removeStyle(n.parentNode);
       
 11423 
       
 11424 					// Remove the child elements style info if a parent already has it
       
 11425 					dom.getParent(n.parentNode, function(pn) {
       
 11426 						if (pn.nodeType == 1) {
       
 11427 							if (at.style) {
       
 11428 								each(at.style, function(v, k) {
       
 11429 									var sv;
       
 11430 
       
 11431 									if (!lo[k] && (sv = dom.getStyle(pn, k))) {
       
 11432 										if (sv === v)
       
 11433 											dom.setStyle(n, k, '');
       
 11434 
       
 11435 										lo[k] = 1;
       
 11436 									}
       
 11437 								});
       
 11438 							}
       
 11439 
       
 11440 							// Remove spans with the same class or marked classes
       
 11441 							if (at['class'] && pn.className && op) {
       
 11442 								each(op.check_classes, function(c) {
       
 11443 									if (dom.hasClass(pn, c))
       
 11444 										dom.removeClass(n, c);
       
 11445 								});
       
 11446 							}
       
 11447 						}
       
 11448 
       
 11449 						return false;
       
 11450 					});
       
 11451 
       
 11452 					n.removeAttribute('_mce_new');
       
 11453 				});
       
 11454 
       
 11455 				removeEmpty();
       
 11456 				ed.selection.moveToBookmark(bm);
       
 11457 
       
 11458 				return !!bm;
       
 11459 			};
       
 11460 
       
 11461 			// Create inline elements
       
 11462 			ed.focus();
       
 11463 			ed.getDoc().execCommand('FontName', false, 'mceinline');
       
 11464 			replaceFonts();
       
 11465 
       
 11466 			if (kh = t._applyInlineStyle.keyhandler) {
       
 11467 				ed.onKeyUp.remove(kh);
       
 11468 				ed.onKeyPress.remove(kh);
       
 11469 				ed.onKeyDown.remove(kh);
       
 11470 				ed.onSetContent.remove(t._applyInlineStyle.chandler);
       
 11471 			}
       
 11472 
       
 11473 			if (ed.selection.isCollapsed()) {
       
 11474 				// IE will format the current word so this code can't be executed on that browser
       
 11475 				if (!isIE) {
       
 11476 					each(dom.getParents(ed.selection.getNode(), 'span'), function(n) {
       
 11477 						each(at.style, function(v, k) {
       
 11478 							var kv;
       
 11479 
       
 11480 							if (kv = dom.getStyle(n, k)) {
       
 11481 								if (kv == v) {
       
 11482 									dom.setStyle(n, k, '');
       
 11483 									found = 2;
       
 11484 									return false;
       
 11485 								}
       
 11486 
       
 11487 								found = 1;
       
 11488 								return false;
       
 11489 							}
       
 11490 						});
       
 11491 
       
 11492 						if (found)
       
 11493 							return false;
       
 11494 					});
       
 11495 
       
 11496 					if (found == 2) {
       
 11497 						bm = ed.selection.getBookmark();
       
 11498 
       
 11499 						removeEmpty();
       
 11500 
       
 11501 						ed.selection.moveToBookmark(bm);
       
 11502 
       
 11503 						// Node change needs to be detached since the onselect event
       
 11504 						// for the select box will run the onclick handler after onselect call. Todo: Add a nicer fix!
       
 11505 						window.setTimeout(function() {
       
 11506 							ed.nodeChanged();
       
 11507 						}, 1);
       
 11508 
       
 11509 						return;
       
 11510 					}
       
 11511 				}
       
 11512 
       
 11513 				// Start collecting styles
       
 11514 				t._pendingStyles = tinymce.extend(t._pendingStyles || {}, at.style);
       
 11515 
       
 11516 				t._applyInlineStyle.chandler = ed.onSetContent.add(function() {
       
 11517 					delete t._pendingStyles;
       
 11518 				});
       
 11519 
       
 11520 				t._applyInlineStyle.keyhandler = kh = function(e) {
       
 11521 					// Use pending styles
       
 11522 					if (t._pendingStyles) {
       
 11523 						at.style = t._pendingStyles;
       
 11524 						delete t._pendingStyles;
       
 11525 					}
       
 11526 
       
 11527 					if (replaceFonts()) {
       
 11528 						ed.onKeyDown.remove(t._applyInlineStyle.keyhandler);
       
 11529 						ed.onKeyPress.remove(t._applyInlineStyle.keyhandler);
       
 11530 					}
       
 11531 
       
 11532 					if (e.type == 'keyup')
       
 11533 						ed.onKeyUp.remove(t._applyInlineStyle.keyhandler);
       
 11534 				};
       
 11535 
       
 11536 				ed.onKeyDown.add(kh);
       
 11537 				ed.onKeyPress.add(kh);
       
 11538 				ed.onKeyUp.add(kh);
       
 11539 			} else
       
 11540 				t._pendingStyles = 0;
       
 11541 		}
       
 11542 	});
       
 11543 })(tinymce);(function(tinymce) {
       
 11544 	tinymce.create('tinymce.UndoManager', {
       
 11545 		index : 0,
       
 11546 		data : null,
       
 11547 		typing : 0,
       
 11548 
       
 11549 		UndoManager : function(ed) {
       
 11550 			var t = this, Dispatcher = tinymce.util.Dispatcher;
       
 11551 
       
 11552 			t.editor = ed;
       
 11553 			t.data = [];
       
 11554 			t.onAdd = new Dispatcher(this);
       
 11555 			t.onUndo = new Dispatcher(this);
       
 11556 			t.onRedo = new Dispatcher(this);
       
 11557 		},
       
 11558 
       
 11559 		add : function(l) {
       
 11560 			var t = this, i, ed = t.editor, b, s = ed.settings, la;
       
 11561 
       
 11562 			l = l || {};
       
 11563 			l.content = l.content || ed.getContent({format : 'raw', no_events : 1});
       
 11564 
       
 11565 			// Add undo level if needed
       
 11566 			l.content = l.content.replace(/^\s*|\s*$/g, '');
       
 11567 			la = t.data[t.index > 0 && (t.index == 0 || t.index == t.data.length) ? t.index - 1 : t.index];
       
 11568 			if (!l.initial && la && l.content == la.content)
       
 11569 				return null;
       
 11570 
       
 11571 			// Time to compress
       
 11572 			if (s.custom_undo_redo_levels) {
       
 11573 				if (t.data.length > s.custom_undo_redo_levels) {
       
 11574 					for (i = 0; i < t.data.length - 1; i++)
       
 11575 						t.data[i] = t.data[i + 1];
       
 11576 
       
 11577 					t.data.length--;
       
 11578 					t.index = t.data.length;
       
 11579 				}
       
 11580 			}
       
 11581 
       
 11582 			if (s.custom_undo_redo_restore_selection && !l.initial)
       
 11583 				l.bookmark = b = l.bookmark || ed.selection.getBookmark();
       
 11584 
       
 11585 			if (t.index < t.data.length)
       
 11586 				t.index++;
       
 11587 
       
 11588 			// Only initial marked undo levels should be allowed as first item
       
 11589 			// This to workaround a bug with Firefox and the blur event
       
 11590 			if (t.data.length === 0 && !l.initial)
       
 11591 				return null;
       
 11592 
       
 11593 			// Add level
       
 11594 			t.data.length = t.index + 1;
       
 11595 			t.data[t.index++] = l;
       
 11596 
       
 11597 			if (l.initial)
       
 11598 				t.index = 0;
       
 11599 
       
 11600 			// Set initial bookmark use first real undo level
       
 11601 			if (t.data.length == 2 && t.data[0].initial)
       
 11602 				t.data[0].bookmark = b;
       
 11603 
       
 11604 			t.onAdd.dispatch(t, l);
       
 11605 			ed.isNotDirty = 0;
       
 11606 
       
 11607 			//console.dir(t.data);
       
 11608 
       
 11609 			return l;
       
 11610 		},
       
 11611 
       
 11612 		undo : function() {
       
 11613 			var t = this, ed = t.editor, l = l, i;
       
 11614 
       
 11615 			if (t.typing) {
       
 11616 				t.add();
       
 11617 				t.typing = 0;
       
 11618 			}
       
 11619 
       
 11620 			if (t.index > 0) {
       
 11621 				// If undo on last index then take snapshot
       
 11622 				if (t.index == t.data.length && t.index > 1) {
       
 11623 					i = t.index;
       
 11624 					t.typing = 0;
       
 11625 
       
 11626 					if (!t.add())
       
 11627 						t.index = i;
       
 11628 
       
 11629 					--t.index;
       
 11630 				}
       
 11631 
       
 11632 				l = t.data[--t.index];
       
 11633 				ed.setContent(l.content, {format : 'raw'});
       
 11634 				ed.selection.moveToBookmark(l.bookmark);
       
 11635 
       
 11636 				t.onUndo.dispatch(t, l);
       
 11637 			}
       
 11638 
       
 11639 			return l;
       
 11640 		},
       
 11641 
       
 11642 		redo : function() {
       
 11643 			var t = this, ed = t.editor, l = null;
       
 11644 
       
 11645 			if (t.index < t.data.length - 1) {
       
 11646 				l = t.data[++t.index];
       
 11647 				ed.setContent(l.content, {format : 'raw'});
       
 11648 				ed.selection.moveToBookmark(l.bookmark);
       
 11649 
       
 11650 				t.onRedo.dispatch(t, l);
       
 11651 			}
       
 11652 
       
 11653 			return l;
       
 11654 		},
       
 11655 
       
 11656 		clear : function() {
       
 11657 			var t = this;
       
 11658 
       
 11659 			t.data = [];
       
 11660 			t.index = 0;
       
 11661 			t.typing = 0;
       
 11662 			t.add({initial : true});
       
 11663 		},
       
 11664 
       
 11665 		hasUndo : function() {
       
 11666 			return this.index != 0 || this.typing;
       
 11667 		},
       
 11668 
       
 11669 		hasRedo : function() {
       
 11670 			return this.index < this.data.length - 1;
       
 11671 		}
       
 11672 	});
       
 11673 })(tinymce);
       
 11674 (function(tinymce) {
       
 11675 	// Shorten names
       
 11676 	var Event, isIE, isGecko, isOpera, each, extend;
       
 11677 
       
 11678 	Event = tinymce.dom.Event;
       
 11679 	isIE = tinymce.isIE;
       
 11680 	isGecko = tinymce.isGecko;
       
 11681 	isOpera = tinymce.isOpera;
       
 11682 	each = tinymce.each;
       
 11683 	extend = tinymce.extend;
       
 11684 
       
 11685 	// Checks if the selection/caret is at the end of the specified block element
       
 11686 	function isAtEnd(rng, par) {
       
 11687 		var rng2 = par.ownerDocument.createRange();
       
 11688 
       
 11689 		rng2.setStart(rng.endContainer, rng.endOffset);
       
 11690 		rng2.setEndAfter(par);
       
 11691 
       
 11692 		// Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element
       
 11693 		return rng2.cloneContents().textContent.length == 0;
       
 11694 	};
       
 11695 
       
 11696 	function isEmpty(n) {
       
 11697 		n = n.innerHTML;
       
 11698 
       
 11699 		n = n.replace(/<(img|hr|table|input|select|textarea)[ \>]/gi, '-'); // Keep these convert them to - chars
       
 11700 		n = n.replace(/<[^>]+>/g, ''); // Remove all tags
       
 11701 
       
 11702 		return n.replace(/[ \t\r\n]+/g, '') == '';
       
 11703 	};
       
 11704 
       
 11705 	tinymce.create('tinymce.ForceBlocks', {
       
 11706 		ForceBlocks : function(ed) {
       
 11707 			var t = this, s = ed.settings, elm;
       
 11708 
       
 11709 			t.editor = ed;
       
 11710 			t.dom = ed.dom;
       
 11711 			elm = (s.forced_root_block || 'p').toLowerCase();
       
 11712 			s.element = elm.toUpperCase();
       
 11713 
       
 11714 			ed.onPreInit.add(t.setup, t);
       
 11715 
       
 11716 			t.reOpera = new RegExp('(\\u00a0|&#160;|&nbsp;)<\/' + elm + '>', 'gi');
       
 11717 			t.rePadd = new RegExp('<p( )([^>]+)><\\\/p>|<p( )([^>]+)\\\/>|<p( )([^>]+)>\\s+<\\\/p>|<p><\\\/p>|<p\\\/>|<p>\\s+<\\\/p>'.replace(/p/g, elm), 'gi');
       
 11718 			t.reNbsp2BR1 = new RegExp('<p( )([^>]+)>[\\s\\u00a0]+<\\\/p>|<p>[\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi');
       
 11719 			t.reNbsp2BR2 = new RegExp('<%p()([^>]+)>(&nbsp;|&#160;)<\\\/%p>|<%p>(&nbsp;|&#160;)<\\\/%p>'.replace(/%p/g, elm), 'gi');
       
 11720 			t.reBR2Nbsp = new RegExp('<p( )([^>]+)>\\s*<br \\\/>\\s*<\\\/p>|<p>\\s*<br \\\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');
       
 11721 
       
 11722 			function padd(ed, o) {
       
 11723 				if (isOpera)
       
 11724 					o.content = o.content.replace(t.reOpera, '</' + elm + '>');
       
 11725 
       
 11726 				o.content = o.content.replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0</' + elm + '>');
       
 11727 
       
 11728 				if (!isIE && !isOpera && o.set) {
       
 11729 					// Use &nbsp; instead of BR in padded paragraphs
       
 11730 					o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2><br /></' + elm + '>');
       
 11731 					o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2><br /></' + elm + '>');
       
 11732 				} else
       
 11733 					o.content = o.content.replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0</' + elm + '>');
       
 11734 			};
       
 11735 
       
 11736 			ed.onBeforeSetContent.add(padd);
       
 11737 			ed.onPostProcess.add(padd);
       
 11738 
       
 11739 			if (s.forced_root_block) {
       
 11740 				ed.onInit.add(t.forceRoots, t);
       
 11741 				ed.onSetContent.add(t.forceRoots, t);
       
 11742 				ed.onBeforeGetContent.add(t.forceRoots, t);
       
 11743 			}
       
 11744 		},
       
 11745 
       
 11746 		setup : function() {
       
 11747 			var t = this, ed = t.editor, s = ed.settings;
       
 11748 
       
 11749 			// Force root blocks when typing and when getting output
       
 11750 			if (s.forced_root_block) {
       
 11751 				ed.onKeyUp.add(t.forceRoots, t);
       
 11752 				ed.onPreProcess.add(t.forceRoots, t);
       
 11753 			}
       
 11754 
       
 11755 			if (s.force_br_newlines) {
       
 11756 				// Force IE to produce BRs on enter
       
 11757 				if (isIE) {
       
 11758 					ed.onKeyPress.add(function(ed, e) {
       
 11759 						var n, s = ed.selection;
       
 11760 
       
 11761 						if (e.keyCode == 13 && s.getNode().nodeName != 'LI') {
       
 11762 							s.setContent('<br id="__" /> ', {format : 'raw'});
       
 11763 							n = ed.dom.get('__');
       
 11764 							n.removeAttribute('id');
       
 11765 							s.select(n);
       
 11766 							s.collapse();
       
 11767 							return Event.cancel(e);
       
 11768 						}
       
 11769 					});
       
 11770 				}
       
 11771 
       
 11772 				return;
       
 11773 			}
       
 11774 
       
 11775 			if (!isIE && s.force_p_newlines) {
       
 11776 /*				ed.onPreProcess.add(function(ed, o) {
       
 11777 					each(ed.dom.select('br', o.node), function(n) {
       
 11778 						var p = n.parentNode;
       
 11779 
       
 11780 						// Replace <p><br /></p> with <p>&nbsp;</p>
       
 11781 						if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) {
       
 11782 							p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n);
       
 11783 						}
       
 11784 					});
       
 11785 				});*/
       
 11786 
       
 11787 				ed.onKeyPress.add(function(ed, e) {
       
 11788 					if (e.keyCode == 13 && !e.shiftKey) {
       
 11789 						if (!t.insertPara(e))
       
 11790 							Event.cancel(e);
       
 11791 					}
       
 11792 				});
       
 11793 
       
 11794 				if (isGecko) {
       
 11795 					ed.onKeyDown.add(function(ed, e) {
       
 11796 						if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
       
 11797 							t.backspaceDelete(e, e.keyCode == 8);
       
 11798 					});
       
 11799 				}
       
 11800 			}
       
 11801 
       
 11802 			function ren(rn, na) {
       
 11803 				var ne = ed.dom.create(na);
       
 11804 
       
 11805 				each(rn.attributes, function(a) {
       
 11806 					if (a.specified && a.nodeValue)
       
 11807 						ne.setAttribute(a.nodeName.toLowerCase(), a.nodeValue);
       
 11808 				});
       
 11809 
       
 11810 				each(rn.childNodes, function(n) {
       
 11811 					ne.appendChild(n.cloneNode(true));
       
 11812 				});
       
 11813 
       
 11814 				rn.parentNode.replaceChild(ne, rn);
       
 11815 
       
 11816 				return ne;
       
 11817 			};
       
 11818 
       
 11819 			// Padd empty inline elements within block elements
       
 11820 			// For example: <p><strong><em></em></strong></p> becomes <p><strong><em>&nbsp;</em></strong></p>
       
 11821 			ed.onPreProcess.add(function(ed, o) {
       
 11822 				each(ed.dom.select('p,h1,h2,h3,h4,h5,h6,div', o.node), function(p) {
       
 11823 					if (isEmpty(p)) {
       
 11824 						each(ed.dom.select('span,em,strong,b,i', o.node), function(n) {
       
 11825 							if (!n.hasChildNodes()) {
       
 11826 								n.appendChild(ed.getDoc().createTextNode('\u00a0'));
       
 11827 								return false; // Break the loop one padding is enough
       
 11828 							}
       
 11829 						});
       
 11830 					}
       
 11831 				});
       
 11832 			});
       
 11833 
       
 11834 			// IE specific fixes
       
 11835 			if (isIE) {
       
 11836 				// Replaces IE:s auto generated paragraphs with the specified element name
       
 11837 				if (s.element != 'P') {
       
 11838 					ed.onKeyPress.add(function(ed, e) {
       
 11839 						t.lastElm = ed.selection.getNode().nodeName;
       
 11840 					});
       
 11841 
       
 11842 					ed.onKeyUp.add(function(ed, e) {
       
 11843 						var bl, sel = ed.selection, n = sel.getNode(), b = ed.getBody();
       
 11844 
       
 11845 						if (b.childNodes.length === 1 && n.nodeName == 'P') {
       
 11846 							n = ren(n, s.element);
       
 11847 							sel.select(n);
       
 11848 							sel.collapse();
       
 11849 							ed.nodeChanged();
       
 11850 						} else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') {
       
 11851 							bl = ed.dom.getParent(n, 'p');
       
 11852 
       
 11853 							if (bl) {
       
 11854 								ren(bl, s.element);
       
 11855 								ed.nodeChanged();
       
 11856 							}
       
 11857 						}
       
 11858 					});
       
 11859 				}
       
 11860 			}
       
 11861 		},
       
 11862 
       
 11863 		find : function(n, t, s) {
       
 11864 			var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, false), c = -1;
       
 11865 
       
 11866 			while (n = w.nextNode()) {
       
 11867 				c++;
       
 11868 
       
 11869 				// Index by node
       
 11870 				if (t == 0 && n == s)
       
 11871 					return c;
       
 11872 
       
 11873 				// Node by index
       
 11874 				if (t == 1 && c == s)
       
 11875 					return n;
       
 11876 			}
       
 11877 
       
 11878 			return -1;
       
 11879 		},
       
 11880 
       
 11881 		forceRoots : function(ed, e) {
       
 11882 			var t = this, ed = t.editor, b = ed.getBody(), d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng(), si = -2, ei, so, eo, tr, c = -0xFFFFFF;
       
 11883 			var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid;
       
 11884 
       
 11885 			// Fix for bug #1863847
       
 11886 			//if (e && e.keyCode == 13)
       
 11887 			//	return true;
       
 11888 
       
 11889 			// Wrap non blocks into blocks
       
 11890 			for (i = nl.length - 1; i >= 0; i--) {
       
 11891 				nx = nl[i];
       
 11892 
       
 11893 				// Is text or non block element
       
 11894 				if (nx.nodeType === 3 || (!t.dom.isBlock(nx) && nx.nodeType !== 8 && !/^(script|mce:script|style|mce:style)$/i.test(nx.nodeName))) {
       
 11895 					if (!bl) {
       
 11896 						// Create new block but ignore whitespace
       
 11897 						if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {
       
 11898 							// Store selection
       
 11899 							if (si == -2 && r) {
       
 11900 								if (!isIE) {
       
 11901 									// If selection is element then mark it
       
 11902 									if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) {
       
 11903 										// Save the id of the selected element
       
 11904 										eid = n.getAttribute("id");
       
 11905 										n.setAttribute("id", "__mce");
       
 11906 									} else {
       
 11907 										// If element is inside body, might not be the case in contentEdiable mode
       
 11908 										if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) {
       
 11909 											so = r.startOffset;
       
 11910 											eo = r.endOffset;
       
 11911 											si = t.find(b, 0, r.startContainer);
       
 11912 											ei = t.find(b, 0, r.endContainer);
       
 11913 										}
       
 11914 									}
       
 11915 								} else {
       
 11916 									tr = d.body.createTextRange();
       
 11917 									tr.moveToElementText(b);
       
 11918 									tr.collapse(1);
       
 11919 									bp = tr.move('character', c) * -1;
       
 11920 
       
 11921 									tr = r.duplicate();
       
 11922 									tr.collapse(1);
       
 11923 									sp = tr.move('character', c) * -1;
       
 11924 
       
 11925 									tr = r.duplicate();
       
 11926 									tr.collapse(0);
       
 11927 									le = (tr.move('character', c) * -1) - sp;
       
 11928 
       
 11929 									si = sp - bp;
       
 11930 									ei = le;
       
 11931 								}
       
 11932 							}
       
 11933 
       
 11934 							// Uses replaceChild instead of cloneNode since it removes selected attribute from option elements on IE
       
 11935 							// See: http://support.microsoft.com/kb/829907
       
 11936 							bl = ed.dom.create(ed.settings.forced_root_block);
       
 11937 							nx.parentNode.replaceChild(bl, nx);
       
 11938 							bl.appendChild(nx);
       
 11939 						}
       
 11940 					} else {
       
 11941 						if (bl.hasChildNodes())
       
 11942 							bl.insertBefore(nx, bl.firstChild);
       
 11943 						else
       
 11944 							bl.appendChild(nx);
       
 11945 					}
       
 11946 				} else
       
 11947 					bl = null; // Time to create new block
       
 11948 			}
       
 11949 
       
 11950 			// Restore selection
       
 11951 			if (si != -2) {
       
 11952 				if (!isIE) {
       
 11953 					bl = b.getElementsByTagName(ed.settings.element)[0];
       
 11954 					r = d.createRange();
       
 11955 
       
 11956 					// Select last location or generated block
       
 11957 					if (si != -1)
       
 11958 						r.setStart(t.find(b, 1, si), so);
       
 11959 					else
       
 11960 						r.setStart(bl, 0);
       
 11961 
       
 11962 					// Select last location or generated block
       
 11963 					if (ei != -1)
       
 11964 						r.setEnd(t.find(b, 1, ei), eo);
       
 11965 					else
       
 11966 						r.setEnd(bl, 0);
       
 11967 
       
 11968 					if (s) {
       
 11969 						s.removeAllRanges();
       
 11970 						s.addRange(r);
       
 11971 					}
       
 11972 				} else {
       
 11973 					try {
       
 11974 						r = s.createRange();
       
 11975 						r.moveToElementText(b);
       
 11976 						r.collapse(1);
       
 11977 						r.moveStart('character', si);
       
 11978 						r.moveEnd('character', ei);
       
 11979 						r.select();
       
 11980 					} catch (ex) {
       
 11981 						// Ignore
       
 11982 					}
       
 11983 				}
       
 11984 			} else if (!isIE && (n = ed.dom.get('__mce'))) {
       
 11985 				// Restore the id of the selected element
       
 11986 				if (eid)
       
 11987 					n.setAttribute('id', eid);
       
 11988 				else
       
 11989 					n.removeAttribute('id');
       
 11990 
       
 11991 				// Move caret before selected element
       
 11992 				r = d.createRange();
       
 11993 				r.setStartBefore(n);
       
 11994 				r.setEndBefore(n);
       
 11995 				se.setRng(r);
       
 11996 			}
       
 11997 		},
       
 11998 
       
 11999 		getParentBlock : function(n) {
       
 12000 			var d = this.dom;
       
 12001 
       
 12002 			return d.getParent(n, d.isBlock);
       
 12003 		},
       
 12004 
       
 12005 		insertPara : function(e) {
       
 12006 			var t = this, ed = t.editor, dom = ed.dom, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body;
       
 12007 			var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch, car;
       
 12008 
       
 12009 			// If root blocks are forced then use Operas default behavior since it's really good
       
 12010 // Removed due to bug: #1853816
       
 12011 //			if (se.forced_root_block && isOpera)
       
 12012 //				return true;
       
 12013 
       
 12014 			// Setup before range
       
 12015 			rb = d.createRange();
       
 12016 
       
 12017 			// If is before the first block element and in body, then move it into first block element
       
 12018 			rb.setStart(s.anchorNode, s.anchorOffset);
       
 12019 			rb.collapse(true);
       
 12020 
       
 12021 			// Setup after range
       
 12022 			ra = d.createRange();
       
 12023 
       
 12024 			// If is before the first block element and in body, then move it into first block element
       
 12025 			ra.setStart(s.focusNode, s.focusOffset);
       
 12026 			ra.collapse(true);
       
 12027 
       
 12028 			// Setup start/end points
       
 12029 			dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;
       
 12030 			sn = dir ? s.anchorNode : s.focusNode;
       
 12031 			so = dir ? s.anchorOffset : s.focusOffset;
       
 12032 			en = dir ? s.focusNode : s.anchorNode;
       
 12033 			eo = dir ? s.focusOffset : s.anchorOffset;
       
 12034 
       
 12035 			// If selection is in empty table cell
       
 12036 			if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) {
       
 12037 				if (sn.firstChild.nodeName == 'BR')
       
 12038 					dom.remove(sn.firstChild); // Remove BR
       
 12039 
       
 12040 				// Create two new block elements
       
 12041 				if (sn.childNodes.length == 0) {
       
 12042 					ed.dom.add(sn, se.element, null, '<br />');
       
 12043 					aft = ed.dom.add(sn, se.element, null, '<br />');
       
 12044 				} else {
       
 12045 					n = sn.innerHTML;
       
 12046 					sn.innerHTML = '';
       
 12047 					ed.dom.add(sn, se.element, null, n);
       
 12048 					aft = ed.dom.add(sn, se.element, null, '<br />');
       
 12049 				}
       
 12050 
       
 12051 				// Move caret into the last one
       
 12052 				r = d.createRange();
       
 12053 				r.selectNodeContents(aft);
       
 12054 				r.collapse(1);
       
 12055 				ed.selection.setRng(r);
       
 12056 
       
 12057 				return false;
       
 12058 			}
       
 12059 
       
 12060 			// If the caret is in an invalid location in FF we need to move it into the first block
       
 12061 			if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) {
       
 12062 				sn = en = sn.firstChild;
       
 12063 				so = eo = 0;
       
 12064 				rb = d.createRange();
       
 12065 				rb.setStart(sn, 0);
       
 12066 				ra = d.createRange();
       
 12067 				ra.setStart(en, 0);
       
 12068 			}
       
 12069 
       
 12070 			// Never use body as start or end node
       
 12071 			sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
       
 12072 			sn = sn.nodeName == "BODY" ? sn.firstChild : sn;
       
 12073 			en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
       
 12074 			en = en.nodeName == "BODY" ? en.firstChild : en;
       
 12075 
       
 12076 			// Get start and end blocks
       
 12077 			sb = t.getParentBlock(sn);
       
 12078 			eb = t.getParentBlock(en);
       
 12079 			bn = sb ? sb.nodeName : se.element; // Get block name to create
       
 12080 
       
 12081 			// Return inside list use default browser behavior
       
 12082 			if (t.dom.getParent(sb, 'ol,ul,pre'))
       
 12083 				return true;
       
 12084 
       
 12085 			// If caption or absolute layers then always generate new blocks within
       
 12086 			if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {
       
 12087 				bn = se.element;
       
 12088 				sb = null;
       
 12089 			}
       
 12090 
       
 12091 			// If caption or absolute layers then always generate new blocks within
       
 12092 			if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {
       
 12093 				bn = se.element;
       
 12094 				eb = null;
       
 12095 			}
       
 12096 
       
 12097 			// Use P instead
       
 12098 			if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(dom.getStyle(sb, 'float', 1)))) {
       
 12099 				bn = se.element;
       
 12100 				sb = eb = null;
       
 12101 			}
       
 12102 
       
 12103 			// Setup new before and after blocks
       
 12104 			bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn);
       
 12105 			aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn);
       
 12106 
       
 12107 			// Remove id from after clone
       
 12108 			aft.removeAttribute('id');
       
 12109 
       
 12110 			// Is header and cursor is at the end, then force paragraph under
       
 12111 			if (/^(H[1-6])$/.test(bn) && isAtEnd(r, sb))
       
 12112 				aft = ed.dom.create(se.element);
       
 12113 
       
 12114 			// Find start chop node
       
 12115 			n = sc = sn;
       
 12116 			do {
       
 12117 				if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
       
 12118 					break;
       
 12119 
       
 12120 				sc = n;
       
 12121 			} while ((n = n.previousSibling ? n.previousSibling : n.parentNode));
       
 12122 
       
 12123 			// Find end chop node
       
 12124 			n = ec = en;
       
 12125 			do {
       
 12126 				if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
       
 12127 					break;
       
 12128 
       
 12129 				ec = n;
       
 12130 			} while ((n = n.nextSibling ? n.nextSibling : n.parentNode));
       
 12131 
       
 12132 			// Place first chop part into before block element
       
 12133 			if (sc.nodeName == bn)
       
 12134 				rb.setStart(sc, 0);
       
 12135 			else
       
 12136 				rb.setStartBefore(sc);
       
 12137 
       
 12138 			rb.setEnd(sn, so);
       
 12139 			bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
       
 12140 
       
 12141 			// Place secnd chop part within new block element
       
 12142 			try {
       
 12143 				ra.setEndAfter(ec);
       
 12144 			} catch(ex) {
       
 12145 				//console.debug(s.focusNode, s.focusOffset);
       
 12146 			}
       
 12147 
       
 12148 			ra.setStart(en, eo);
       
 12149 			aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
       
 12150 
       
 12151 			// Create range around everything
       
 12152 			r = d.createRange();
       
 12153 			if (!sc.previousSibling && sc.parentNode.nodeName == bn) {
       
 12154 				r.setStartBefore(sc.parentNode);
       
 12155 			} else {
       
 12156 				if (rb.startContainer.nodeName == bn && rb.startOffset == 0)
       
 12157 					r.setStartBefore(rb.startContainer);
       
 12158 				else
       
 12159 					r.setStart(rb.startContainer, rb.startOffset);
       
 12160 			}
       
 12161 
       
 12162 			if (!ec.nextSibling && ec.parentNode.nodeName == bn)
       
 12163 				r.setEndAfter(ec.parentNode);
       
 12164 			else
       
 12165 				r.setEnd(ra.endContainer, ra.endOffset);
       
 12166 
       
 12167 			// Delete and replace it with new block elements
       
 12168 			r.deleteContents();
       
 12169 
       
 12170 			if (isOpera)
       
 12171 				ed.getWin().scrollTo(0, vp.y);
       
 12172 
       
 12173 			// Never wrap blocks in blocks
       
 12174 			if (bef.firstChild && bef.firstChild.nodeName == bn)
       
 12175 				bef.innerHTML = bef.firstChild.innerHTML;
       
 12176 
       
 12177 			if (aft.firstChild && aft.firstChild.nodeName == bn)
       
 12178 				aft.innerHTML = aft.firstChild.innerHTML;
       
 12179 
       
 12180 			// Padd empty blocks
       
 12181 			if (isEmpty(bef))
       
 12182 				bef.innerHTML = '<br />';
       
 12183 
       
 12184 			function appendStyles(e, en) {
       
 12185 				var nl = [], nn, n, i;
       
 12186 
       
 12187 				e.innerHTML = '';
       
 12188 
       
 12189 				// Make clones of style elements
       
 12190 				if (se.keep_styles) {
       
 12191 					n = en;
       
 12192 					do {
       
 12193 						// We only want style specific elements
       
 12194 						if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) {
       
 12195 							nn = n.cloneNode(false);
       
 12196 							dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique
       
 12197 							nl.push(nn);
       
 12198 						}
       
 12199 					} while (n = n.parentNode);
       
 12200 				}
       
 12201 
       
 12202 				// Append style elements to aft
       
 12203 				if (nl.length > 0) {
       
 12204 					for (i = nl.length - 1, nn = e; i >= 0; i--)
       
 12205 						nn = nn.appendChild(nl[i]);
       
 12206 
       
 12207 					// Padd most inner style element
       
 12208 					nl[0].innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there
       
 12209 					return nl[0]; // Move caret to most inner element
       
 12210 				} else
       
 12211 					e.innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there
       
 12212 			};
       
 12213 
       
 12214 			// Fill empty afterblook with current style
       
 12215 			if (isEmpty(aft))
       
 12216 				car = appendStyles(aft, en);
       
 12217 
       
 12218 			// Opera needs this one backwards for older versions
       
 12219 			if (isOpera && parseFloat(opera.version()) < 9.5) {
       
 12220 				r.insertNode(bef);
       
 12221 				r.insertNode(aft);
       
 12222 			} else {
       
 12223 				r.insertNode(aft);
       
 12224 				r.insertNode(bef);
       
 12225 			}
       
 12226 
       
 12227 			// Normalize
       
 12228 			aft.normalize();
       
 12229 			bef.normalize();
       
 12230 
       
 12231 			function first(n) {
       
 12232 				return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() || n;
       
 12233 			};
       
 12234 
       
 12235 			// Move cursor and scroll into view
       
 12236 			r = d.createRange();
       
 12237 			r.selectNodeContents(isGecko ? first(car || aft) : car || aft);
       
 12238 			r.collapse(1);
       
 12239 			s.removeAllRanges();
       
 12240 			s.addRange(r);
       
 12241 
       
 12242 			// scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs
       
 12243 			y = ed.dom.getPos(aft).y;
       
 12244 			ch = aft.clientHeight;
       
 12245 
       
 12246 			// Is element within viewport
       
 12247 			if (y < vp.y || y + ch > vp.y + vp.h) {
       
 12248 				ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks
       
 12249 				//console.debug('SCROLL!', 'vp.y: ' + vp.y, 'y' + y, 'vp.h' + vp.h, 'clientHeight' + aft.clientHeight, 'yyy: ' + (y < vp.y ? y : y - vp.h + aft.clientHeight));
       
 12250 			}
       
 12251 
       
 12252 			return false;
       
 12253 		},
       
 12254 
       
 12255 		backspaceDelete : function(e, bs) {
       
 12256 			var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn;
       
 12257 
       
 12258 			/*
       
 12259 			var par, rng, nextBlock;
       
 12260 
       
 12261 			// Delete key will not merge paragraphs on Gecko so we need to do this manually
       
 12262 			// Hitting the delete key at the following caret position doesn't merge the elements <p>A|</p><p>B</p>
       
 12263 			// This logic will merge them into this: <p>A|B</p>
       
 12264 			if (e.keyCode == 46) {
       
 12265 				if (r.collapsed) {
       
 12266 					par = dom.getParent(sc, 'p,h1,h2,h3,h4,h5,h6,div');
       
 12267 
       
 12268 					if (par) {
       
 12269 						rng = dom.createRng();
       
 12270 
       
 12271 						rng.setStart(sc, r.startOffset);
       
 12272 						rng.setEndAfter(par);
       
 12273 
       
 12274 						// Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element
       
 12275 						if (dom.getOuterHTML(rng.cloneContents()).replace(/<[^>]+>/g, '').length == 0) {
       
 12276 							nextBlock = dom.getNext(par, 'p,h1,h2,h3,h4,h5,h6,div');
       
 12277 
       
 12278 							// Copy all children from next sibling block and remove it
       
 12279 							if (nextBlock) {
       
 12280 								each(nextBlock.childNodes, function(node) {
       
 12281 									par.appendChild(node.cloneNode(true));
       
 12282 								});
       
 12283 
       
 12284 								dom.remove(nextBlock);
       
 12285 							}
       
 12286 
       
 12287 							// Block the default even since the Gecko team might eventually fix this
       
 12288 							// We will remove this logic once they do we can't feature detect this one
       
 12289 							e.preventDefault();
       
 12290 							return;
       
 12291 						}
       
 12292 					}
       
 12293 				}
       
 12294 			}
       
 12295 			*/
       
 12296 
       
 12297 			// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
       
 12298 			// This workaround removes the element by hand and moves the caret to the previous element
       
 12299 			if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
       
 12300 				if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
       
 12301 					// Find previous block element
       
 12302 					n = sc;
       
 12303 					while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ;
       
 12304 
       
 12305 					if (n) {
       
 12306 						if (sc != b.firstChild) {
       
 12307 							// Find last text node
       
 12308 							w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
       
 12309 							while (tn = w.nextNode())
       
 12310 								n = tn;
       
 12311 
       
 12312 							// Place caret at the end of last text node
       
 12313 							r = ed.getDoc().createRange();
       
 12314 							r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);
       
 12315 							r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);
       
 12316 							se.setRng(r);
       
 12317 
       
 12318 							// Remove the target container
       
 12319 							ed.dom.remove(sc);
       
 12320 						}
       
 12321 
       
 12322 						return Event.cancel(e);
       
 12323 					}
       
 12324 				}
       
 12325 			}
       
 12326 
       
 12327 			// Gecko generates BR elements here and there, we don't like those so lets remove them
       
 12328 			function handler(e) {
       
 12329 				var pr;
       
 12330 
       
 12331 				e = e.target;
       
 12332 
       
 12333 				// A new BR was created in a block element, remove it
       
 12334 				if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {
       
 12335 					pr = e.previousSibling;
       
 12336 
       
 12337 					Event.remove(b, 'DOMNodeInserted', handler);
       
 12338 
       
 12339 					// Is there whitespace at the end of the node before then we might need the pesky BR
       
 12340 					// to place the caret at a correct location see bug: #2013943
       
 12341 					if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue))
       
 12342 						return;
       
 12343 
       
 12344 					// Only remove BR elements that got inserted in the middle of the text
       
 12345 					if (e.previousSibling || e.nextSibling)
       
 12346 						ed.dom.remove(e);
       
 12347 				}
       
 12348 			};
       
 12349 
       
 12350 			// Listen for new nodes
       
 12351 			Event._add(b, 'DOMNodeInserted', handler);
       
 12352 
       
 12353 			// Remove listener
       
 12354 			window.setTimeout(function() {
       
 12355 				Event._remove(b, 'DOMNodeInserted', handler);
       
 12356 			}, 1);
       
 12357 		}
       
 12358 	});
       
 12359 })(tinymce);
       
 12360 (function(tinymce) {
       
 12361 	// Shorten names
       
 12362 	var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;
       
 12363 
       
 12364 	tinymce.create('tinymce.ControlManager', {
       
 12365 		ControlManager : function(ed, s) {
       
 12366 			var t = this, i;
       
 12367 
       
 12368 			s = s || {};
       
 12369 			t.editor = ed;
       
 12370 			t.controls = {};
       
 12371 			t.onAdd = new tinymce.util.Dispatcher(t);
       
 12372 			t.onPostRender = new tinymce.util.Dispatcher(t);
       
 12373 			t.prefix = s.prefix || ed.id + '_';
       
 12374 			t._cls = {};
       
 12375 
       
 12376 			t.onPostRender.add(function() {
       
 12377 				each(t.controls, function(c) {
       
 12378 					c.postRender();
       
 12379 				});
       
 12380 			});
       
 12381 		},
       
 12382 
       
 12383 		get : function(id) {
       
 12384 			return this.controls[this.prefix + id] || this.controls[id];
       
 12385 		},
       
 12386 
       
 12387 		setActive : function(id, s) {
       
 12388 			var c = null;
       
 12389 
       
 12390 			if (c = this.get(id))
       
 12391 				c.setActive(s);
       
 12392 
       
 12393 			return c;
       
 12394 		},
       
 12395 
       
 12396 		setDisabled : function(id, s) {
       
 12397 			var c = null;
       
 12398 
       
 12399 			if (c = this.get(id))
       
 12400 				c.setDisabled(s);
       
 12401 
       
 12402 			return c;
       
 12403 		},
       
 12404 
       
 12405 		add : function(c) {
       
 12406 			var t = this;
       
 12407 
       
 12408 			if (c) {
       
 12409 				t.controls[c.id] = c;
       
 12410 				t.onAdd.dispatch(c, t);
       
 12411 			}
       
 12412 
       
 12413 			return c;
       
 12414 		},
       
 12415 
       
 12416 		createControl : function(n) {
       
 12417 			var c, t = this, ed = t.editor;
       
 12418 
       
 12419 			each(ed.plugins, function(p) {
       
 12420 				if (p.createControl) {
       
 12421 					c = p.createControl(n, t);
       
 12422 
       
 12423 					if (c)
       
 12424 						return false;
       
 12425 				}
       
 12426 			});
       
 12427 
       
 12428 			switch (n) {
       
 12429 				case "|":
       
 12430 				case "separator":
       
 12431 					return t.createSeparator();
       
 12432 			}
       
 12433 
       
 12434 			if (!c && ed.buttons && (c = ed.buttons[n]))
       
 12435 				return t.createButton(n, c);
       
 12436 
       
 12437 			return t.add(c);
       
 12438 		},
       
 12439 
       
 12440 		createDropMenu : function(id, s, cc) {
       
 12441 			var t = this, ed = t.editor, c, bm, v, cls;
       
 12442 
       
 12443 			s = extend({
       
 12444 				'class' : 'mceDropDown',
       
 12445 				constrain : ed.settings.constrain_menus
       
 12446 			}, s);
       
 12447 
       
 12448 			s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';
       
 12449 			if (v = ed.getParam('skin_variant'))
       
 12450 				s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
       
 12451 
       
 12452 			id = t.prefix + id;
       
 12453 			cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
       
 12454 			c = t.controls[id] = new cls(id, s);
       
 12455 			c.onAddItem.add(function(c, o) {
       
 12456 				var s = o.settings;
       
 12457 
       
 12458 				s.title = ed.getLang(s.title, s.title);
       
 12459 
       
 12460 				if (!s.onclick) {
       
 12461 					s.onclick = function(v) {
       
 12462 						ed.execCommand(s.cmd, s.ui || false, s.value);
       
 12463 					};
       
 12464 				}
       
 12465 			});
       
 12466 
       
 12467 			ed.onRemove.add(function() {
       
 12468 				c.destroy();
       
 12469 			});
       
 12470 
       
 12471 			// Fix for bug #1897785, #1898007
       
 12472 			if (tinymce.isIE) {
       
 12473 				c.onShowMenu.add(function() {
       
 12474 					// IE 8 needs focus in order to store away a range with the current collapsed caret location
       
 12475 					ed.focus();
       
 12476 
       
 12477 					bm = ed.selection.getBookmark(1);
       
 12478 				});
       
 12479 
       
 12480 				c.onHideMenu.add(function() {
       
 12481 					if (bm) {
       
 12482 						ed.selection.moveToBookmark(bm);
       
 12483 						bm = 0;
       
 12484 					}
       
 12485 				});
       
 12486 			}
       
 12487 
       
 12488 			return t.add(c);
       
 12489 		},
       
 12490 
       
 12491 		createListBox : function(id, s, cc) {
       
 12492 			var t = this, ed = t.editor, cmd, c, cls;
       
 12493 
       
 12494 			if (t.get(id))
       
 12495 				return null;
       
 12496 
       
 12497 			s.title = ed.translate(s.title);
       
 12498 			s.scope = s.scope || ed;
       
 12499 
       
 12500 			if (!s.onselect) {
       
 12501 				s.onselect = function(v) {
       
 12502 					ed.execCommand(s.cmd, s.ui || false, v || s.value);
       
 12503 				};
       
 12504 			}
       
 12505 
       
 12506 			s = extend({
       
 12507 				title : s.title,
       
 12508 				'class' : 'mce_' + id,
       
 12509 				scope : s.scope,
       
 12510 				control_manager : t
       
 12511 			}, s);
       
 12512 
       
 12513 			id = t.prefix + id;
       
 12514 
       
 12515 			if (ed.settings.use_native_selects)
       
 12516 				c = new tinymce.ui.NativeListBox(id, s);
       
 12517 			else {
       
 12518 				cls = cc || t._cls.listbox || tinymce.ui.ListBox;
       
 12519 				c = new cls(id, s);
       
 12520 			}
       
 12521 
       
 12522 			t.controls[id] = c;
       
 12523 
       
 12524 			// Fix focus problem in Safari
       
 12525 			if (tinymce.isWebKit) {
       
 12526 				c.onPostRender.add(function(c, n) {
       
 12527 					// Store bookmark on mousedown
       
 12528 					Event.add(n, 'mousedown', function() {
       
 12529 						ed.bookmark = ed.selection.getBookmark(1);
       
 12530 					});
       
 12531 
       
 12532 					// Restore on focus, since it might be lost
       
 12533 					Event.add(n, 'focus', function() {
       
 12534 						ed.selection.moveToBookmark(ed.bookmark);
       
 12535 						ed.bookmark = null;
       
 12536 					});
       
 12537 				});
       
 12538 			}
       
 12539 
       
 12540 			if (c.hideMenu)
       
 12541 				ed.onMouseDown.add(c.hideMenu, c);
       
 12542 
       
 12543 			return t.add(c);
       
 12544 		},
       
 12545 
       
 12546 		createButton : function(id, s, cc) {
       
 12547 			var t = this, ed = t.editor, o, c, cls;
       
 12548 
       
 12549 			if (t.get(id))
       
 12550 				return null;
       
 12551 
       
 12552 			s.title = ed.translate(s.title);
       
 12553 			s.label = ed.translate(s.label);
       
 12554 			s.scope = s.scope || ed;
       
 12555 
       
 12556 			if (!s.onclick && !s.menu_button) {
       
 12557 				s.onclick = function() {
       
 12558 					ed.execCommand(s.cmd, s.ui || false, s.value);
       
 12559 				};
       
 12560 			}
       
 12561 
       
 12562 			s = extend({
       
 12563 				title : s.title,
       
 12564 				'class' : 'mce_' + id,
       
 12565 				unavailable_prefix : ed.getLang('unavailable', ''),
       
 12566 				scope : s.scope,
       
 12567 				control_manager : t
       
 12568 			}, s);
       
 12569 
       
 12570 			id = t.prefix + id;
       
 12571 
       
 12572 			if (s.menu_button) {
       
 12573 				cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;
       
 12574 				c = new cls(id, s);
       
 12575 				ed.onMouseDown.add(c.hideMenu, c);
       
 12576 			} else {
       
 12577 				cls = t._cls.button || tinymce.ui.Button;
       
 12578 				c = new cls(id, s);
       
 12579 			}
       
 12580 
       
 12581 			return t.add(c);
       
 12582 		},
       
 12583 
       
 12584 		createMenuButton : function(id, s, cc) {
       
 12585 			s = s || {};
       
 12586 			s.menu_button = 1;
       
 12587 
       
 12588 			return this.createButton(id, s, cc);
       
 12589 		},
       
 12590 
       
 12591 		createSplitButton : function(id, s, cc) {
       
 12592 			var t = this, ed = t.editor, cmd, c, cls;
       
 12593 
       
 12594 			if (t.get(id))
       
 12595 				return null;
       
 12596 
       
 12597 			s.title = ed.translate(s.title);
       
 12598 			s.scope = s.scope || ed;
       
 12599 
       
 12600 			if (!s.onclick) {
       
 12601 				s.onclick = function(v) {
       
 12602 					ed.execCommand(s.cmd, s.ui || false, v || s.value);
       
 12603 				};
       
 12604 			}
       
 12605 
       
 12606 			if (!s.onselect) {
       
 12607 				s.onselect = function(v) {
       
 12608 					ed.execCommand(s.cmd, s.ui || false, v || s.value);
       
 12609 				};
       
 12610 			}
       
 12611 
       
 12612 			s = extend({
       
 12613 				title : s.title,
       
 12614 				'class' : 'mce_' + id,
       
 12615 				scope : s.scope,
       
 12616 				control_manager : t
       
 12617 			}, s);
       
 12618 
       
 12619 			id = t.prefix + id;
       
 12620 			cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;
       
 12621 			c = t.add(new cls(id, s));
       
 12622 			ed.onMouseDown.add(c.hideMenu, c);
       
 12623 
       
 12624 			return c;
       
 12625 		},
       
 12626 
       
 12627 		createColorSplitButton : function(id, s, cc) {
       
 12628 			var t = this, ed = t.editor, cmd, c, cls, bm;
       
 12629 
       
 12630 			if (t.get(id))
       
 12631 				return null;
       
 12632 
       
 12633 			s.title = ed.translate(s.title);
       
 12634 			s.scope = s.scope || ed;
       
 12635 
       
 12636 			if (!s.onclick) {
       
 12637 				s.onclick = function(v) {
       
 12638 					if (tinymce.isIE)
       
 12639 						bm = ed.selection.getBookmark(1);
       
 12640 
       
 12641 					ed.execCommand(s.cmd, s.ui || false, v || s.value);
       
 12642 				};
       
 12643 			}
       
 12644 
       
 12645 			if (!s.onselect) {
       
 12646 				s.onselect = function(v) {
       
 12647 					ed.execCommand(s.cmd, s.ui || false, v || s.value);
       
 12648 				};
       
 12649 			}
       
 12650 
       
 12651 			s = extend({
       
 12652 				title : s.title,
       
 12653 				'class' : 'mce_' + id,
       
 12654 				'menu_class' : ed.getParam('skin') + 'Skin',
       
 12655 				scope : s.scope,
       
 12656 				more_colors_title : ed.getLang('more_colors')
       
 12657 			}, s);
       
 12658 
       
 12659 			id = t.prefix + id;
       
 12660 			cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;
       
 12661 			c = new cls(id, s);
       
 12662 			ed.onMouseDown.add(c.hideMenu, c);
       
 12663 
       
 12664 			// Remove the menu element when the editor is removed
       
 12665 			ed.onRemove.add(function() {
       
 12666 				c.destroy();
       
 12667 			});
       
 12668 
       
 12669 			// Fix for bug #1897785, #1898007
       
 12670 			if (tinymce.isIE) {
       
 12671 				c.onShowMenu.add(function() {
       
 12672 					// IE 8 needs focus in order to store away a range with the current collapsed caret location
       
 12673 					ed.focus();
       
 12674 					bm = ed.selection.getBookmark(1);
       
 12675 				});
       
 12676 
       
 12677 				c.onHideMenu.add(function() {
       
 12678 					if (bm) {
       
 12679 						ed.selection.moveToBookmark(bm);
       
 12680 						bm = 0;
       
 12681 					}
       
 12682 				});
       
 12683 			}
       
 12684 
       
 12685 			return t.add(c);
       
 12686 		},
       
 12687 
       
 12688 		createToolbar : function(id, s, cc) {
       
 12689 			var c, t = this, cls;
       
 12690 
       
 12691 			id = t.prefix + id;
       
 12692 			cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;
       
 12693 			c = new cls(id, s);
       
 12694 
       
 12695 			if (t.get(id))
       
 12696 				return null;
       
 12697 
       
 12698 			return t.add(c);
       
 12699 		},
       
 12700 
       
 12701 		createSeparator : function(cc) {
       
 12702 			var cls = cc || this._cls.separator || tinymce.ui.Separator;
       
 12703 
       
 12704 			return new cls();
       
 12705 		},
       
 12706 
       
 12707 		setControlType : function(n, c) {
       
 12708 			return this._cls[n.toLowerCase()] = c;
       
 12709 		},
       
 12710 	
       
 12711 		destroy : function() {
       
 12712 			each(this.controls, function(c) {
       
 12713 				c.destroy();
       
 12714 			});
       
 12715 
       
 12716 			this.controls = null;
       
 12717 		}
       
 12718 	});
       
 12719 })(tinymce);
       
 12720 (function(tinymce) {
       
 12721 	var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;
       
 12722 
       
 12723 	tinymce.create('tinymce.WindowManager', {
       
 12724 		WindowManager : function(ed) {
       
 12725 			var t = this;
       
 12726 
       
 12727 			t.editor = ed;
       
 12728 			t.onOpen = new Dispatcher(t);
       
 12729 			t.onClose = new Dispatcher(t);
       
 12730 			t.params = {};
       
 12731 			t.features = {};
       
 12732 		},
       
 12733 
       
 12734 		open : function(s, p) {
       
 12735 			var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;
       
 12736 
       
 12737 			// Default some options
       
 12738 			s = s || {};
       
 12739 			p = p || {};
       
 12740 			sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window
       
 12741 			sh = isOpera ? vp.h : screen.height;
       
 12742 			s.name = s.name || 'mc_' + new Date().getTime();
       
 12743 			s.width = parseInt(s.width || 320);
       
 12744 			s.height = parseInt(s.height || 240);
       
 12745 			s.resizable = true;
       
 12746 			s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);
       
 12747 			s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);
       
 12748 			p.inline = false;
       
 12749 			p.mce_width = s.width;
       
 12750 			p.mce_height = s.height;
       
 12751 			p.mce_auto_focus = s.auto_focus;
       
 12752 
       
 12753 			if (mo) {
       
 12754 				if (isIE) {
       
 12755 					s.center = true;
       
 12756 					s.help = false;
       
 12757 					s.dialogWidth = s.width + 'px';
       
 12758 					s.dialogHeight = s.height + 'px';
       
 12759 					s.scroll = s.scrollbars || false;
       
 12760 				}
       
 12761 			}
       
 12762 
       
 12763 			// Build features string
       
 12764 			each(s, function(v, k) {
       
 12765 				if (tinymce.is(v, 'boolean'))
       
 12766 					v = v ? 'yes' : 'no';
       
 12767 
       
 12768 				if (!/^(name|url)$/.test(k)) {
       
 12769 					if (isIE && mo)
       
 12770 						f += (f ? ';' : '') + k + ':' + v;
       
 12771 					else
       
 12772 						f += (f ? ',' : '') + k + '=' + v;
       
 12773 				}
       
 12774 			});
       
 12775 
       
 12776 			t.features = s;
       
 12777 			t.params = p;
       
 12778 			t.onOpen.dispatch(t, s, p);
       
 12779 
       
 12780 			u = s.url || s.file;
       
 12781 			u = tinymce._addVer(u);
       
 12782 
       
 12783 			try {
       
 12784 				if (isIE && mo) {
       
 12785 					w = 1;
       
 12786 					window.showModalDialog(u, window, f);
       
 12787 				} else
       
 12788 					w = window.open(u, s.name, f);
       
 12789 			} catch (ex) {
       
 12790 				// Ignore
       
 12791 			}
       
 12792 
       
 12793 			if (!w)
       
 12794 				alert(t.editor.getLang('popup_blocked'));
       
 12795 		},
       
 12796 
       
 12797 		close : function(w) {
       
 12798 			w.close();
       
 12799 			this.onClose.dispatch(this);
       
 12800 		},
       
 12801 
       
 12802 		createInstance : function(cl, a, b, c, d, e) {
       
 12803 			var f = tinymce.resolve(cl);
       
 12804 
       
 12805 			return new f(a, b, c, d, e);
       
 12806 		},
       
 12807 
       
 12808 		confirm : function(t, cb, s, w) {
       
 12809 			w = w || window;
       
 12810 
       
 12811 			cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t))));
       
 12812 		},
       
 12813 
       
 12814 		alert : function(tx, cb, s, w) {
       
 12815 			var t = this;
       
 12816 
       
 12817 			w = w || window;
       
 12818 			w.alert(t._decode(t.editor.getLang(tx, tx)));
       
 12819 
       
 12820 			if (cb)
       
 12821 				cb.call(s || t);
       
 12822 		},
       
 12823 
       
 12824 		// Internal functions
       
 12825 
       
 12826 		_decode : function(s) {
       
 12827 			return tinymce.DOM.decode(s).replace(/\\n/g, '\n');
       
 12828 		}
       
 12829 	});
       
 12830 }(tinymce));(function(tinymce) {
       
 12831 	tinymce.CommandManager = function() {
       
 12832 		var execCommands = {}, queryStateCommands = {}, queryValueCommands = {};
       
 12833 
       
 12834 		function add(collection, cmd, func, scope) {
       
 12835 			if (typeof(cmd) == 'string')
       
 12836 				cmd = [cmd];
       
 12837 
       
 12838 			tinymce.each(cmd, function(cmd) {
       
 12839 				collection[cmd.toLowerCase()] = {func : func, scope : scope};
       
 12840 			});
       
 12841 		};
       
 12842 
       
 12843 		tinymce.extend(this, {
       
 12844 			add : function(cmd, func, scope) {
       
 12845 				add(execCommands, cmd, func, scope);
       
 12846 			},
       
 12847 
       
 12848 			addQueryStateHandler : function(cmd, func, scope) {
       
 12849 				add(queryStateCommands, cmd, func, scope);
       
 12850 			},
       
 12851 
       
 12852 			addQueryValueHandler : function(cmd, func, scope) {
       
 12853 				add(queryValueCommands, cmd, func, scope);
       
 12854 			},
       
 12855 
       
 12856 			execCommand : function(scope, cmd, ui, value, args) {
       
 12857 				if (cmd = execCommands[cmd.toLowerCase()]) {
       
 12858 					if (cmd.func.call(scope || cmd.scope, ui, value, args) !== false)
       
 12859 						return true;
       
 12860 				}
       
 12861 			},
       
 12862 
       
 12863 			queryCommandValue : function() {
       
 12864 				if (cmd = queryValueCommands[cmd.toLowerCase()])
       
 12865 					return cmd.func.call(scope || cmd.scope, ui, value, args);
       
 12866 			},
       
 12867 
       
 12868 			queryCommandState : function() {
       
 12869 				if (cmd = queryStateCommands[cmd.toLowerCase()])
       
 12870 					return cmd.func.call(scope || cmd.scope, ui, value, args);
       
 12871 			}
       
 12872 		});
       
 12873 	};
       
 12874 
       
 12875 	tinymce.GlobalCommands = new tinymce.CommandManager();
       
 12876 })(tinymce);(function(tinymce) {
       
 12877 	function processRange(dom, start, end, callback) {
       
 12878 		var ancestor, n, startPoint, endPoint, sib;
       
 12879 
       
 12880 		function findEndPoint(n, c) {
       
 12881 			do {
       
 12882 				if (n.parentNode == c)
       
 12883 					return n;
       
 12884 
       
 12885 				n = n.parentNode;
       
 12886 			} while(n);
       
 12887 		};
       
 12888 
       
 12889 		function process(n) {
       
 12890 			callback(n);
       
 12891 			tinymce.walk(n, callback, 'childNodes');
       
 12892 		};
       
 12893 
       
 12894 		// Find common ancestor and end points
       
 12895 		ancestor = dom.findCommonAncestor(start, end);
       
 12896 		startPoint = findEndPoint(start, ancestor) || start;
       
 12897 		endPoint = findEndPoint(end, ancestor) || end;
       
 12898 
       
 12899 		// Process left leaf
       
 12900 		for (n = start; n && n != startPoint; n = n.parentNode) {
       
 12901 			for (sib = n.nextSibling; sib; sib = sib.nextSibling)
       
 12902 				process(sib);
       
 12903 		}
       
 12904 
       
 12905 		// Process middle from start to end point
       
 12906 		if (startPoint != endPoint) {
       
 12907 			for (n = startPoint.nextSibling; n && n != endPoint; n = n.nextSibling)
       
 12908 				process(n);
       
 12909 		} else
       
 12910 			process(startPoint);
       
 12911 
       
 12912 		// Process right leaf
       
 12913 		for (n = end; n && n != endPoint; n = n.parentNode) {
       
 12914 			for (sib = n.previousSibling; sib; sib = sib.previousSibling)
       
 12915 				process(sib);
       
 12916 		}
       
 12917 	};
       
 12918 
       
 12919 	tinymce.GlobalCommands.add('RemoveFormat', function() {
       
 12920 		var ed = this, dom = ed.dom, s = ed.selection, r = s.getRng(1), nodes = [], bm, start, end, sc, so, ec, eo, n;
       
 12921 
       
 12922 		function findFormatRoot(n) {
       
 12923 			var sp;
       
 12924 
       
 12925 			dom.getParent(n, function(n) {
       
 12926 				if (dom.is(n, ed.getParam('removeformat_selector')))
       
 12927 					sp = n;
       
 12928 
       
 12929 				return dom.isBlock(n);
       
 12930 			}, ed.getBody());
       
 12931 
       
 12932 			return sp;
       
 12933 		};
       
 12934 
       
 12935 		function collect(n) {
       
 12936 			if (dom.is(n, ed.getParam('removeformat_selector')))
       
 12937 				nodes.push(n);
       
 12938 		};
       
 12939 
       
 12940 		function walk(n) {
       
 12941 			collect(n);
       
 12942 			tinymce.walk(n, collect, 'childNodes');
       
 12943 		};
       
 12944 
       
 12945 		bm = s.getBookmark();
       
 12946 		sc = r.startContainer;
       
 12947 		ec = r.endContainer;
       
 12948 		so = r.startOffset;
       
 12949 		eo = r.endOffset;
       
 12950 		sc = sc.nodeType == 1 ? sc.childNodes[Math.min(so, sc.childNodes.length - 1)] : sc;
       
 12951 		ec = ec.nodeType == 1 ? ec.childNodes[Math.min(so == eo ? eo : eo - 1, ec.childNodes.length - 1)] : ec;
       
 12952 
       
 12953 		// Same container
       
 12954 		if (sc == ec) { // TEXT_NODE
       
 12955 			start = findFormatRoot(sc);
       
 12956 
       
 12957 			// Handle single text node
       
 12958 			if (sc.nodeType == 3) {
       
 12959 				if (start && start.nodeType == 1) { // ELEMENT
       
 12960 					n = sc.splitText(so);
       
 12961 					n.splitText(eo - so);
       
 12962 					dom.split(start, n);
       
 12963 
       
 12964 					s.moveToBookmark(bm);
       
 12965 				}
       
 12966 
       
 12967 				return;
       
 12968 			}
       
 12969 
       
 12970 			// Handle single element
       
 12971 			walk(dom.split(start, sc) || sc);
       
 12972 		} else {
       
 12973 			// Find start/end format root
       
 12974 			start = findFormatRoot(sc);
       
 12975 			end = findFormatRoot(ec);
       
 12976 
       
 12977 			// Split start text node
       
 12978 			if (start) {
       
 12979 				if (sc.nodeType == 3) { // TEXT
       
 12980 					// Since IE doesn't support white space nodes in the DOM we need to
       
 12981 					// add this invisible character so that the splitText function can split the contents
       
 12982 					if (so == sc.nodeValue.length)
       
 12983 						sc.nodeValue += '\uFEFF'; // Yet another pesky IE fix
       
 12984 
       
 12985 					sc = sc.splitText(so);
       
 12986 				}
       
 12987 			}
       
 12988 
       
 12989 			// Split end text node
       
 12990 			if (end) {
       
 12991 				if (ec.nodeType == 3) // TEXT
       
 12992 					ec.splitText(eo);
       
 12993 			}
       
 12994 
       
 12995 			// If the start and end format root is the same then we need to wrap
       
 12996 			// the end node in a span since the split calls might change the reference
       
 12997 			// Example: <p><b><em>x[yz<span>---</span>12]3</em></b></p>
       
 12998 			if (start && start == end)
       
 12999 				dom.replace(dom.create('span', {id : '__end'}, ec.cloneNode(true)), ec);
       
 13000 
       
 13001 			// Split all start containers down to the format root
       
 13002 			if (start)
       
 13003 				start = dom.split(start, sc);
       
 13004 			else
       
 13005 				start = sc;
       
 13006 
       
 13007 			// If there is a span wrapper use that one instead
       
 13008 			if (n = dom.get('__end')) {
       
 13009 				ec = n;
       
 13010 				end = findFormatRoot(ec);
       
 13011 			}
       
 13012 
       
 13013 			// Split all end containers down to the format root
       
 13014 			if (end)
       
 13015 				end = dom.split(end, ec);
       
 13016 			else
       
 13017 				end = ec;
       
 13018 
       
 13019 			// Collect nodes in between
       
 13020 			processRange(dom, start, end, collect);
       
 13021 
       
 13022 			// Remove invisible character for IE workaround if we find it
       
 13023 			if (sc.nodeValue == '\uFEFF')
       
 13024 				sc.nodeValue = '';
       
 13025 
       
 13026 			// Process start/end container elements
       
 13027 			walk(ec);
       
 13028 			walk(sc);
       
 13029 		}
       
 13030 
       
 13031 		// Remove all collected nodes
       
 13032 		tinymce.each(nodes, function(n) {
       
 13033 			dom.remove(n, 1);
       
 13034 		});
       
 13035 
       
 13036 		// Remove leftover wrapper
       
 13037 		dom.remove('__end', 1);
       
 13038 
       
 13039 		s.moveToBookmark(bm);
       
 13040 	});
       
 13041 })(tinymce);
       
 13042 (function(tinymce) {
       
 13043 	tinymce.GlobalCommands.add('mceBlockQuote', function() {
       
 13044 		var ed = this, s = ed.selection, dom = ed.dom, sb, eb, n, bm, bq, r, bq2, i, nl;
       
 13045 
       
 13046 		function getBQ(e) {
       
 13047 			return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';});
       
 13048 		};
       
 13049 
       
 13050 		// Get start/end block
       
 13051 		sb = dom.getParent(s.getStart(), dom.isBlock);
       
 13052 		eb = dom.getParent(s.getEnd(), dom.isBlock);
       
 13053 
       
 13054 		// Remove blockquote(s)
       
 13055 		if (bq = getBQ(sb)) {
       
 13056 			if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))
       
 13057 				bm = s.getBookmark();
       
 13058 
       
 13059 			// Move all elements after the end block into new bq
       
 13060 			if (getBQ(eb)) {
       
 13061 				bq2 = bq.cloneNode(false);
       
 13062 
       
 13063 				while (n = eb.nextSibling)
       
 13064 					bq2.appendChild(n.parentNode.removeChild(n));
       
 13065 			}
       
 13066 
       
 13067 			// Add new bq after
       
 13068 			if (bq2)
       
 13069 				dom.insertAfter(bq2, bq);
       
 13070 
       
 13071 			// Move all selected blocks after the current bq
       
 13072 			nl = s.getSelectedBlocks(sb, eb);
       
 13073 			for (i = nl.length - 1; i >= 0; i--) {
       
 13074 				dom.insertAfter(nl[i], bq);
       
 13075 			}
       
 13076 
       
 13077 			// Empty bq, then remove it
       
 13078 			if (/^\s*$/.test(bq.innerHTML))
       
 13079 				dom.remove(bq, 1); // Keep children so boomark restoration works correctly
       
 13080 
       
 13081 			// Empty bq, then remote it
       
 13082 			if (bq2 && /^\s*$/.test(bq2.innerHTML))
       
 13083 				dom.remove(bq2, 1); // Keep children so boomark restoration works correctly
       
 13084 
       
 13085 			if (!bm) {
       
 13086 				// Move caret inside empty block element
       
 13087 				if (!tinymce.isIE) {
       
 13088 					r = ed.getDoc().createRange();
       
 13089 					r.setStart(sb, 0);
       
 13090 					r.setEnd(sb, 0);
       
 13091 					s.setRng(r);
       
 13092 				} else {
       
 13093 					s.select(sb);
       
 13094 					s.collapse(0);
       
 13095 
       
 13096 					// IE misses the empty block some times element so we must move back the caret
       
 13097 					if (dom.getParent(s.getStart(), dom.isBlock) != sb) {
       
 13098 						r = s.getRng();
       
 13099 						r.move('character', -1);
       
 13100 						r.select();
       
 13101 					}
       
 13102 				}
       
 13103 			} else
       
 13104 				ed.selection.moveToBookmark(bm);
       
 13105 
       
 13106 			return;
       
 13107 		}
       
 13108 
       
 13109 		// Since IE can start with a totally empty document we need to add the first bq and paragraph
       
 13110 		if (tinymce.isIE && !sb && !eb) {
       
 13111 			ed.getDoc().execCommand('Indent');
       
 13112 			n = getBQ(s.getNode());
       
 13113 			n.style.margin = n.dir = ''; // IE adds margin and dir to bq
       
 13114 			return;
       
 13115 		}
       
 13116 
       
 13117 		if (!sb || !eb)
       
 13118 			return;
       
 13119 
       
 13120 		// If empty paragraph node then do not use bookmark
       
 13121 		if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))
       
 13122 			bm = s.getBookmark();
       
 13123 
       
 13124 		// Move selected block elements into a bq
       
 13125 		tinymce.each(s.getSelectedBlocks(getBQ(s.getStart()), getBQ(s.getEnd())), function(e) {
       
 13126 			// Found existing BQ add to this one
       
 13127 			if (e.nodeName == 'BLOCKQUOTE' && !bq) {
       
 13128 				bq = e;
       
 13129 				return;
       
 13130 			}
       
 13131 
       
 13132 			// No BQ found, create one
       
 13133 			if (!bq) {
       
 13134 				bq = dom.create('blockquote');
       
 13135 				e.parentNode.insertBefore(bq, e);
       
 13136 			}
       
 13137 
       
 13138 			// Add children from existing BQ
       
 13139 			if (e.nodeName == 'BLOCKQUOTE' && bq) {
       
 13140 				n = e.firstChild;
       
 13141 
       
 13142 				while (n) {
       
 13143 					bq.appendChild(n.cloneNode(true));
       
 13144 					n = n.nextSibling;
       
 13145 				}
       
 13146 
       
 13147 				dom.remove(e);
       
 13148 				return;
       
 13149 			}
       
 13150 
       
 13151 			// Add non BQ element to BQ
       
 13152 			bq.appendChild(dom.remove(e));
       
 13153 		});
       
 13154 
       
 13155 		if (!bm) {
       
 13156 			// Move caret inside empty block element
       
 13157 			if (!tinymce.isIE) {
       
 13158 				r = ed.getDoc().createRange();
       
 13159 				r.setStart(sb, 0);
       
 13160 				r.setEnd(sb, 0);
       
 13161 				s.setRng(r);
       
 13162 			} else {
       
 13163 				s.select(sb);
       
 13164 				s.collapse(1);
       
 13165 			}
       
 13166 		} else
       
 13167 			s.moveToBookmark(bm);
       
 13168 	});
       
 13169 })(tinymce);
       
 13170 (function(tinymce) {
       
 13171 	tinymce.each(['Cut', 'Copy', 'Paste'], function(cmd) {
       
 13172 		tinymce.GlobalCommands.add(cmd, function() {
       
 13173 			var ed = this, doc = ed.getDoc();
       
 13174 
       
 13175 			try {
       
 13176 				doc.execCommand(cmd, false, null);
       
 13177 
       
 13178 				// On WebKit the command will just be ignored if it's not enabled
       
 13179 				if (!doc.queryCommandEnabled(cmd))
       
 13180 					throw 'Error';
       
 13181 			} catch (ex) {
       
 13182 				if (tinymce.isGecko) {
       
 13183 					ed.windowManager.confirm(ed.getLang('clipboard_msg'), function(s) {
       
 13184 						if (s)
       
 13185 							open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', '_blank');
       
 13186 					});
       
 13187 				} else
       
 13188 					ed.windowManager.alert(ed.getLang('clipboard_no_support'));
       
 13189 			}
       
 13190 		});
       
 13191 	});
       
 13192 })(tinymce);
       
 13193 (function(tinymce) {
       
 13194 	tinymce.GlobalCommands.add('InsertHorizontalRule', function() {
       
 13195 		if (tinymce.isOpera)
       
 13196 			return this.getDoc().execCommand('InsertHorizontalRule', false, '');
       
 13197 
       
 13198 		this.selection.setContent('<hr />');
       
 13199 	});
       
 13200 })(tinymce);
       
 13201 (function() {
       
 13202 	var cmds = tinymce.GlobalCommands;
       
 13203 
       
 13204 	cmds.add(['mceEndUndoLevel', 'mceAddUndoLevel'], function() {
       
 13205 		this.undoManager.add();
       
 13206 	});
       
 13207 
       
 13208 	cmds.add('Undo', function() {
       
 13209 		var ed = this;
       
 13210 
       
 13211 		if (ed.settings.custom_undo_redo) {
       
 13212 			ed.undoManager.undo();
       
 13213 			ed.nodeChanged();
       
 13214 			return true;
       
 13215 		}
       
 13216 
       
 13217 		return false; // Run browser command
       
 13218 	});
       
 13219 
       
 13220 	cmds.add('Redo', function() {
       
 13221 		var ed = this;
       
 13222 
       
 13223 		if (ed.settings.custom_undo_redo) {
       
 13224 			ed.undoManager.redo();
       
 13225 			ed.nodeChanged();
       
 13226 			return true;
       
 13227 		}
       
 13228 
       
 13229 		return false; // Run browser command
       
 13230 	});
       
 13231 })();