alecpl
2008-07-01 e6e5c60aae745a580a2d7fca1e2b7104c3907352
commit | author | age
d9344f 1
S 2 /* file:jscripts/tiny_mce/classes/tinymce.js */
3
4 var tinymce = {
5     majorVersion : '3',
6     minorVersion : '0.6.2',
7     releaseDate : '2008-04-07',
8
9     _init : function() {
10         var t = this, ua = navigator.userAgent, i, nl, n, base;
11
12         // Browser checks
13         t.isOpera = window.opera && opera.buildNumber;
14         t.isWebKit = /WebKit/.test(ua);
15         t.isOldWebKit = t.isWebKit && !window.getSelection().getRangeAt;
16         t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(navigator.appName);
17         t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
18         t.isGecko = !t.isWebKit && /Gecko/.test(ua);
19         t.isMac = ua.indexOf('Mac') != -1;
20
21         // TinyMCE .NET webcontrol might be setting the values for TinyMCE
22         if (window.tinyMCEPreInit) {
23             t.suffix = tinyMCEPreInit.suffix;
24             t.baseURL = tinyMCEPreInit.base;
25             return;
26         }
27
28         // Get suffix and base
29         t.suffix = '';
30
31         // If base element found, add that infront of baseURL
32         nl = document.getElementsByTagName('base');
33         for (i=0; i<nl.length; i++) {
34             if (nl[i].href)
35                 base = nl[i].href;
36         }
37
38         function getBase(n) {
39             if (n.src && /tiny_mce(|_dev|_src|_gzip|_jquery|_prototype).js/.test(n.src)) {
40                 if (/_(src|dev)\.js/g.test(n.src))
41                     t.suffix = '_src';
42
43                 t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
44
45                 // If path to script is relative and a base href was found add that one infront
46                 if (base && t.baseURL.indexOf('://') == -1)
47                     t.baseURL = base + t.baseURL;
48
49                 return t.baseURL;
50             }
51
52             return null;
53         };
54
55         // Check document
56         nl = document.getElementsByTagName('script');
57         for (i=0; i<nl.length; i++) {
58             if (getBase(nl[i]))
59                 return;
60         }
61
62         // Check head
63         n = document.getElementsByTagName('head')[0];
64         if (n) {
65             nl = n.getElementsByTagName('script');
66             for (i=0; i<nl.length; i++) {
67                 if (getBase(nl[i]))
68                     return;
69             }
70         }
71
72         return;
73     },
74
75     is : function(o, t) {
76         var n = typeof(o);
77
78         if (!t)
79             return n != 'undefined';
80
81         if (t == 'array' && (o instanceof Array))
82             return true;
83
84         return n == t;
85     },
86
87     // #if !jquery
88
89     each : function(o, cb, s) {
90         var n, l;
91
92         if (!o)
93             return 0;
94
95         s = s || o;
96
97         if (typeof(o.length) != 'undefined') {
98             // Indexed arrays, needed for Safari
99             for (n=0, l = o.length; n<l; n++) {
100                 if (cb.call(s, o[n], n, o) === false)
101                     return 0;
102             }
103         } else {
104             // Hashtables
105             for (n in o) {
106                 if (o.hasOwnProperty(n)) {
107                     if (cb.call(s, o[n], n, o) === false)
108                         return 0;
109                 }
110             }
111         }
112
113         return 1;
114     },
115
116     map : function(a, f) {
117         var o = [];
118
119         tinymce.each(a, function(v) {
120             o.push(f(v));
121         });
122
123         return o;
124     },
125
126     grep : function(a, f) {
127         var o = [];
128
129         tinymce.each(a, function(v) {
130             if (!f || f(v))
131                 o.push(v);
132         });
133
134         return o;
135     },
136
137     inArray : function(a, v) {
138         var i, l;
139
140         if (a) {
141             for (i = 0, l = a.length; i < l; i++) {
142                 if (a[i] === v)
143                     return i;
144             }
145         }
146
147         return -1;
148     },
149
150     extend : function(o, e) {
151         var i, a = arguments;
152
153         for (i=1; i<a.length; i++) {
154             e = a[i];
155
156             tinymce.each(e, function(v, n) {
157                 if (typeof(v) !== 'undefined')
158                     o[n] = v;
159             });
160         }
161
162         return o;
163     },
164
165     trim : function(s) {
166         return (s ? '' + s : '').replace(/^\s*|\s*$/g, '');
167     },
168
169     // #endif
170
171     create : function(s, p) {
172         var t = this, sp, ns, cn, scn, c, de = 0;
173
174         // Parse : <prefix> <class>:<super class>
175         s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
176         cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
177
178         // Create namespace for new class
179         ns = t.createNS(s[3].replace(/\.\w+$/, ''));
180
181         // Class already exists
182         if (ns[cn])
183             return;
184
185         // Make pure static class
186         if (s[2] == 'static') {
187             ns[cn] = p;
188
189             if (this.onCreate)
190                 this.onCreate(s[2], s[3], ns[cn]);
191
192             return;
193         }
194
195         // Create default constructor
196         if (!p[cn]) {
197             p[cn] = function() {};
198             de = 1;
199         }
200
201         // Add constructor and methods
202         ns[cn] = p[cn];
203         t.extend(ns[cn].prototype, p);
204
205         // Extend
206         if (s[5]) {
207             sp = t.resolve(s[5]).prototype;
208             scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
209
210             // Extend constructor
211             c = ns[cn];
212             if (de) {
213                 // Add passthrough constructor
214                 ns[cn] = function() {
215                     return sp[scn].apply(this, arguments);
216                 };
217             } else {
218                 // Add inherit constructor
219                 ns[cn] = function() {
220                     this.parent = sp[scn];
221                     return c.apply(this, arguments);
222                 };
223             }
224             ns[cn].prototype[cn] = ns[cn];
225
226             // Add super methods
227             t.each(sp, function(f, n) {
228                 ns[cn].prototype[n] = sp[n];
229             });
230
231             // Add overridden methods
232             t.each(p, function(f, n) {
233                 // Extend methods if needed
234                 if (sp[n]) {
235                     ns[cn].prototype[n] = function() {
236                         this.parent = sp[n];
237                         return f.apply(this, arguments);
238                     };
239                 } else {
240                     if (n != cn)
241                         ns[cn].prototype[n] = f;
242                 }
243             });
244         }
245
246         // Add static methods
247         t.each(p['static'], function(f, n) {
248             ns[cn][n] = f;
249         });
250
251         if (this.onCreate)
252             this.onCreate(s[2], s[3], ns[cn].prototype);
253     },
254
255     walk : function(o, f, n, s) {
256         s = s || this;
257
258         if (o) {
259             if (n)
260                 o = o[n];
261
262             tinymce.each(o, function(o, i) {
263                 if (f.call(s, o, i, n) === false)
264                     return false;
265
266                 tinymce.walk(o, f, n, s);
267             });
268         }
269     },
270
271     createNS : function(n, o) {
272         var i, v;
273
274         o = o || window;
275
276         n = n.split('.');
277         for (i=0; i<n.length; i++) {
278             v = n[i];
279
280             if (!o[v])
281                 o[v] = {};
282
283             o = o[v];
284         }
285
286         return o;
287     },
288
289     resolve : function(n, o) {
290         var i, l;
291
292         o = o || window;
293
294         n = n.split('.');
295         for (i=0, l = n.length; i<l; i++) {
296             o = o[n[i]];
297
298             if (!o)
299                 break;
300         }
301
302         return o;
303     },
304
305     addUnload : function(f, s) {
306         var t = this, w = window, unload;
307
308         f = {func : f, scope : s || this};
309
310         if (!t.unloads) {
311             unload = function() {
312                 var li = t.unloads, o, n;
313
314                 // Call unload handlers
315                 for (n in li) {
316                     o = li[n];
317
318                     if (o && o.func)
319                         o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
320                 }
321
322                 // Detach unload function
323                 if (w.detachEvent)
324                     w.detachEvent('onunload', unload);
325                 else if (w.removeEventListener)
326                     w.removeEventListener('unload', unload, false);
327
328                 // Destroy references
329                 o = li = w = unload = null;
330
331                 // Run garbarge collector on IE
332                 if (window.CollectGarbage)
333                     window.CollectGarbage();
334             };
335
336             // Attach unload handler
337             if (w.attachEvent)
338                 w.attachEvent('onunload', unload);
339             else if (w.addEventListener)
340                 w.addEventListener('unload', unload, false);
341
342             // Setup initial unload handler array
343             t.unloads = [f];
344         } else
345             t.unloads.push(f);
346
347         return f;
348     },
349
350     removeUnload : function(f) {
351         var u = this.unloads, r = null;
352
353         tinymce.each(u, function(o, i) {
354             if (o && o.func == f) {
355                 u.splice(i, 1);
356                 r = f;
357                 return false;
358             }
359         });
360
361         return r;
362     },
363
364     explode : function(s, d) {
365         return tinymce.map(s.split(d || ','), tinymce.trim);
366     }
367
368     };
369
370 // Required for GZip AJAX loading
371 window.tinymce = tinymce;
372
373 // Initialize the API
374 tinymce._init();
375
376 /* file:jscripts/tiny_mce/classes/adapter/jquery/adapter.js */
377
378
379 /* file:jscripts/tiny_mce/classes/adapter/prototype/adapter.js */
380
381
382 /* file:jscripts/tiny_mce/classes/util/Dispatcher.js */
383
384 tinymce.create('tinymce.util.Dispatcher', {
385     scope : null,
386     listeners : null,
387
388     Dispatcher : function(s) {
389         this.scope = s || this;
390         this.listeners = [];
391     },
392
393     add : function(cb, s) {
394         this.listeners.push({cb : cb, scope : s || this.scope});
395
396         return cb;
397     },
398
399     addToTop : function(cb, s) {
400         this.listeners.unshift({cb : cb, scope : s || this.scope});
401
402         return cb;
403     },
404
405     remove : function(cb) {
406         var l = this.listeners, o = null;
407
408         tinymce.each(l, function(c, i) {
409             if (cb == c.cb) {
410                 o = cb;
411                 l.splice(i, 1);
412                 return false;
413             }
414         });
415
416         return o;
417     },
418
419     dispatch : function() {
420         var s, a = arguments, i, li = this.listeners, c;
421
422         // Needs to be a real loop since the listener count might change while looping
423         // And this is also more efficient
424         for (i = 0; i<li.length; i++) {
425             c = li[i];
426             s = c.cb.apply(c.scope, a);
427
428             if (s === false)
429                 break;
430         }
431
432         return s;
433     }
434
435     });
436
437 /* file:jscripts/tiny_mce/classes/util/URI.js */
438
439 (function() {
440     var each = tinymce.each;
441
442     tinymce.create('tinymce.util.URI', {
443         URI : function(u, s) {
444             var t = this, o, a, b;
445
446             // Default settings
447             s = t.settings = s || {};
448
449             // Strange app protocol or local anchor
450             if (/^(mailto|news|javascript|about):/i.test(u) || /^\s*#/.test(u)) {
451                 t.source = u;
452                 return;
453             }
454
455             // Absolute path with no host, fake host and protocol
456             if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
457                 u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
458
459             // Relative path
460             if (u.indexOf('://') === -1 && u.indexOf('//') !== 0)
461                 u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);
462
463             // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
464             u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
465             u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
466             each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
467                 var s = u[i];
468
469                 // Zope 3 workaround, they use @@something
470                 if (s)
471                     s = s.replace(/\(mce_at\)/g, '@@');
472
473                 t[v] = s;
474             });
475
476             if (b = s.base_uri) {
477                 if (!t.protocol)
478                     t.protocol = b.protocol;
479
480                 if (!t.userInfo)
481                     t.userInfo = b.userInfo;
482
483                 if (!t.port && t.host == 'mce_host')
484                     t.port = b.port;
485
486                 if (!t.host || t.host == 'mce_host')
487                     t.host = b.host;
488
489                 t.source = '';
490             }
491
492             //t.path = t.path || '/';
493         },
494
495         setPath : function(p) {
496             var t = this;
497
498             p = /^(.*?)\/?(\w+)?$/.exec(p);
499
500             // Update path parts
501             t.path = p[0];
502             t.directory = p[1];
503             t.file = p[2];
504
505             // Rebuild source
506             t.source = '';
507             t.getURI();
508         },
509
510         toRelative : function(u) {
511             var t = this, o;
512
513             u = new tinymce.util.URI(u, {base_uri : t});
514
515             // Not on same domain/port or protocol
516             if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
517                 return u.getURI();
518
519             o = t.toRelPath(t.path, u.path);
520
521             // Add query
522             if (u.query)
523                 o += '?' + u.query;
524
525             // Add anchor
526             if (u.anchor)
527                 o += '#' + u.anchor;
528
529             return o;
530         },
531     
532         toAbsolute : function(u, nh) {
533             var u = new tinymce.util.URI(u, {base_uri : this});
534
535             return u.getURI(this.host == u.host ? nh : 0);
536         },
537
538         toRelPath : function(base, path) {
539             var items, bp = 0, out = '', i;
540
541             // Split the paths
542             base = base.substring(0, base.lastIndexOf('/'));
543             base = base.split('/');
544             items = path.split('/');
545
546             if (base.length >= items.length) {
547                 for (i = 0; i < base.length; i++) {
548                     if (i >= items.length || base[i] != items[i]) {
549                         bp = i + 1;
550                         break;
551                     }
552                 }
553             }
554
555             if (base.length < items.length) {
556                 for (i = 0; i < items.length; i++) {
557                     if (i >= base.length || base[i] != items[i]) {
558                         bp = i + 1;
559                         break;
560                     }
561                 }
562             }
563
564             if (bp == 1)
565                 return path;
566
567             for (i = 0; i < base.length - (bp - 1); i++)
568                 out += "../";
569
570             for (i = bp - 1; i < items.length; i++) {
571                 if (i != bp - 1)
572                     out += "/" + items[i];
573                 else
574                     out += items[i];
575             }
576
577             return out;
578         },
579
580         toAbsPath : function(base, path) {
581             var i, nb = 0, o = [];
582
583             // Split paths
584             base = base.split('/');
585             path = path.split('/');
586
587             // Remove empty chunks
588             each(base, function(k) {
589                 if (k)
590                     o.push(k);
591             });
592
593             base = o;
594
595             // Merge relURLParts chunks
596             for (i = path.length - 1, o = []; i >= 0; i--) {
597                 // Ignore empty or .
598                 if (path[i].length == 0 || path[i] == ".")
599                     continue;
600
601                 // Is parent
602                 if (path[i] == '..') {
603                     nb++;
604                     continue;
605                 }
606
607                 // Move up
608                 if (nb > 0) {
609                     nb--;
610                     continue;
611                 }
612
613                 o.push(path[i]);
614             }
615
616             i = base.length - nb;
617
618             // If /a/b/c or /
619             if (i <= 0)
620                 return '/' + o.reverse().join('/');
621
622             return '/' + base.slice(0, i).join('/') + '/' + o.reverse().join('/');
623         },
624
625         getURI : function(nh) {
626             var s, t = this;
627
628             // Rebuild source
629             if (!t.source || nh) {
630                 s = '';
631
632                 if (!nh) {
633                     if (t.protocol)
634                         s += t.protocol + '://';
635
636                     if (t.userInfo)
637                         s += t.userInfo + '@';
638
639                     if (t.host)
640                         s += t.host;
641
642                     if (t.port)
643                         s += ':' + t.port;
644                 }
645
646                 if (t.path)
647                     s += t.path;
648
649                 if (t.query)
650                     s += '?' + t.query;
651
652                 if (t.anchor)
653                     s += '#' + t.anchor;
654
655                 t.source = s;
656             }
657
658             return t.source;
659         }
660
661         });
662 })();
663
664 /* file:jscripts/tiny_mce/classes/util/Cookie.js */
665
666 (function() {
667     var each = tinymce.each;
668
669     tinymce.create('static tinymce.util.Cookie', {
670         getHash : function(n) {
671             var v = this.get(n), h;
672
673             if (v) {
674                 each(v.split('&'), function(v) {
675                     v = v.split('=');
676                     h = h || {};
677                     h[unescape(v[0])] = unescape(v[1]);
678                 });
679             }
680
681             return h;
682         },
683
684         setHash : function(n, v, e, p, d, s) {
685             var o = '';
686
687             each(v, function(v, k) {
688                 o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
689             });
690
691             this.set(n, o, e, p, d, s);
692         },
693
694         get : function(n) {
695             var c = document.cookie, e, p = n + "=", b;
696
697             // Strict mode
698             if (!c)
699                 return;
700
701             b = c.indexOf("; " + p);
702
703             if (b == -1) {
704                 b = c.indexOf(p);
705
706                 if (b != 0)
707                     return null;
708             } else
709                 b += 2;
710
711             e = c.indexOf(";", b);
712
713             if (e == -1)
714                 e = c.length;
715
716             return unescape(c.substring(b + p.length, e));
717         },
718
719         set : function(n, v, e, p, d, s) {
720             document.cookie = n + "=" + escape(v) +
721                 ((e) ? "; expires=" + e.toGMTString() : "") +
722                 ((p) ? "; path=" + escape(p) : "") +
723                 ((d) ? "; domain=" + d : "") +
724                 ((s) ? "; secure" : "");
725         },
726
727         remove : function(n, p) {
728             var d = new Date();
729
730             d.setTime(d.getTime() - 1000);
731
732             this.set(n, '', d, p, d);
733         }
734
735         });
736 })();
737
738 /* file:jscripts/tiny_mce/classes/util/JSON.js */
739
740 tinymce.create('static tinymce.util.JSON', {
741     serialize : function(o) {
742         var i, v, s = tinymce.util.JSON.serialize, t;
743
744         if (o == null)
745             return 'null';
746
747         t = typeof o;
748
749         if (t == 'string') {
750             v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
751
752             return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'])/g, function(a, b) {
753                 i = v.indexOf(b);
754
755                 if (i + 1)
756                     return '\\' + v.charAt(i + 1);
757
758                 a = b.charCodeAt().toString(16);
759
760                 return '\\u' + '0000'.substring(a.length) + a;
761             }) + '"';
762         }
763
764         if (t == 'object') {
765             if (o instanceof Array) {
766                     for (i=0, v = '['; i<o.length; i++)
767                         v += (i > 0 ? ',' : '') + s(o[i]);
768
769                     return v + ']';
770                 }
771
772                 v = '{';
773
774                 for (i in o)
775                     v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';
776
777                 return v + '}';
778         }
779
780         return '' + o;
781     },
782
783     parse : function(s) {
784         try {
785             return eval('(' + s + ')');
786         } catch (ex) {
787             // Ignore
788         }
789     }
790
791     });
792
793 /* file:jscripts/tiny_mce/classes/util/XHR.js */
794
795 tinymce.create('static tinymce.util.XHR', {
796     send : function(o) {
797         var x, t, w = window, c = 0;
798
799         // Default settings
800         o.scope = o.scope || this;
801         o.success_scope = o.success_scope || o.scope;
802         o.error_scope = o.error_scope || o.scope;
803         o.async = o.async === false ? false : true;
804         o.data = o.data || '';
805
806         function get(s) {
807             x = 0;
808
809             try {
810                 x = new ActiveXObject(s);
811             } catch (ex) {
812             }
813
814             return x;
815         };
816
817         x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
818
819         if (x) {
820             if (x.overrideMimeType)
821                 x.overrideMimeType(o.content_type);
822
823             x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
824
825             if (o.content_type)
826                 x.setRequestHeader('Content-Type', o.content_type);
827
828             x.send(o.data);
829
830             // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
831             t = w.setInterval(function() {
832                 if (x.readyState == 4 || c++ > 10000) {
833                     w.clearInterval(t);
834
835                     if (o.success && c < 10000 && x.status == 200)
836                         o.success.call(o.success_scope, '' + x.responseText, x, o);
837                     else if (o.error)
838                         o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
839
840                     x = null;
841                 }
842             }, 10);
843         }
844
845         }
846 });
847
848 /* file:jscripts/tiny_mce/classes/util/JSONRequest.js */
849
850 (function() {
851     var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
852
853     tinymce.create('tinymce.util.JSONRequest', {
854         JSONRequest : function(s) {
855             this.settings = extend({
856             }, s);
857             this.count = 0;
858         },
859
860         send : function(o) {
861             var ecb = o.error, scb = o.success;
862
863             o = extend(this.settings, o);
864
865             o.success = function(c, x) {
866                 c = JSON.parse(c);
867
868                 if (typeof(c) == 'undefined') {
869                     c = {
870                         error : 'JSON Parse error.'
871                     };
872                 }
873
874                 if (c.error)
875                     ecb.call(o.error_scope || o.scope, c.error, x);
876                 else
877                     scb.call(o.success_scope || o.scope, c.result);
878             };
879
880             o.error = function(ty, x) {
881                 ecb.call(o.error_scope || o.scope, ty, x);
882             };
883
884             o.data = JSON.serialize({
885                 id : o.id || 'c' + (this.count++),
886                 method : o.method,
887                 params : o.params
888             });
889
890             // JSON content type for Ruby on rails. Bug: #1883287
891             o.content_type = 'application/json';
892
893             XHR.send(o);
894         },
895
896         'static' : {
897             sendRPC : function(o) {
898                 return new tinymce.util.JSONRequest().send(o);
899             }
900         }
901
902         });
903 }());
904 /* file:jscripts/tiny_mce/classes/dom/DOMUtils.js */
905
906 (function() {
907     // Shorten names
908     var each = tinymce.each, is = tinymce.is;
909     var isWebKit = tinymce.isWebKit, isIE = tinymce.isIE;
910
911     tinymce.create('tinymce.dom.DOMUtils', {
912         doc : null,
913         root : null,
914         files : null,
915         listeners : {},
916         pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,
917         cache : {},
918         idPattern : /^#[\w]+$/,
919         elmPattern : /^[\w_*]+$/,
920         elmClassPattern : /^([\w_]*)\.([\w_]+)$/,
921
922         DOMUtils : function(d, s) {
923             var t = this;
924
925             t.doc = d;
926             t.win = window;
927             t.files = {};
928             t.cssFlicker = false;
929             t.counter = 0;
930             t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat"; 
931             t.stdMode = d.documentMode === 8;
932
933             this.settings = s = tinymce.extend({
934                 keep_values : false,
935                 hex_colors : 1,
936                 process_html : 1
937             }, s);
938
939             // Fix IE6SP2 flicker and check it failed for pre SP2
940             if (tinymce.isIE6) {
941                 try {
942                     d.execCommand('BackgroundImageCache', false, true);
943                 } catch (e) {
944                     t.cssFlicker = true;
945                 }
946             }
947
948             tinymce.addUnload(t.destroy, t);
949         },
950
951         getRoot : function() {
952             var t = this, s = t.settings;
953
954             return (s && t.get(s.root_element)) || t.doc.body;
955         },
956
957         getViewPort : function(w) {
958             var d, b;
959
960             w = !w ? this.win : w;
961             d = w.document;
962             b = this.boxModel ? d.documentElement : d.body;
963
964             // Returns viewport size excluding scrollbars
965             return {
966                 x : w.pageXOffset || b.scrollLeft,
967                 y : w.pageYOffset || b.scrollTop,
968                 w : w.innerWidth || b.clientWidth,
969                 h : w.innerHeight || b.clientHeight
970             };
971         },
972
973         getRect : function(e) {
974             var p, t = this, w, h;
975
976             e = t.get(e);
977             p = t.getPos(e);
978             w = t.getStyle(e, 'width');
979             h = t.getStyle(e, 'height');
980
981             // Non pixel value, then force offset/clientWidth
982             if (w.indexOf('px') === -1)
983                 w = 0;
984
985             // Non pixel value, then force offset/clientWidth
986             if (h.indexOf('px') === -1)
987                 h = 0;
988
989             return {
990                 x : p.x,
991                 y : p.y,
992                 w : parseInt(w) || e.offsetWidth || e.clientWidth,
993                 h : parseInt(h) || e.offsetHeight || e.clientHeight
994             };
995         },
996
997         getParent : function(n, f, r) {
998             var na, se = this.settings;
999
1000             n = this.get(n);
1001
1002             if (se.strict_root)
1003                 r = r || this.getRoot();
1004
1005             // Wrap node name as func
1006             if (is(f, 'string')) {
1007                 na = f.toUpperCase();
1008
1009                 f = function(n) {
1010                     var s = false;
1011
1012                     // Any element
1013                     if (n.nodeType == 1 && na === '*') {
1014                         s = true;
1015                         return false;
1016                     }
1017
1018                     each(na.split(','), function(v) {
1019                         if (n.nodeType == 1 && ((se.strict && n.nodeName.toUpperCase() == v) || n.nodeName == v)) {
1020                             s = true;
1021                             return false; // Break loop
1022                         }
1023                     });
1024
1025                     return s;
1026                 };
1027             }
1028
1029             while (n) {
1030                 if (n == r)
1031                     return null;
1032
1033                 if (f(n))
1034                     return n;
1035
1036                 n = n.parentNode;
1037             }
1038
1039             return null;
1040         },
1041
1042         get : function(e) {
1043             var n;
1044
1045             if (this.doc && typeof(e) == 'string') {
1046                 n = e;
1047                 e = this.doc.getElementById(e);
1048
1049                 // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
1050                 if (e && e.id !== n)
1051                     return this.doc.getElementsByName(n)[1];
1052             }
1053
1054             return e;
1055         },
1056
1057         // #if !jquery
1058
1059         select : function(pa, s) {
1060             var t = this, cs, c, pl, o = [], x, i, l, n;
1061
1062             s = t.get(s) || t.doc;
1063
1064             // Look for native support and use that if it's found
1065             if (s.querySelectorAll) {
1066                 // Element scope then use temp id
1067                 // We need to do this to be compatible with other implementations
1068                 // See bug report: http://bugs.webkit.org/show_bug.cgi?id=17461
1069                 if (s != t.doc) {
1070                     i = s.id;
1071                     s.id = '_mc_tmp';
1072                     pa = '#_mc_tmp ' + pa;
1073                 }
1074
1075                 // Select elements
1076                 l = tinymce.grep(s.querySelectorAll(pa));
1077
1078                 // Restore old id
1079                 s.id = i;
1080
1081                 return l;
1082             }
1083
1084             if (t.settings.strict) {
1085                 function get(s, n) {
1086                     return s.getElementsByTagName(n.toLowerCase());
1087                 };
1088             } else {
1089                 function get(s, n) {
1090                     return s.getElementsByTagName(n);
1091                 };
1092             }
1093
1094             // Simple element pattern. For example: "p" or "*"
1095             if (t.elmPattern.test(pa)) {
1096                 x = get(s, pa);
1097
1098                 for (i = 0, l = x.length; i<l; i++)
1099                     o.push(x[i]);
1100
1101                 return o;
1102             }
1103
1104             // Simple class pattern. For example: "p.class" or ".class"
1105             if (t.elmClassPattern.test(pa)) {
1106                 pl = t.elmClassPattern.exec(pa);
1107                 x = get(s, pl[1] || '*');
1108                 c = ' ' + pl[2] + ' ';
1109
1110                 for (i = 0, l = x.length; i<l; i++) {
1111                     n = x[i];
1112
1113                     if (n.className && (' ' + n.className + ' ').indexOf(c) !== -1)
1114                         o.push(n);
1115                 }
1116
1117                 return o;
1118             }
1119
1120             function collect(n) {
1121                 if (!n.mce_save) {
1122                     n.mce_save = 1;
1123                     o.push(n);
1124                 }
1125             };
1126
1127             function collectIE(n) {
1128                 if (!n.getAttribute('mce_save')) {
1129                     n.setAttribute('mce_save', '1');
1130                     o.push(n);
1131                 }
1132             };
1133
1134             function find(n, f, r) {
1135                 var i, l, nl = get(r, n);
1136
1137                 for (i = 0, l = nl.length; i < l; i++)
1138                     f(nl[i]);
1139             };
1140
1141             each(pa.split(','), function(v, i) {
1142                 v = tinymce.trim(v);
1143
1144                 // Simple element pattern, most common in TinyMCE
1145                 if (t.elmPattern.test(v)) {
1146                     each(get(s, v), function(n) {
1147                         collect(n);
1148                     });
1149
1150                     return;
1151                 }
1152
1153                 // Simple element pattern with class, fairly common in TinyMCE
1154                 if (t.elmClassPattern.test(v)) {
1155                     x = t.elmClassPattern.exec(v);
1156
1157                     each(get(s, x[1]), function(n) {
1158                         if (t.hasClass(n, x[2]))
1159                             collect(n);
1160                     });
1161
1162                     return;
1163                 }
1164
1165                 if (!(cs = t.cache[pa])) {
1166                     cs = 'x=(function(cf, s) {';
1167                     pl = v.split(' ');
1168
1169                     each(pl, function(v) {
1170                         var p = /^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@([\w\\]+)([\^\$\*!]?=)([\w\\]+)\])?(?:\:([\w\\]+))?/i.exec(v);
1171
1172                         // Find elements
1173                         p[1] = p[1] || '*';
1174                         cs += 'find("' + p[1] + '", function(n) {';
1175
1176                         // Check id
1177                         if (p[2])
1178                             cs += 'if (n.id !== "' + p[2] + '") return;';
1179
1180                         // Check classes
1181                         if (p[3]) {
1182                             cs += 'var c = " " + n.className + " ";';
1183                             cs += 'if (';
1184                             c = '';
1185                             each(p[3].split('.'), function(v) {
1186                                 if (v)
1187                                     c += (c ? '||' : '') + 'c.indexOf(" ' + v + ' ") === -1';
1188                             });
1189                             cs += c + ') return;';
1190                         }
1191                     });
1192
1193                     cs += 'cf(n);';
1194
1195                     for (i = pl.length - 1; i >= 0; i--)
1196                         cs += '}, ' + (i ? 'n' : 's') + ');';
1197
1198                     cs += '})';
1199
1200                     // Compile CSS pattern function
1201                     t.cache[pa] = cs = eval(cs);
1202                 }
1203
1204                 // Run selector function
1205                 cs(isIE ? collectIE : collect, s);
1206             });
1207
1208             // Cleanup
1209             each(o, function(n) {
1210                 if (isIE)
1211                     n.removeAttribute('mce_save');
1212                 else
1213                     delete n.mce_save;
1214             });
1215
1216             return o;
1217         },
1218
1219         // #endif
1220
1221         add : function(p, n, a, h, c) {
1222             var t = this;
1223
1224             return this.run(p, function(p) {
1225                 var e, k;
1226
1227                 e = is(n, 'string') ? t.doc.createElement(n) : n;
1228
1229                 if (a) {
1230                     for (k in a) {
1231                         if (a.hasOwnProperty(k) && !is(a[k], 'object'))
1232                             t.setAttrib(e, k, '' + a[k]);
1233                     }
1234
1235                     if (a.style && !is(a.style, 'string')) {
1236                         each(a.style, function(v, n) {
1237                             t.setStyle(e, n, v);
1238                         });
1239                     }
1240                 }
1241
1242                 if (h) {
1243                     if (h.nodeType)
1244                         e.appendChild(h);
1245                     else
1246                         t.setHTML(e, h);
1247                 }
1248
1249                 return !c ? p.appendChild(e) : e;
1250             });
1251         },
1252
1253         create : function(n, a, h) {
1254             return this.add(this.doc.createElement(n), n, a, h, 1);
1255         },
1256
1257         createHTML : function(n, a, h) {
1258             var o = '', t = this, k;
1259
1260             o += '<' + n;
1261
1262             for (k in a) {
1263                 if (a.hasOwnProperty(k))
1264                     o += ' ' + k + '="' + t.encode(a[k]) + '"';
1265             }
1266
1267             if (tinymce.is(h))
1268                 return o + '>' + h + '</' + n + '>';
1269
1270             return o + ' />';
1271         },
1272
1273         remove : function(n, k) {
1274             return this.run(n, function(n) {
1275                 var p, g;
1276
1277                 p = n.parentNode;
1278
1279                 if (!p)
1280                     return null;
1281
1282                 if (k) {
1283                     each (n.childNodes, function(c) {
1284                         p.insertBefore(c.cloneNode(true), n);
1285                     });
1286                 }
1287
1288                 // Fix IE psuedo leak
1289         /*        if (isIE) {
1290                     p = n.cloneNode(true);
1291                     n.outerHTML = '';
1292
1293                     return p;
1294                 }*/
1295
1296                 return p.removeChild(n);
1297             });
1298         },
1299
1300         // #if !jquery
1301
1302         setStyle : function(n, na, v) {
1303             var t = this;
1304
1305             return t.run(n, function(e) {
1306                 var s, i;
1307
1308                 s = e.style;
1309
1310                 // Camelcase it, if needed
1311                 na = na.replace(/-(\D)/g, function(a, b){
1312                     return b.toUpperCase();
1313                 });
1314
1315                 // Default px suffix on these
1316                 if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))
1317                     v += 'px';
1318
1319                 switch (na) {
1320                     case 'opacity':
1321                         // IE specific opacity
1322                         if (isIE) {
1323                             s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
1324
1325                             if (!n.currentStyle || !n.currentStyle.hasLayout)
1326                                 s.display = 'inline-block';
1327                         }
1328
1329                         // Fix for older browsers
1330                         s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';
1331                         break;
1332
1333                     case 'float':
1334                         isIE ? s.styleFloat = v : s.cssFloat = v;
1335                         break;
1336                     
1337                     default:
1338                         s[na] = v || '';
1339                 }
1340
1341                 // Force update of the style data
1342                 if (t.settings.update_styles)
1343                     t.setAttrib(e, 'mce_style');
1344             });
1345         },
1346
1347         getStyle : function(n, na, c) {
1348             n = this.get(n);
1349
1350             if (!n)
1351                 return false;
1352
1353             // Gecko
1354             if (this.doc.defaultView && c) {
1355                 // Remove camelcase
1356                 na = na.replace(/[A-Z]/g, function(a){
1357                     return '-' + a;
1358                 });
1359
1360                 try {
1361                     return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);
1362                 } catch (ex) {
1363                     // Old safari might fail
1364                     return null;
1365                 }
1366             }
1367
1368             // Camelcase it, if needed
1369             na = na.replace(/-(\D)/g, function(a, b){
1370                 return b.toUpperCase();
1371             });
1372
1373             if (na == 'float')
1374                 na = isIE ? 'styleFloat' : 'cssFloat';
1375
1376             // IE & Opera
1377             if (n.currentStyle && c)
1378                 return n.currentStyle[na];
1379
1380             return n.style[na];
1381         },
1382
1383         setStyles : function(e, o) {
1384             var t = this, s = t.settings, ol;
1385
1386             ol = s.update_styles;
1387             s.update_styles = 0;
1388
1389             each(o, function(v, n) {
1390                 t.setStyle(e, n, v);
1391             });
1392
1393             // Update style info
1394             s.update_styles = ol;
1395             if (s.update_styles)
1396                 t.setAttrib(e, s.cssText);
1397         },
1398
1399         setAttrib : function(e, n, v) {
1400             var t = this;
1401
1402             // Strict XML mode
1403             if (t.settings.strict)
1404                 n = n.toLowerCase();
1405
1406             return this.run(e, function(e) {
1407                 var s = t.settings;
1408
1409                 switch (n) {
1410                     case "style":
1411                         if (s.keep_values) {
1412                             if (v)
1413                                 e.setAttribute('mce_style', v, 2);
1414                             else
1415                                 e.removeAttribute('mce_style', 2);
1416                         }
1417
1418                         e.style.cssText = v;
1419                         break;
1420
1421                     case "class":
1422                         e.className = v || ''; // Fix IE null bug
1423                         break;
1424
1425                     case "src":
1426                     case "href":
1427                         if (s.keep_values) {
1428                             if (s.url_converter)
1429                                 v = s.url_converter.call(s.url_converter_scope || t, v, n, e);
1430
1431                             t.setAttrib(e, 'mce_' + n, v, 2);
1432                         }
1433
1434                         break;
1435                 }
1436
1437                 if (is(v) && v !== null && v.length !== 0)
1438                     e.setAttribute(n, '' + v, 2);
1439                 else
1440                     e.removeAttribute(n, 2);
1441             });
1442         },
1443
1444         setAttribs : function(e, o) {
1445             var t = this;
1446
1447             return this.run(e, function(e) {
1448                 each(o, function(v, n) {
1449                     t.setAttrib(e, n, v);
1450                 });
1451             });
1452         },
1453
1454         // #endif
1455
1456         getAttrib : function(e, n, dv) {
1457             var v, t = this;
1458
1459             e = t.get(e);
1460
1461             if (!e)
1462                 return false;
1463
1464             if (!is(dv))
1465                 dv = "";
1466
1467             // Try the mce variant for these
1468             if (/^(src|href|style|coords)$/.test(n)) {
1469                 v = e.getAttribute("mce_" + n);
1470
1471                 if (v)
1472                     return v;
1473             }
1474
1475             v = e.getAttribute(n, 2);
1476
1477             if (!v) {
1478                 switch (n) {
1479                     case 'class':
1480                         v = e.className;
1481                         break;
1482
1483                     default:
1484                         // Fix for IE crash Bug: #1884376 probably due to invalid DOM structure
1485                         if (isIE && n === 'name' && e.nodeName === 'A') {
1486                             v = e.name;
1487                             break;
1488                         }
1489
1490                         v = e.attributes[n];
1491                         v = v && is(v.nodeValue) ? v.nodeValue : v;
1492                 }
1493             }
1494
1495             switch (n) {
1496                 case 'style':
1497                     v = v || e.style.cssText;
1498
1499                     if (v) {
1500                         v = t.serializeStyle(t.parseStyle(v));
1501
1502                         if (t.settings.keep_values)
1503                             e.setAttribute('mce_style', v);
1504                     }
1505
1506                     break;
1507             }
1508
1509             // Remove Apple and WebKit stuff
1510             if (isWebKit && n === "class" && v)
1511                 v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');
1512
1513             // Handle IE issues
1514             if (isIE) {
1515                 switch (n) {
1516                     case 'rowspan':
1517                     case 'colspan':
1518                         // IE returns 1 as default value
1519                         if (v === 1)
1520                             v = '';
1521
1522                         break;
1523
1524                     case 'size':
1525                         // IE returns +0 as default value for size
1526                         if (v === '+0')
1527                             v = '';
1528
1529                         break;
1530
1531                     case 'hspace':
1532                         // IE returns -1 as default value
1533                         if (v === -1)
1534                             v = '';
1535
1536                         break;
1537
1538                     case 'tabindex':
1539                         // IE returns 32768 as default value
1540                         if (v === 32768)
1541                             v = '';
1542
1543                         break;
1544
1545                     case 'shape':
1546                         v = v.toLowerCase();
1547                         break;
1548
1549                     default:
1550                         // IE has odd anonymous function for event attributes
1551                         if (n.indexOf('on') === 0 && v)
1552                             v = ('' + v).replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/, '$1');
1553                 }
1554             }
1555
1556             return (v && v != '') ? '' + v : dv;
1557         },
1558
1559         getPos : function(n) {
1560             var t = this, x = 0, y = 0, e, d = t.doc, r;
1561
1562             n = t.get(n);
1563
1564             // Use getBoundingClientRect on IE, Opera has it but it's not perfect
1565             if (n && isIE) {
1566                 n = n.getBoundingClientRect();
1567                 e = t.boxModel ? d.documentElement : d.body;
1568                 x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
1569                 x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
1570                 n.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset
1571
1572                 return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
1573             }
1574
1575             r = n;
1576             while (r) {
1577                 x += r.offsetLeft || 0;
1578                 y += r.offsetTop || 0;
1579                 r = r.offsetParent;
1580             }
1581
1582             r = n;
1583             while (r) {
1584                 // Opera 9.25 bug fix, fixed in 9.50
1585                 if (!/^table-row|inline.*/i.test(t.getStyle(r, "display", 1))) {
1586                     x -= r.scrollLeft || 0;
1587                     y -= r.scrollTop || 0;
1588                 }
1589
1590                 r = r.parentNode;
1591
1592                 if (r == d.body)
1593                     break;
1594             }
1595
1596             return {x : x, y : y};
1597         },
1598
1599         parseStyle : function(st) {
1600             var t = this, s = t.settings, o = {};
1601
1602             if (!st)
1603                 return o;
1604
1605             function compress(p, s, ot) {
1606                 var t, r, b, l;
1607
1608                 // Get values and check it it needs compressing
1609                 t = o[p + '-top' + s];
1610                 if (!t)
1611                     return;
1612
1613                 r = o[p + '-right' + s];
1614                 if (t != r)
1615                     return;
1616
1617                 b = o[p + '-bottom' + s];
1618                 if (r != b)
1619                     return;
1620
1621                 l = o[p + '-left' + s];
1622                 if (b != l)
1623                     return;
1624
1625                 // Compress
1626                 o[ot] = l;
1627                 delete o[p + '-top' + s];
1628                 delete o[p + '-right' + s];
1629                 delete o[p + '-bottom' + s];
1630                 delete o[p + '-left' + s];
1631             };
1632
1633             function compress2(ta, a, b, c) {
1634                 var t;
1635
1636                 t = o[a];
1637                 if (!t)
1638                     return;
1639
1640                 t = o[b];
1641                 if (!t)
1642                     return;
1643
1644                 t = o[c];
1645                 if (!t)
1646                     return;
1647
1648                 // Compress
1649                 o[ta] = o[a] + ' ' + o[b] + ' ' + o[c];
1650                 delete o[a];
1651                 delete o[b];
1652                 delete o[c];
1653             };
1654
1655             each(st.split(';'), function(v) {
1656                 var sv, ur = [];
1657
1658                 if (v) {
1659                     v = v.replace(/url\([^\)]+\)/g, function(v) {ur.push(v);return 'url(' + ur.length + ')';});
1660                     v = v.split(':');
1661                     sv = tinymce.trim(v[1]);
1662                     sv = sv.replace(/url\(([^\)]+)\)/g, function(a, b) {return ur[parseInt(b) - 1];});
1663
1664                     sv = sv.replace(/rgb\([^\)]+\)/g, function(v) {
1665                         return t.toHex(v);
1666                     });
1667
1668                     if (s.url_converter) {
1669                         sv = sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g, function(x, c) {
1670                             return 'url(' + t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), 'style', null)) + ')';
1671                         });
1672                     }
1673
1674                     o[tinymce.trim(v[0]).toLowerCase()] = sv;
1675                 }
1676             });
1677
1678             compress("border", "", "border");
1679             compress("border", "-width", "border-width");
1680             compress("border", "-color", "border-color");
1681             compress("border", "-style", "border-style");
1682             compress("padding", "", "padding");
1683             compress("margin", "", "margin");
1684             compress2('border', 'border-width', 'border-style', 'border-color');
1685
1686             if (isIE) {
1687                 // Remove pointless border
1688                 if (o.border == 'medium none')
1689                     o.border = '';
1690             }
1691
1692             return o;
1693         },
1694
1695         serializeStyle : function(o) {
1696             var s = '';
1697
1698             each(o, function(v, k) {
1699                 if (k && v) {
1700                     switch (k) {
1701                         case 'color':
1702                         case 'background-color':
1703                             v = v.toLowerCase();
1704                             break;
1705                     }
1706
1707                     s += (s ? ' ' : '') + k + ': ' + v + ';';
1708                 }
1709             });
1710
1711             return s;
1712         },
1713
1714         loadCSS : function(u) {
1715             var t = this, d = t.doc;
1716
1717             if (!u)
1718                 u = '';
1719
1720             each(u.split(','), function(u) {
1721                 if (t.files[u])
1722                     return;
1723
1724                 t.files[u] = true;
1725                 t.add(t.select('head')[0], 'link', {rel : 'stylesheet', href : u});
1726             });
1727         },
1728
1729         // #if !jquery
1730
1731         addClass : function(e, c) {
1732             return this.run(e, function(e) {
1733                 var o;
1734
1735                 if (!c)
1736                     return 0;
1737
1738                 if (this.hasClass(e, c))
1739                     return e.className;
1740
1741                 o = this.removeClass(e, c);
1742
1743                 return e.className = (o != '' ? (o + ' ') : '') + c;
1744             });
1745         },
1746
1747         removeClass : function(e, c) {
1748             var t = this, re;
1749
1750             return t.run(e, function(e) {
1751                 var v;
1752
1753                 if (t.hasClass(e, c)) {
1754                     if (!re)
1755                         re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
1756
1757                     v = e.className.replace(re, ' ');
1758
1759                     return e.className = tinymce.trim(v != ' ' ? v : '');
1760                 }
1761
1762                 return e.className;
1763             });
1764         },
1765
1766         hasClass : function(n, c) {
1767             n = this.get(n);
1768
1769             if (!n || !c)
1770                 return false;
1771
1772             return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;
1773         },
1774
1775         show : function(e) {
1776             return this.setStyle(e, 'display', 'block');
1777         },
1778
1779         hide : function(e) {
1780             return this.setStyle(e, 'display', 'none');
1781         },
1782
1783         isHidden : function(e) {
1784             e = this.get(e);
1785
1786             return e.style.display == 'none' || this.getStyle(e, 'display') == 'none';
1787         },
1788
1789         // #endif
1790
1791         uniqueId : function(p) {
1792             return (!p ? 'mce_' : p) + (this.counter++);
1793         },
1794
1795         setHTML : function(e, h) {
1796             var t = this;
1797
1798             return this.run(e, function(e) {
1799                 var x, i, nl, n, p, x;
1800
1801                 h = t.processHTML(h);
1802
1803                 if (isIE) {
1804                     function set() {
1805                         try {
1806                             // IE will remove comments from the beginning
1807                             // unless you padd the contents with something
1808                             e.innerHTML = '<br />' + h;
1809                             e.removeChild(e.firstChild);
1810                         } catch (ex) {
1811                             // 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
1812                             // This seems to fix this problem
1813
1814                             // Remove all child nodes
1815                             while (e.firstChild)
1816                                 e.firstChild.removeNode();
1817
1818                             // Create new div with HTML contents and a BR infront to keep comments
1819                             x = t.create('div');
1820                             x.innerHTML = '<br />' + h;
1821
1822                             // Add all children from div to target
1823                             each (x.childNodes, function(n, i) {
1824                                 // Skip br element
1825                                 if (i)
1826                                     e.appendChild(n);
1827                             });
1828                         }
1829                     };
1830
1831                     // IE has a serious bug when it comes to paragraphs it can produce an invalid
1832                     // DOM tree if contents like this <p><ul><li>Item 1</li></ul></p> is inserted
1833                     // It seems to be that IE doesn't like a root block element placed inside another root block element
1834                     if (t.settings.fix_ie_paragraphs)
1835                         h = h.replace(/<p><\/p>|<p([^>]+)><\/p>|<p[^\/+]\/>/gi, '<p$1 mce_keep="true">&nbsp;</p>');
1836
1837                     set();
1838
1839                     if (t.settings.fix_ie_paragraphs) {
1840                         // Check for odd paragraphs this is a sign of a broken DOM
1841                         nl = e.getElementsByTagName("p");
1842                         for (i = nl.length - 1, x = 0; i >= 0; i--) {
1843                             n = nl[i];
1844
1845                             if (!n.hasChildNodes()) {
1846                                 if (!n.mce_keep) {
1847                                     x = 1; // Is broken
1848                                     break;
1849                                 }
1850
1851                                 n.removeAttribute('mce_keep');
1852                             }
1853                         }
1854                     }
1855
1856                     // Time to fix the madness IE left us
1857                     if (x) {
1858                         // So if we replace the p elements with divs and mark them and then replace them back to paragraphs
1859                         // after we use innerHTML we can fix the DOM tree
1860                         h = h.replace(/<p([^>]+)>|<p>/g, '<div$1 mce_tmp="1">');
1861                         h = h.replace(/<\/p>/g, '</div>');
1862
1863                         // Set the new HTML with DIVs
1864                         set();
1865
1866                         // Replace all DIV elements with he mce_tmp attibute back to paragraphs
1867                         // This is needed since IE has a annoying bug see above for details
1868                         // This is a slow process but it has to be done. :(
1869                         if (t.settings.fix_ie_paragraphs) {
1870                             nl = e.getElementsByTagName("DIV");
1871                             for (i = nl.length - 1; i >= 0; i--) {
1872                                 n = nl[i];
1873
1874                                 // Is it a temp div
1875                                 if (n.mce_tmp) {
1876                                     // Create new paragraph
1877                                     p = t.doc.createElement('p');
1878
1879                                     // Copy all attributes
1880                                     n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) {
1881                                         var v;
1882
1883                                         if (b !== 'mce_tmp') {
1884                                             v = n.getAttribute(b);
1885
1886                                             if (!v && b === 'class')
1887                                                 v = n.className;
1888
1889                                             p.setAttribute(b, v);
1890                                         }
1891                                     });
1892
1893                                     // Append all children to new paragraph
1894                                     for (x = 0; x<n.childNodes.length; x++)
1895                                         p.appendChild(n.childNodes[x].cloneNode(true));
1896
1897                                     // Replace div with new paragraph
1898                                     n.swapNode(p);
1899                                 }
1900                             }
1901                         }
1902                     }
1903                 } else
1904                     e.innerHTML = h;
1905
1906                 return h;
1907             });
1908         },
1909
1910         processHTML : function(h) {
1911             var t = this, s = t.settings;
1912
1913             if (!s.process_html)
1914                 return h;
1915
1916             // Convert strong and em to b and i in FF since it can't handle them
1917             if (tinymce.isGecko) {
1918                 h = h.replace(/<(\/?)strong>|<strong( [^>]+)>/gi, '<$1b$2>');
1919                 h = h.replace(/<(\/?)em>|<em( [^>]+)>/gi, '<$1i$2>');
1920             }
1921
1922             // Fix some issues
1923             h = h.replace(/<a( )([^>]+)\/>|<a\/>/gi, '<a$1$2></a>'); // Force open
1924
1925             // Store away src and href in mce_src and mce_href since browsers mess them up
1926             if (s.keep_values) {
1927                 // Wrap scripts in comments for serialization purposes
1928                 if (h.indexOf('<script') !== -1) {
1929                     h = h.replace(/<script>/g, '<script type="text/javascript">');
1930                     h = h.replace(/<script(|[^>]+)>(\s*<!--|\/\/\s*<\[CDATA\[)?[\r\n]*/g, '<mce:script$1><!--\n');
1931                     h = h.replace(/\s*(\/\/\s*-->|\/\/\s*]]>)?<\/script>/g, '\n// --></mce:script>');
1932                     h = h.replace(/<mce:script(|[^>]+)><!--\n\/\/ --><\/mce:script>/g, '<mce:script$1></mce:script>');
1933                 }
1934
1935                 // Process all tags with src, href or style
1936                 h = h.replace(/<([\w:]+) [^>]*(src|href|style|coords)[^>]*>/gi, function(a, n) {
1937                     function handle(m, b, c) {
1938                         var u = c;
1939
1940                         // Tag already got a mce_ version
1941                         if (a.indexOf('mce_' + b) != -1)
1942                             return m;
1943
1944                         if (b == 'style') {
1945                             // Why did I need this one?
1946                             //if (isIE)
1947                             //    u = t.serializeStyle(t.parseStyle(u));
1948
1949                             if (s.hex_colors) {
1950                                 u = u.replace(/rgb\([^\)]+\)/g, function(v) {
1951                                     return t.toHex(v);
1952                                 });
1953                             }
1954
1955                             if (s.url_converter) {
1956                                 u = u.replace(/url\([\'\"]?([^\)\'\"]+)\)/g, function(x, c) {
1957                                     return 'url(' + t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n)) + ')';
1958                                 });
1959                             }
1960                         } else if (b != 'coords') {
1961                             if (s.url_converter)
1962                                 u = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n));
1963                         }
1964
1965                         return ' ' + b + '="' + c + '" mce_' + b + '="' + u + '"';
1966                     };
1967
1968                     a = a.replace(/ (src|href|style|coords)=[\"]([^\"]+)[\"]/gi, handle); // W3C
1969                     a = a.replace(/ (src|href|style|coords)=[\']([^\']+)[\']/gi, handle); // W3C
1970
1971                     return a.replace(/ (src|href|style|coords)=([^\s\"\'>]+)/gi, handle); // IE
1972                 });
1973             }
1974
1975             return h;
1976         },
1977
1978         getOuterHTML : function(e) {
1979             var d;
1980
1981             e = this.get(e);
1982
1983             if (!e)
1984                 return null;
1985
1986             if (isIE)
1987                 return e.outerHTML;
1988
1989             d = (e.ownerDocument || this.doc).createElement("body");
1990             d.appendChild(e.cloneNode(true));
1991
1992             return d.innerHTML;
1993         },
1994
1995         setOuterHTML : function(e, h, d) {
1996             var t = this;
1997
1998             return this.run(e, function(e) {
1999                 var n, tp;
2000
2001                 e = t.get(e);
2002                 d = d || e.ownerDocument || t.doc;
2003
2004                 if (isIE && e.nodeType == 1)
2005                     e.outerHTML = h;
2006                 else {
2007                     tp = d.createElement("body");
2008                     tp.innerHTML = h;
2009
2010                     n = tp.lastChild;
2011                     while (n) {
2012                         t.insertAfter(n.cloneNode(true), e);
2013                         n = n.previousSibling;
2014                     }
2015
2016                     t.remove(e);
2017                 }
2018             });
2019         },
2020
2021         decode : function(s) {
2022             var e;
2023
2024             // Look for entities to decode
2025             if (/&[^;]+;/.test(s)) {
2026                 // Decode the entities using a div element not super efficient but less code
2027                 e = this.doc.createElement("div");
2028                 e.innerHTML = s;
2029
2030                 return !e.firstChild ? s : e.firstChild.nodeValue;
2031             }
2032
2033             return s;
2034         },
2035
2036         encode : function(s) {
2037             return s ? ('' + s).replace(/[<>&\"]/g, function (c, b) {
2038                 switch (c) {
2039                     case '&':
2040                         return '&amp;';
2041
2042                     case '"':
2043                         return '&quot;';
2044
2045                     case '<':
2046                         return '&lt;';
2047
2048                     case '>':
2049                         return '&gt;';
2050                 }
2051
2052                 return c;
2053             }) : s;
2054         },
2055
2056         // #if !jquery
2057
2058         insertAfter : function(n, r) {
2059             var t = this;
2060
2061             r = t.get(r);
2062
2063             return this.run(n, function(n) {
2064                 var p, ns;
2065
2066                 p = r.parentNode;
2067                 ns = r.nextSibling;
2068
2069                 if (ns)
2070                     p.insertBefore(n, ns);
2071                 else
2072                     p.appendChild(n);
2073
2074                 return n;
2075             });
2076         },
2077
2078         // #endif
2079
2080         isBlock : function(n) {
2081             if (n.nodeType && n.nodeType !== 1)
2082                 return false;
2083
2084             n = n.nodeName || n;
2085
2086             return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n);
2087         },
2088
2089         // #if !jquery
2090
2091         replace : function(n, o, k) {
2092             if (is(o, 'array'))
2093                 n = n.cloneNode(true);
2094
2095             return this.run(o, function(o) {
2096                 if (k) {
2097                     each(o.childNodes, function(c) {
2098                         n.appendChild(c.cloneNode(true));
2099                     });
2100                 }
2101
2102                 // Fix IE psuedo leak for elements since replacing elements if fairly common
2103                 if (isIE && o.nodeType === 1) {
2104                     o.parentNode.insertBefore(n, o);
2105                     o.outerHTML = '';
2106                     return n;
2107                 }
2108
2109                 return o.parentNode.replaceChild(n, o);
2110             });
2111         },
2112
2113         // #endif
2114
2115         toHex : function(s) {
2116             var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);
2117
2118             function hex(s) {
2119                 s = parseInt(s).toString(16);
2120
2121                 return s.length > 1 ? s : '0' + s; // 0 -> 00
2122             };
2123
2124             if (c) {
2125                 s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]);
2126
2127                 return s;
2128             }
2129
2130             return s;
2131         },
2132
2133         getClasses : function() {
2134             var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov;
2135
2136             if (t.classes)
2137                 return t.classes;
2138
2139             function addClasses(s) {
2140                 // IE style imports
2141                 each(s.imports, function(r) {
2142                     addClasses(r);
2143                 });
2144
2145                 each(s.cssRules || s.rules, function(r) {
2146                     // Real type or fake it on IE
2147                     switch (r.type || 1) {
2148                         // Rule
2149                         case 1:
2150                             if (r.selectorText) {
2151                                 each(r.selectorText.split(','), function(v) {
2152                                     v = v.replace(/^\s*|\s*$|^\s\./g, "");
2153
2154                                     // Is internal or it doesn't contain a class
2155                                     if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v))
2156                                         return;
2157
2158                                     // Remove everything but class name
2159                                     ov = v;
2160                                     v = v.replace(/.*\.([a-z0-9_\-]+).*/i, '$1');
2161
2162                                     // Filter classes
2163                                     if (f && !(v = f(v, ov)))
2164                                         return;
2165
2166                                     if (!lo[v]) {
2167                                         cl.push({'class' : v});
2168                                         lo[v] = 1;
2169                                     }
2170                                 });
2171                             }
2172                             break;
2173
2174                         // Import
2175                         case 3:
2176                             addClasses(r.styleSheet);
2177                             break;
2178                     }
2179                 });
2180             };
2181
2182             try {
2183                 each(t.doc.styleSheets, addClasses);
2184             } catch (ex) {
2185                 // Ignore
2186             }
2187
2188             if (cl.length > 0)
2189                 t.classes = cl;
2190
2191             return cl;
2192         },
2193
2194         run : function(e, f, s) {
2195             var t = this, o;
2196
2197             if (t.doc && typeof(e) === 'string')
2198                 e = t.doc.getElementById(e);
2199
2200             if (!e)
2201                 return false;
2202
2203             s = s || this;
2204             if (!e.nodeType && (e.length || e.length === 0)) {
2205                 o = [];
2206
2207                 each(e, function(e, i) {
2208                     if (e) {
2209                         if (typeof(e) == 'string')
2210                             e = t.doc.getElementById(e);
2211
2212                         o.push(f.call(s, e, i));
2213                     }
2214                 });
2215
2216                 return o;
2217             }
2218
2219             return f.call(s, e);
2220         },
2221
2222         getAttribs : function(n) {
2223             var o;
2224
2225             n = this.get(n);
2226
2227             if (!n)
2228                 return [];
2229
2230             if (isIE) {
2231                 o = [];
2232
2233                 // Object will throw exception in IE
2234                 if (n.nodeName == 'OBJECT')
2235                     return n.attributes;
2236
2237                 // It's crazy that this is faster in IE but it's because it returns all attributes all the time
2238                 n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi, function(a, b) {
2239                     o.push({specified : 1, nodeName : b});
2240                 });
2241
2242                 return o;
2243             }
2244
2245             return n.attributes;
2246         },
2247
2248         destroy : function(s) {
2249             var t = this;
2250
2251             t.win = t.doc = t.root = null;
2252
2253             // Manual destroy then remove unload handler
2254             if (!s)
2255                 tinymce.removeUnload(t.destroy);
2256         }
2257
2258         /*
2259         walk : function(n, f, s) {
2260             var d = this.doc, w;
2261
2262             if (d.createTreeWalker) {
2263                 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
2264
2265                 while ((n = w.nextNode()) != null)
2266                     f.call(s || this, n);
2267             } else
2268                 tinymce.walk(n, f, 'childNodes', s);
2269         }
2270         */
2271
2272         /*
2273         toRGB : function(s) {
2274             var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s);
2275
2276             if (c) {
2277                 // #FFF -> #FFFFFF
2278                 if (!is(c[3]))
2279                     c[3] = c[2] = c[1];
2280
2281                 return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")";
2282             }
2283
2284             return s;
2285         }
2286         */
2287
2288         });
2289
2290     // Setup page DOM
2291     tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0});
2292 })();
2293
2294 /* file:jscripts/tiny_mce/classes/dom/Event.js */
2295
2296 (function() {
2297     // Shorten names
2298     var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
2299
2300     tinymce.create('static tinymce.dom.Event', {
2301         inits : [],
2302         events : [],
2303
2304         // #if !jquery
2305
2306         add : function(o, n, f, s) {
2307             var cb, t = this, el = t.events, r;
2308
2309             // Handle array
2310             if (o && o instanceof Array) {
2311                 r = [];
2312
2313                 each(o, function(o) {
2314                     o = DOM.get(o);
2315                     r.push(t.add(o, n, f, s));
2316                 });
2317
2318                 return r;
2319             }
2320
2321             o = DOM.get(o);
2322
2323             if (!o)
2324                 return;
2325
2326             // Setup event callback
2327             cb = function(e) {
2328                 e = e || window.event;
2329
2330                 // Patch in target in IE it's W3C valid
2331                 if (e && !e.target && isIE)
2332                     e.target = e.srcElement;
2333
2334                 if (!s)
2335                     return f(e);
2336
2337                 return f.call(s, e);
2338             };
2339
2340             if (n == 'unload') {
2341                 tinymce.unloads.unshift({func : cb});
2342                 return cb;
2343             }
2344
2345             if (n == 'init') {
2346                 if (t.domLoaded)
2347                     cb();
2348                 else
2349                     t.inits.push(cb);
2350
2351                 return cb;
2352             }
2353
2354             // Store away listener reference
2355             el.push({
2356                 obj : o,
2357                 name : n,
2358                 func : f,
2359                 cfunc : cb,
2360                 scope : s
2361             });
2362
2363             t._add(o, n, cb);
2364
2365             return f;
2366         },
2367
2368         remove : function(o, n, f) {
2369             var t = this, a = t.events, s = false, r;
2370
2371             // Handle array
2372             if (o && o instanceof Array) {
2373                 r = [];
2374
2375                 each(o, function(o) {
2376                     o = DOM.get(o);
2377                     r.push(t.remove(o, n, f));
2378                 });
2379
2380                 return r;
2381             }
2382
2383             o = DOM.get(o);
2384
2385             each(a, function(e, i) {
2386                 if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
2387                     a.splice(i, 1);
2388                     t._remove(o, n, e.cfunc);
2389                     s = true;
2390                     return false;
2391                 }
2392             });
2393
2394             return s;
2395         },
2396
2397         clear : function(o) {
2398             var t = this, a = t.events, i, e;
2399
2400             if (o) {
2401                 o = DOM.get(o);
2402
2403                 for (i = a.length - 1; i >= 0; i--) {
2404                     e = a[i];
2405
2406                     if (e.obj === o) {
2407                         t._remove(e.obj, e.name, e.cfunc);
2408                         e.obj = e.cfunc = null;
2409                         a.splice(i, 1);
2410                     }
2411                 }
2412             }
2413         },
2414
2415         // #endif
2416
2417         cancel : function(e) {
2418             if (!e)
2419                 return false;
2420
2421             this.stop(e);
2422             return this.prevent(e);
2423         },
2424
2425         stop : function(e) {
2426             if (e.stopPropagation)
2427                 e.stopPropagation();
2428             else
2429                 e.cancelBubble = true;
2430
2431             return false;
2432         },
2433
2434         prevent : function(e) {
2435             if (e.preventDefault)
2436                 e.preventDefault();
2437             else
2438                 e.returnValue = false;
2439
2440             return false;
2441         },
2442
2443         _unload : function() {
2444             var t = Event;
2445
2446             each(t.events, function(e, i) {
2447                 t._remove(e.obj, e.name, e.cfunc);
2448                 e.obj = e.cfunc = null;
2449             });
2450
2451             t.events = [];
2452             t = null;
2453         },
2454
2455         _add : function(o, n, f) {
2456             if (o.attachEvent)
2457                 o.attachEvent('on' + n, f);
2458             else if (o.addEventListener)
2459                 o.addEventListener(n, f, false);
2460             else
2461                 o['on' + n] = f;
2462         },
2463
2464         _remove : function(o, n, f) {
2465             if (o) {
2466                 try {
2467                     if (o.detachEvent)
2468                         o.detachEvent('on' + n, f);
2469                     else if (o.removeEventListener)
2470                         o.removeEventListener(n, f, false);
2471                     else
2472                         o['on' + n] = null;
2473                 } catch (ex) {
2474                     // Might fail with permission denined on IE so we just ignore that
2475                 }
2476             }
2477         },
2478
2479         _pageInit : function() {
2480             var e = Event;
2481
2482             e._remove(window, 'DOMContentLoaded', e._pageInit);
2483             e.domLoaded = true;
2484
2485             each(e.inits, function(c) {
2486                 c();
2487             });
2488
2489             e.inits = [];
2490         },
2491
2492         _wait : function() {
2493             var t;
2494
2495             // No need since the document is already loaded
2496             if (window.tinyMCE_GZ && tinyMCE_GZ.loaded)
2497                 return;
2498
2499             if (isIE && document.location.protocol != 'https:') {
2500                 // Fake DOMContentLoaded on IE
2501                 document.write('<script id=__ie_onload defer src=\'javascript:""\';><\/script>');
2502                 DOM.get("__ie_onload").onreadystatechange = function() {
2503                     if (this.readyState == "complete") {
2504                         Event._pageInit();
2505                         DOM.get("__ie_onload").onreadystatechange = null; // Prevent leak
2506                     }
2507                 };
2508             } else {
2509                 Event._add(window, 'DOMContentLoaded', Event._pageInit, Event);
2510
2511                 if (isIE || isWebKit) {
2512                     t = setInterval(function() {
2513                         if (/loaded|complete/.test(document.readyState)) {
2514                             clearInterval(t);
2515                             Event._pageInit();
2516                         }
2517                     }, 10);
2518                 }
2519             }
2520         }
2521
2522         });
2523
2524     // Shorten name
2525     Event = tinymce.dom.Event;
2526
2527     // Dispatch DOM content loaded event for IE and Safari
2528     Event._wait();
2529     tinymce.addUnload(Event._unload);
2530 })();
2531
2532 /* file:jscripts/tiny_mce/classes/dom/Element.js */
2533
2534 (function() {
2535     var each = tinymce.each;
2536
2537     tinymce.create('tinymce.dom.Element', {
2538         Element : function(id, s) {
2539             var t = this, dom, el;
2540
2541             s = s || {};
2542             t.id = id;
2543             t.dom = dom = s.dom || tinymce.DOM;
2544             t.settings = s;
2545
2546             // Only IE leaks DOM references, this is a lot faster
2547             if (!tinymce.isIE)
2548                 el = t.dom.get(t.id);
2549
2550             each([
2551                 'getPos',
2552                 'getRect',
2553                 'getParent',
2554                 'add',
2555                 'setStyle',
2556                 'getStyle',
2557                 'setStyles',
2558                 'setAttrib',
2559                 'setAttribs',
2560                 'getAttrib',
2561                 'addClass',
2562                 'removeClass',
2563                 'hasClass',
2564                 'getOuterHTML',
2565                 'setOuterHTML',
2566                 'remove',
2567                 'show',
2568                 'hide',
2569                 'isHidden',
2570                 'setHTML',
2571                 'get'
2572             ], function(k) {
2573                 t[k] = function() {
2574                     var a = arguments, o;
2575
2576                     // Opera fails
2577                     if (tinymce.isOpera) {
2578                         a = [id];
2579
2580                         each(arguments, function(v) {
2581                             a.push(v);
2582                         });
2583                     } else
2584                         Array.prototype.unshift.call(a, el || id);
2585
2586                     o = dom[k].apply(dom, a);
2587                     t.update(k);
2588
2589                     return o;
2590                 };
2591             });
2592         },
2593
2594         on : function(n, f, s) {
2595             return tinymce.dom.Event.add(this.id, n, f, s);
2596         },
2597
2598         getXY : function() {
2599             return {
2600                 x : parseInt(this.getStyle('left')),
2601                 y : parseInt(this.getStyle('top'))
2602             };
2603         },
2604
2605         getSize : function() {
2606             var n = this.dom.get(this.id);
2607
2608             return {
2609                 w : parseInt(this.getStyle('width') || n.clientWidth),
2610                 h : parseInt(this.getStyle('height') || n.clientHeight)
2611             };
2612         },
2613
2614         moveTo : function(x, y) {
2615             this.setStyles({left : x, top : y});
2616         },
2617
2618         moveBy : function(x, y) {
2619             var p = this.getXY();
2620
2621             this.moveTo(p.x + x, p.y + y);
2622         },
2623
2624         resizeTo : function(w, h) {
2625             this.setStyles({width : w, height : h});
2626         },
2627
2628         resizeBy : function(w, h) {
2629             var s = this.getSize();
2630
2631             this.resizeTo(s.w + w, s.h + h);
2632         },
2633
2634         update : function(k) {
2635             var t = this, b, dom = t.dom;
2636
2637             if (tinymce.isIE6 && t.settings.blocker) {
2638                 k = k || '';
2639
2640                 // Ignore getters
2641                 if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)
2642                     return;
2643
2644                 // Remove blocker on remove
2645                 if (k == 'remove') {
2646                     dom.remove(t.blocker);
2647                     return;
2648                 }
2649
2650                 if (!t.blocker) {
2651                     t.blocker = dom.uniqueId();
2652                     b = dom.add(t.settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});
2653                     dom.setStyle(b, 'opacity', 0);
2654                 } else
2655                     b = dom.get(t.blocker);
2656
2657                 dom.setStyle(b, 'left', t.getStyle('left', 1));
2658                 dom.setStyle(b, 'top', t.getStyle('top', 1));
2659                 dom.setStyle(b, 'width', t.getStyle('width', 1));
2660                 dom.setStyle(b, 'height', t.getStyle('height', 1));
2661                 dom.setStyle(b, 'display', t.getStyle('display', 1));
2662                 dom.setStyle(b, 'zIndex', parseInt(t.getStyle('zIndex', 1) || 0) - 1);
2663             }
2664         }
2665
2666         });
2667 })();
2668
2669 /* file:jscripts/tiny_mce/classes/dom/Selection.js */
2670
2671 (function() {
2672     // Shorten names
2673     var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each;
2674
2675     tinymce.create('tinymce.dom.Selection', {
2676         Selection : function(dom, win, serializer) {
2677             var t = this;
2678
2679             t.dom = dom;
2680             t.win = win;
2681             t.serializer = serializer;
2682
2683             // Prevent leaks
2684             tinymce.addUnload(t.destroy, t);
2685         },
2686
2687         getContent : function(s) {
2688             var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
2689
2690             s = s || {};
2691             wb = wa = '';
2692             s.get = true;
2693             s.format = s.format || 'html';
2694
2695             if (s.format == 'text')
2696                 return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));
2697
2698             if (r.cloneContents) {
2699                 n = r.cloneContents();
2700
2701                 if (n)
2702                     e.appendChild(n);
2703             } else if (is(r.item) || is(r.htmlText))
2704                 e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
2705             else
2706                 e.innerHTML = r.toString();
2707
2708             // Keep whitespace before and after
2709             if (/^\s/.test(e.innerHTML))
2710                 wb = ' ';
2711
2712             if (/\s+$/.test(e.innerHTML))
2713                 wa = ' ';
2714
2715             s.getInner = true;
2716
2717             return t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;
2718         },
2719
2720         setContent : function(h, s) {
2721             var t = this, r = t.getRng(), d;
2722
2723             s = s || {format : 'html'};
2724             s.set = true;
2725             h = t.dom.processHTML(h);
2726
2727             if (r.insertNode) {
2728                 d = t.win.document;
2729
2730                 // Gecko has a bug where if you insert &nbsp; using InsertHTML it will insert a space instead
2731                 // So we simply check if the input is HTML or text and then insert text using the insertNode method
2732                 if (tinymce.isGecko && h.indexOf('<') == -1) {
2733                     r.deleteContents();
2734                     r.insertNode(t.getRng().createContextualFragment(h + '<span id="__caret">_</span>'));
2735                     t.select(t.dom.get('__caret'));
2736                     t.getRng().deleteContents();
2737                     return;
2738                 }
2739
2740                 // Use insert HTML if it exists (places cursor after content)
2741                 try {
2742                     // This might fail with an exception see bug #1893736
2743                     if (d.queryCommandEnabled('InsertHTML'))
2744                         return d.execCommand('InsertHTML', false, h);
2745                 } catch (ex) {
2746                     // Use old school method
2747                     r.deleteContents();
2748                     r.insertNode(t.getRng().createContextualFragment(h));
2749                 }
2750             } else {
2751                 if (r.item)
2752                     r.item(0).outerHTML = h;
2753                 else
2754                     r.pasteHTML(h);
2755             }
2756         },
2757
2758         getStart : function() {
2759             var t = this, r = t.getRng(), e;
2760
2761             if (isIE) {
2762                 if (r.item)
2763                     return r.item(0);
2764
2765                 r = r.duplicate();
2766                 r.collapse(1);
2767                 e = r.parentElement();
2768
2769                 if (e.nodeName == 'BODY')
2770                     return e.firstChild;
2771
2772                 return e;
2773             } else {
2774                 e = r.startContainer;
2775
2776                 if (e.nodeName == 'BODY')
2777                     return e.firstChild;
2778
2779                 return t.dom.getParent(e, function(n) {return n.nodeType == 1;});
2780             }
2781         },
2782
2783         getEnd : function() {
2784             var t = this, r = t.getRng(), e;
2785
2786             if (isIE) {
2787                 if (r.item)
2788                     return r.item(0);
2789
2790                 r = r.duplicate();
2791                 r.collapse(0);
2792                 e = r.parentElement();
2793
2794                 if (e.nodeName == 'BODY')
2795                     return e.lastChild;
2796
2797                 return e;
2798             } else {
2799                 e = r.endContainer;
2800
2801                 if (e.nodeName == 'BODY')
2802                     return e.lastChild;
2803
2804                 return t.dom.getParent(e, function(n) {return n.nodeType == 1;});
2805             }
2806         },
2807
2808         getBookmark : function(si) {
2809             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;
2810             sx = vp.x;
2811             sy = vp.y;
2812
2813             // Simple bookmark fast but not as persistent
2814             if (si == 'simple')
2815                 return {rng : r, scrollX : sx, scrollY : sy};
2816
2817             // Handle IE
2818             if (isIE) {
2819                 // Control selection
2820                 if (r.item) {
2821                     e = r.item(0);
2822
2823                     each(t.dom.select(e.nodeName), function(n, i) {
2824                         if (e == n) {
2825                             sp = i;
2826                             return false;
2827                         }
2828                     });
2829
2830                     return {
2831                         tag : e.nodeName,
2832                         index : sp,
2833                         scrollX : sx,
2834                         scrollY : sy
2835                     };
2836                 }
2837
2838                 // Text selection
2839                 tr = t.dom.doc.body.createTextRange();
2840                 tr.moveToElementText(ro);
2841                 tr.collapse(true);
2842                 bp = Math.abs(tr.move('character', c));
2843
2844                 tr = r.duplicate();
2845                 tr.collapse(true);
2846                 sp = Math.abs(tr.move('character', c));
2847
2848                 tr = r.duplicate();
2849                 tr.collapse(false);
2850                 le = Math.abs(tr.move('character', c)) - sp;
2851
2852                 return {
2853                     start : sp - bp,
2854                     length : le,
2855                     scrollX : sx,
2856                     scrollY : sy
2857                 };
2858             }
2859
2860             // Handle W3C
2861             e = t.getNode();
2862             s = t.getSel();
2863
2864             if (!s)
2865                 return null;
2866
2867             // Image selection
2868             if (e && e.nodeName == 'IMG') {
2869                 return {
2870                     scrollX : sx,
2871                     scrollY : sy
2872                 };
2873             }
2874
2875             // Text selection
2876
2877             function getPos(r, sn, en) {
2878                 var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
2879
2880                 while ((n = w.nextNode()) != null) {
2881                     if (n == sn)
2882                         d.start = p;
2883
2884                     if (n == en) {
2885                         d.end = p;
2886                         return d;
2887                     }
2888
2889                     p += tinymce.trim(n.nodeValue || '').length;
2890                 }
2891
2892                 return null;
2893             };
2894
2895             // Caret or selection
2896             if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
2897                 e = getPos(ro, s.anchorNode, s.focusNode);
2898
2899                 if (!e)
2900                     return {scrollX : sx, scrollY : sy};
2901
2902                 // Count whitespace before
2903                 (s.anchorNode.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
2904
2905                 return {
2906                     start : Math.max(e.start + s.anchorOffset - wb, 0),
2907                     end : Math.max(e.end + s.focusOffset - wb, 0),
2908                     scrollX : sx,
2909                     scrollY : sy,
2910                     beg : s.anchorOffset - wb == 0
2911                 };
2912             } else {
2913                 e = getPos(ro, r.startContainer, r.endContainer);
2914
2915                 // Count whitespace before start and end container
2916                 (r.startContainer.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
2917                 (r.endContainer.nodeValue || '').replace(/^\s+/, function(a) {wa = a.length;});
2918
2919                 if (!e)
2920                     return {scrollX : sx, scrollY : sy};
2921
2922                 return {
2923                     start : Math.max(e.start + r.startOffset - wb, 0),
2924                     end : Math.max(e.end + r.endOffset - wa, 0),
2925                     scrollX : sx,
2926                     scrollY : sy,
2927                     beg : r.startOffset - wb == 0
2928                 };
2929             }
2930         },
2931
2932         moveToBookmark : function(b) {
2933             var t = this, r = t.getRng(), s = t.getSel(), ro = t.dom.getRoot(), sd, nvl, nv;
2934
2935             function getPos(r, sp, ep) {
2936                 var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}, o, v, wa, wb;
2937
2938                 while ((n = w.nextNode()) != null) {
2939                     wa = wb = 0;
2940
2941                     nv = n.nodeValue || '';
2942                     nv.replace(/^\s+[^\s]/, function(a) {wb = a.length - 1;});
2943                     nv.replace(/[^\s]\s+$/, function(a) {wa = a.length - 1;});
2944
2945                     nvl = tinymce.trim(nv).length;
2946                     p += nvl;
2947
2948                     if (p >= sp && !d.startNode) {
2949                         o = sp - (p - nvl);
2950
2951                         // Fix for odd quirk in FF
2952                         if (b.beg && o >= nvl)
2953                             continue;
2954
2955                         d.startNode = n;
2956                         d.startOffset = o + wb;
2957                     }
2958
2959                     if (p >= ep) {
2960                         d.endNode = n;
2961                         d.endOffset = ep - (p - nvl) + wb;
2962                         return d;
2963                     }
2964                 }
2965
2966                 return null;
2967             };
2968
2969             if (!b)
2970                 return false;
2971
2972             t.win.scrollTo(b.scrollX, b.scrollY);
2973
2974             // Handle explorer
2975             if (isIE) {
2976                 // Handle simple
2977                 if (r = b.rng) {
2978                     try {
2979                         r.select();
2980                     } catch (ex) {
2981                         // Ignore
2982                     }
2983
2984                     return true;
2985                 }
2986
2987                 t.win.focus();
2988
2989                 // Handle control bookmark
2990                 if (b.tag) {
2991                     r = ro.createControlRange();
2992
2993                     each(t.dom.select(b.tag), function(n, i) {
2994                         if (i == b.index)
2995                             r.addElement(n);
2996                     });
2997                 } else {
2998                     // Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
2999                     try {
3000                         // Incorrect bookmark
3001                         if (b.start < 0)
3002                             return true;
3003
3004                         r = s.createRange();
3005                         r.moveToElementText(ro);
3006                         r.collapse(true);
3007                         r.moveStart('character', b.start);
3008                         r.moveEnd('character', b.length);
3009                     } catch (ex2) {
3010                         return true;
3011                     }
3012                 }
3013
3014                 try {
3015                     r.select();
3016                 } catch (ex) {
3017                     // Needed for some odd IE bug #1843306
3018                 }
3019
3020                 return true;
3021             }
3022
3023             // Handle W3C
3024             if (!s)
3025                 return false;
3026
3027             // Handle simple
3028             if (b.rng) {
3029                 s.removeAllRanges();
3030                 s.addRange(b.rng);
3031             } else {
3032                 if (is(b.start) && is(b.end)) {
3033                     try {
3034                         sd = getPos(ro, b.start, b.end);
3035
3036                         if (sd) {
3037                             r = t.dom.doc.createRange();
3038                             r.setStart(sd.startNode, sd.startOffset);
3039                             r.setEnd(sd.endNode, sd.endOffset);
3040                             s.removeAllRanges();
3041                             s.addRange(r);
3042                         }
3043
3044                         if (!tinymce.isOpera)
3045                             t.win.focus();
3046                     } catch (ex) {
3047                         // Ignore
3048                     }
3049                 }
3050             }
3051         },
3052
3053         select : function(n, c) {
3054             var t = this, r = t.getRng(), s = t.getSel(), b, fn, ln, d = t.win.document;
3055
3056             function first(n) {
3057                 return n ? d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() : null;
3058             };
3059
3060             function last(n) {
3061                 var c, o, w;
3062
3063                 if (!n)
3064                     return null;
3065
3066                 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
3067                 while (c = w.nextNode())
3068                     o = c;
3069
3070                 return o;
3071             };
3072
3073             if (isIE) {
3074                 try {
3075                     b = d.body;
3076
3077                     if (/^(IMG|TABLE)$/.test(n.nodeName)) {
3078                         r = b.createControlRange();
3079                         r.addElement(n);
3080                     } else {
3081                         r = b.createTextRange();
3082                         r.moveToElementText(n);
3083                     }
3084
3085                     r.select();
3086                 } catch (ex) {
3087                     // Throws illigal agrument in IE some times
3088                 }
3089             } else {
3090                 if (c) {
3091                     fn = first(n);
3092                     ln = last(n);
3093
3094                     if (fn && ln) {
3095                         //console.debug(fn, ln);
3096                         r = d.createRange();
3097                         r.setStart(fn, 0);
3098                         r.setEnd(ln, ln.nodeValue.length);
3099                     } else
3100                         r.selectNode(n);
3101                 } else
3102                     r.selectNode(n);
3103
3104                 t.setRng(r);
3105             }
3106
3107             return n;
3108         },
3109
3110         isCollapsed : function() {
3111             var t = this, r = t.getRng(), s = t.getSel();
3112
3113             if (!r || r.item)
3114                 return false;
3115
3116             return !s || r.boundingWidth == 0 || s.isCollapsed;
3117         },
3118
3119         collapse : function(b) {
3120             var t = this, r = t.getRng(), n;
3121
3122             // Control range on IE
3123             if (r.item) {
3124                 n = r.item(0);
3125                 r = this.win.document.body.createTextRange();
3126                 r.moveToElementText(n);
3127             }
3128
3129             r.collapse(!!b);
3130             t.setRng(r);
3131         },
3132
3133         getSel : function() {
3134             var t = this, w = this.win;
3135
3136             return w.getSelection ? w.getSelection() : w.document.selection;
3137         },
3138
3139         getRng : function() {
3140             var t = this, s = t.getSel(), r;
3141
3142             try {
3143                 if (s)
3144                     r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : t.win.document.createRange());
3145             } catch (ex) {
3146                 // IE throws unspecified error here if TinyMCE is placed in a frame/iframe
3147             }
3148
3149             // No range found then create an empty one
3150             // This can occur when the editor is placed in a hidden container element on Gecko
3151             // Or on IE when there was an exception
3152             if (!r)
3153                 r = isIE ? t.win.document.body.createTextRange() : t.win.document.createRange();
3154
3155             return r;
3156         },
3157
3158         setRng : function(r) {
3159             var s;
3160
3161             if (!isIE) {
3162                 s = this.getSel();
3163
3164                 if (s) {
3165                     s.removeAllRanges();
3166                     s.addRange(r);
3167                 }
3168             } else {
3169                 try {
3170                     r.select();
3171                 } catch (ex) {
3172                     // Needed for some odd IE bug #1843306
3173                 }
3174             }
3175         },
3176
3177         setNode : function(n) {
3178             var t = this;
3179
3180             t.setContent(t.dom.getOuterHTML(n));
3181
3182             return n;
3183         },
3184
3185         getNode : function() {
3186             var t = this, r = t.getRng(), s = t.getSel(), e;
3187
3188             if (!isIE) {
3189                 // Range maybe lost after the editor is made visible again
3190                 if (!r)
3191                     return t.dom.getRoot();
3192
3193                 e = r.commonAncestorContainer;
3194
3195                 // Handle selection a image or other control like element such as anchors
3196                 if (!r.collapsed) {
3197                     if (r.startContainer == r.endContainer || (tinymce.isWebKit && r.startContainer == r.endContainer.parentNode)) {
3198                         if (r.startOffset - r.endOffset < 2 || tinymce.isWebKit) {
3199                             if (r.startContainer.hasChildNodes())
3200                                 e = r.startContainer.childNodes[r.startOffset];
3201                         }
3202                     }
3203                 }
3204
3205                 return t.dom.getParent(e, function(n) {
3206                     return n.nodeType == 1;
3207                 });
3208             }
3209
3210             return r.item ? r.item(0) : r.parentElement();
3211         },
3212
3213         destroy : function(s) {
3214             var t = this;
3215
3216             t.win = null;
3217
3218             // Manual destroy then remove unload handler
3219             if (!s)
3220                 tinymce.removeUnload(t.destroy);
3221         }
3222
3223         });
3224 })();
3225
3226 /* file:jscripts/tiny_mce/classes/dom/XMLWriter.js */
3227
3228 (function() {
3229     tinymce.create('tinymce.dom.XMLWriter', {
3230         node : null,
3231
3232         XMLWriter : function(s) {
3233             // Get XML document
3234             function getXML() {
3235                 var i = document.implementation;
3236
3237                 if (!i || !i.createDocument) {
3238                     // Try IE objects
3239                     try {return new ActiveXObject('MSXML2.DOMDocument');} catch (ex) {}
3240                     try {return new ActiveXObject('Microsoft.XmlDom');} catch (ex) {}
3241                 } else
3242                     return i.createDocument('', '', null);
3243             };
3244
3245             this.doc = getXML();
3246             
3247             // Since Opera and WebKit doesn't escape > into &gt; we need to do it our self to normalize the output for all browsers
3248             this.valid = tinymce.isOpera || tinymce.isWebKit;
3249
3250             this.reset();
3251         },
3252
3253         reset : function() {
3254             var t = this, d = t.doc;
3255
3256             if (d.firstChild)
3257                 d.removeChild(d.firstChild);
3258
3259             t.node = d.appendChild(d.createElement("html"));
3260         },
3261
3262         writeStartElement : function(n) {
3263             var t = this;
3264
3265             t.node = t.node.appendChild(t.doc.createElement(n));
3266         },
3267
3268         writeAttribute : function(n, v) {
3269             if (this.valid)
3270                 v = v.replace(/>/g, '%MCGT%');
3271
3272             this.node.setAttribute(n, v);
3273         },
3274
3275         writeEndElement : function() {
3276             this.node = this.node.parentNode;
3277         },
3278
3279         writeFullEndElement : function() {
3280             var t = this, n = t.node;
3281
3282             n.appendChild(t.doc.createTextNode(""));
3283             t.node = n.parentNode;
3284         },
3285
3286         writeText : function(v) {
3287             if (this.valid)
3288                 v = v.replace(/>/g, '%MCGT%');
3289
3290             this.node.appendChild(this.doc.createTextNode(v));
3291         },
3292
3293         writeCDATA : function(v) {
3294             this.node.appendChild(this.doc.createCDATA(v));
3295         },
3296
3297         writeComment : function(v) {
3298             this.node.appendChild(this.doc.createComment(v));
3299         },
3300
3301         getContent : function() {
3302             var h;
3303
3304             h = this.doc.xml || new XMLSerializer().serializeToString(this.doc);
3305             h = h.replace(/<\?[^?]+\?>|<html>|<\/html>|<html\/>|<!DOCTYPE[^>]+>/g, '');
3306             h = h.replace(/ ?\/>/g, ' />');
3307
3308             if (this.valid)
3309                 h = h.replace(/\%MCGT%/g, '&gt;');
3310
3311             return h;
3312         }
3313
3314         });
3315 })();
3316
3317 /* file:jscripts/tiny_mce/classes/dom/StringWriter.js */
3318
3319 (function() {
3320     tinymce.create('tinymce.dom.StringWriter', {
3321         str : null,
3322         tags : null,
3323         count : 0,
3324         settings : null,
3325         indent : null,
3326
3327         StringWriter : function(s) {
3328             this.settings = tinymce.extend({
3329                 indent_char : ' ',
3330                 indentation : 1
3331             }, s);
3332
3333             this.reset();
3334         },
3335
3336         reset : function() {
3337             this.indent = '';
3338             this.str = "";
3339             this.tags = [];
3340             this.count = 0;
3341         },
3342
3343         writeStartElement : function(n) {
3344             this._writeAttributesEnd();
3345             this.writeRaw('<' + n);
3346             this.tags.push(n);
3347             this.inAttr = true;
3348             this.count++;
3349             this.elementCount = this.count;
3350         },
3351
3352         writeAttribute : function(n, v) {
3353             var t = this;
3354
3355             t.writeRaw(" " + t.encode(n) + '="' + t.encode(v) + '"');
3356         },
3357
3358         writeEndElement : function() {
3359             var n;
3360
3361             if (this.tags.length > 0) {
3362                 n = this.tags.pop();
3363
3364                 if (this._writeAttributesEnd(1))
3365                     this.writeRaw('</' + n + '>');
3366
3367                 if (this.settings.indentation > 0)
3368                     this.writeRaw('\n');
3369             }
3370         },
3371
3372         writeFullEndElement : function() {
3373             if (this.tags.length > 0) {
3374                 this._writeAttributesEnd();
3375                 this.writeRaw('</' + this.tags.pop() + '>');
3376
3377                 if (this.settings.indentation > 0)
3378                     this.writeRaw('\n');
3379             }
3380         },
3381
3382         writeText : function(v) {
3383             this._writeAttributesEnd();
3384             this.writeRaw(this.encode(v));
3385             this.count++;
3386         },
3387
3388         writeCDATA : function(v) {
3389             this._writeAttributesEnd();
3390             this.writeRaw('<![CDATA[' + v + ']]>');
3391             this.count++;
3392         },
3393
3394         writeComment : function(v) {
3395             this._writeAttributesEnd();
3396             this.writeRaw('<!-- ' + v + '-->');
3397             this.count++;
3398         },
3399
3400         writeRaw : function(v) {
3401             this.str += v;
3402         },
3403
3404         encode : function(s) {
3405             return s.replace(/[<>&"]/g, function(v) {
3406                 switch (v) {
3407                     case '<':
3408                         return '&lt;';
3409
3410                     case '>':
3411                         return '&gt;';
3412
3413                     case '&':
3414                         return '&amp;';
3415
3416                     case '"':
3417                         return '&quot;';
3418                 }
3419
3420                 return v;
3421             });
3422         },
3423
3424         getContent : function() {
3425             return this.str;
3426         },
3427
3428         _writeAttributesEnd : function(s) {
3429             if (!this.inAttr)
3430                 return;
3431
3432             this.inAttr = false;
3433
3434             if (s && this.elementCount == this.count) {
3435                 this.writeRaw(' />');
3436                 return false;
3437             }
3438
3439             this.writeRaw('>');
3440
3441             return true;
3442         }
3443
3444         });
3445 })();
3446
3447 /* file:jscripts/tiny_mce/classes/dom/Serializer.js */
3448
3449 (function() {
3450     // Shorten names
3451     var extend = tinymce.extend, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, isIE = tinymce.isIE, isGecko = tinymce.isGecko;
3452
3453     // Returns only attribites that have values not all attributes in IE
3454     function getIEAtts(n) {
3455         var o = [];
3456
3457         // Object will throw exception in IE
3458         if (n.nodeName == 'OBJECT')
3459             return n.attributes;
3460
3461         n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi, function(a, b) {
3462             o.push({specified : 1, nodeName : b});
3463         });
3464
3465         return o;
3466     };
3467
3468     function wildcardToRE(s) {
3469         return s.replace(/([?+*])/g, '.$1');
3470     };
3471
3472     tinymce.create('tinymce.dom.Serializer', {
3473         Serializer : function(s) {
3474             var t = this;
3475
3476             t.key = 0;
3477             t.onPreProcess = new Dispatcher(t);
3478             t.onPostProcess = new Dispatcher(t);
3479
3480             if (tinymce.relaxedDomain && tinymce.isGecko) {
3481                 // Gecko has a bug where we can't create a new XML document if domain relaxing is used
3482                 t.writer = new tinymce.dom.StringWriter();
3483             } else {
3484                 try {
3485                     t.writer = new tinymce.dom.XMLWriter();
3486                 } catch (ex) {
3487                     // IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter
3488                     t.writer = new tinymce.dom.StringWriter();
3489                 }
3490             }
3491
3492             // Default settings
3493             t.settings = s = extend({
3494                 dom : tinymce.DOM,
3495                 valid_nodes : 0,
3496                 node_filter : 0,
3497                 attr_filter : 0,
3498                 invalid_attrs : /^(mce_|_moz_)/,
3499                 closed : /(br|hr|input|meta|img|link|param)/,
3500                 entity_encoding : 'named',
3501                 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',
3502                 valid_elements : '*[*]',
3503                 extended_valid_elements : 0,
3504                 valid_child_elements : 0,
3505                 invalid_elements : 0,
3506                 fix_table_elements : 0,
3507                 fix_list_elements : true,
3508                 fix_content_duplication : true,
3509                 convert_fonts_to_spans : false,
3510                 font_size_classes : 0,
3511                 font_size_style_values : 0,
3512                 apply_source_formatting : 0,
3513                 indent_mode : 'simple',
3514                 indent_char : '\t',
3515                 indent_levels : 1,
3516                 remove_linebreaks : 1
3517             }, s);
3518
3519             t.dom = s.dom;
3520
3521             if (s.fix_list_elements) {
3522                 t.onPreProcess.add(function(se, o) {
3523                     var nl, x, a = ['ol', 'ul'], i, n, p, r = /^(OL|UL)$/, np;
3524
3525                     function prevNode(e, n) {
3526                         var a = n.split(','), i;
3527
3528                         while ((e = e.previousSibling) != null) {
3529                             for (i=0; i<a.length; i++) {
3530                                 if (e.nodeName == a[i])
3531                                     return e;
3532                             }
3533                         }
3534
3535                         return null;
3536                     };
3537
3538                     for (x=0; x<a.length; x++) {
3539                         nl = t.dom.select(a[x], o.node);
3540
3541                         for (i=0; i<nl.length; i++) {
3542                             n = nl[i];
3543                             p = n.parentNode;
3544
3545                             if (r.test(p.nodeName)) {
3546                                 np = prevNode(n, 'LI');
3547
3548                                 if (!np) {
3549                                     np = t.dom.create('li');
3550                                     np.innerHTML = '&nbsp;';
3551                                     np.appendChild(n);
3552                                     p.insertBefore(np, p.firstChild);
3553                                 } else
3554                                     np.appendChild(n);
3555                             }
3556                         }
3557                     }
3558                 });
3559             }
3560
3561             if (s.fix_table_elements) {
3562                 t.onPreProcess.add(function(se, o) {
3563                     each(t.dom.select('table', o.node), function(e) {
3564                         var pa = t.dom.getParent(e, 'H1,H2,H3,H4,H5,H6,P'), pa2, n, tm, pl = [], i, ns;
3565
3566                         if (pa) {
3567                             pa2 = pa.cloneNode(false);
3568
3569                             pl.push(e);
3570                             for (n = e; n = n.parentNode;) {
3571                                 pl.push(n);
3572
3573                                 if (n == pa)
3574                                     break;
3575                             }
3576
3577                             tm = pa2;
3578                             for (i = pl.length - 1; i >= 0; i--) {
3579                                 if (i == pl.length - 1) {
3580                                     while (ns = pl[i - 1].nextSibling)
3581                                         tm.appendChild(ns.parentNode.removeChild(ns));
3582                                 } else {
3583                                     n = pl[i].cloneNode(false);
3584
3585                                     if (i != 0) {
3586                                         while (ns = pl[i - 1].nextSibling)
3587                                             n.appendChild(ns.parentNode.removeChild(ns));
3588                                     }
3589
3590                                     tm = tm.appendChild(n);
3591                                 }
3592                             }
3593
3594                             e = t.dom.insertAfter(e.parentNode.removeChild(e), pa);
3595                             t.dom.insertAfter(e, pa);
3596                             t.dom.insertAfter(pa2, e);
3597                         }
3598                     });
3599                 });
3600             }
3601         },
3602
3603         setEntities : function(s) {
3604             var t = this, a, i, l = {}, re = '', v;
3605
3606             // No need to setup more than once
3607             if (t.entityLookup)
3608                 return;
3609
3610             // Build regex and lookup array
3611             a = s.split(',');
3612             for (i = 0; i < a.length; i += 2) {
3613                 v = a[i];
3614
3615                 // Don't add default &amp; &quot; etc.
3616                 if (v == 34 || v == 38 || v == 60 || v == 62)
3617                     continue;
3618
3619                 l[String.fromCharCode(a[i])] = a[i + 1];
3620
3621                 v = parseInt(a[i]).toString(16);
3622                 re += '\\u' + '0000'.substring(v.length) + v;
3623             }
3624
3625             if (!re) {
3626                 t.settings.entity_encoding = 'raw';
3627                 return;
3628             }
3629
3630             t.entitiesRE = new RegExp('[' + re + ']', 'g');
3631             t.entityLookup = l;
3632         },
3633
3634         setValidChildRules : function(s) {
3635             this.childRules = null;
3636             this.addValidChildRules(s);
3637         },
3638
3639         addValidChildRules : function(s) {
3640             var t = this, inst, intr, bloc;
3641
3642             if (!s)
3643                 return;
3644
3645             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';
3646             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';
3647             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';
3648
3649             each(s.split(','), function(s) {
3650                 var p = s.split(/\[|\]/), re;
3651
3652                 s = '';
3653                 each(p[1].split('|'), function(v) {
3654                     if (s)
3655                         s += '|';
3656
3657                     switch (v) {
3658                         case '%itrans':
3659                             v = intr;
3660                             break;
3661
3662                         case '%itrans_na':
3663                             v = intr.substring(2);
3664                             break;
3665
3666                         case '%istrict':
3667                             v = inst;
3668                             break;
3669
3670                         case '%istrict_na':
3671                             v = inst.substring(2);
3672                             break;
3673
3674                         case '%btrans':
3675                             v = bloc;
3676                             break;
3677
3678                         case '%bstrict':
3679                             v = bloc;
3680                             break;
3681                     }
3682
3683                     s += v;
3684                 });
3685                 re = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
3686
3687                 each(p[0].split('/'), function(s) {
3688                     t.childRules = t.childRules || {};
3689                     t.childRules[s] = re;
3690                 });
3691             });
3692
3693             // Build regex
3694             s = '';
3695             each(t.childRules, function(v, k) {
3696                 if (s)
3697                     s += '|';
3698
3699                 s += k;
3700             });
3701
3702             t.parentElementsRE = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
3703
3704             /*console.debug(t.parentElementsRE.toString());
3705             each(t.childRules, function(v) {
3706                 console.debug(v.toString());
3707             });*/
3708         },
3709
3710         setRules : function(s) {
3711             var t = this;
3712
3713             t._setup();
3714             t.rules = {};
3715             t.wildRules = [];
3716             t.validElements = {};
3717
3718             return t.addRules(s);
3719         },
3720
3721         addRules : function(s) {
3722             var t = this, dr;
3723
3724             if (!s)
3725                 return;
3726
3727             t._setup();
3728
3729             each(s.split(','), function(s) {
3730                 var p = s.split(/\[|\]/), tn = p[0].split('/'), ra, at, wat, va = [];
3731
3732                 // Extend with default rules
3733                 if (dr)
3734                     at = tinymce.extend([], dr.attribs);
3735
3736                 // Parse attributes
3737                 if (p.length > 1) {
3738                     each(p[1].split('|'), function(s) {
3739                         var ar = {}, i;
3740
3741                         at = at || [];
3742
3743                         // Parse attribute rule
3744                         s = s.replace(/::/g, '~');
3745                         s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(s);
3746                         s[2] = s[2].replace(/~/g, ':');
3747
3748                         // Add required attributes
3749                         if (s[1] == '!') {
3750                             ra = ra || [];
3751                             ra.push(s[2]);
3752                         }
3753
3754                         // Remove inherited attributes
3755                         if (s[1] == '-') {
3756                             for (i = 0; i <at.length; i++) {
3757                                 if (at[i].name == s[2]) {
3758                                     at.splice(i, 1);
3759                                     return;
3760                                 }
3761                             }
3762                         }
3763
3764                         switch (s[3]) {
3765                             // Add default attrib values
3766                             case '=':
3767                                 ar.defaultVal = s[4] || '';
3768                                 break;
3769
3770                             // Add forced attrib values
3771                             case ':':
3772                                 ar.forcedVal = s[4];
3773                                 break;
3774
3775                             // Add validation values
3776                             case '<':
3777                                 ar.validVals = s[4].split('?');
3778                                 break;
3779                         }
3780
3781                         if (/[*.?]/.test(s[2])) {
3782                             wat = wat || [];
3783                             ar.nameRE = new RegExp('^' + wildcardToRE(s[2]) + '$');
3784                             wat.push(ar);
3785                         } else {
3786                             ar.name = s[2];
3787                             at.push(ar);
3788                         }
3789
3790                         va.push(s[2]);
3791                     });
3792                 }
3793
3794                 // Handle element names
3795                 each(tn, function(s, i) {
3796                     var pr = s.charAt(0), x = 1, ru = {};
3797
3798                     // Extend with default rule data
3799                     if (dr) {
3800                         if (dr.noEmpty)
3801                             ru.noEmpty = dr.noEmpty;
3802
3803                         if (dr.fullEnd)
3804                             ru.fullEnd = dr.fullEnd;
3805
3806                         if (dr.padd)
3807                             ru.padd = dr.padd;
3808                     }
3809
3810                     // Handle prefixes
3811                     switch (pr) {
3812                         case '-':
3813                             ru.noEmpty = true;
3814                             break;
3815
3816                         case '+':
3817                             ru.fullEnd = true;
3818                             break;
3819
3820                         case '#':
3821                             ru.padd = true;
3822                             break;
3823
3824                         default:
3825                             x = 0;
3826                     }
3827
3828                     tn[i] = s = s.substring(x);
3829                     t.validElements[s] = 1;
3830
3831                     // Add element name or element regex
3832                     if (/[*.?]/.test(tn[0])) {
3833                         ru.nameRE = new RegExp('^' + wildcardToRE(tn[0]) + '$');
3834                         t.wildRules = t.wildRules || {};
3835                         t.wildRules.push(ru);
3836                     } else {
3837                         ru.name = tn[0];
3838
3839                         // Store away default rule
3840                         if (tn[0] == '@')
3841                             dr = ru;
3842
3843                         t.rules[s] = ru;
3844                     }
3845
3846                     ru.attribs = at;
3847
3848                     if (ra)
3849                         ru.requiredAttribs = ra;
3850
3851                     if (wat) {
3852                         // Build valid attributes regexp
3853                         s = '';
3854                         each(va, function(v) {
3855                             if (s)
3856                                 s += '|';
3857
3858                             s += '(' + wildcardToRE(v) + ')';
3859                         });
3860                         ru.validAttribsRE = new RegExp('^' + s.toLowerCase() + '$');
3861                         ru.wildAttribs = wat;
3862                     }
3863                 });
3864             });
3865
3866             // Build valid elements regexp
3867             s = '';
3868             each(t.validElements, function(v, k) {
3869                 if (s)
3870                     s += '|';
3871
3872                 if (k != '@')
3873                     s += k;
3874             });
3875             t.validElementsRE = new RegExp('^(' + wildcardToRE(s.toLowerCase()) + ')$');
3876
3877             //console.debug(t.validElementsRE.toString());
3878             //console.dir(t.rules);
3879             //console.dir(t.wildRules);
3880         },
3881
3882         findRule : function(n) {
3883             var t = this, rl = t.rules, i, r;
3884
3885             t._setup();
3886
3887             // Exact match
3888             r = rl[n];
3889             if (r)
3890                 return r;
3891
3892             // Try wildcards
3893             rl = t.wildRules;
3894             for (i = 0; i < rl.length; i++) {
3895                 if (rl[i].nameRE.test(n))
3896                     return rl[i];
3897             }
3898
3899             return null;
3900         },
3901
3902         findAttribRule : function(ru, n) {
3903             var i, wa = ru.wildAttribs;
3904
3905             for (i = 0; i < wa.length; i++) {
3906                 if (wa[i].nameRE.test(n))
3907                     return wa[i];
3908             }
3909
3910             return null;
3911         },
3912
3913         serialize : function(n, o) {
3914             var h, t = this;
3915
3916             t._setup();
3917             o = o || {};
3918             o.format = o.format || 'html';
3919             t.processObj = o;
3920             n = n.cloneNode(true);
3921             t.key = '' + (parseInt(t.key) + 1);
3922
3923             // Pre process
3924             if (!o.no_events) {
3925                 o.node = n;
3926                 t.onPreProcess.dispatch(t, o);
3927             }
3928
3929             // Serialize HTML DOM into a string
3930             t.writer.reset();
3931             t._serializeNode(n, o.getInner);
3932
3933             // Post process
3934             o.content = t.writer.getContent();
3935
3936             if (!o.no_events)
3937                 t.onPostProcess.dispatch(t, o);
3938
3939             t._postProcess(o);
3940             o.node = null;
3941
3942             return tinymce.trim(o.content);
3943         },
3944
3945         // Internal functions
3946
3947         _postProcess : function(o) {
3948             var t = this, s = t.settings, h = o.content, sc = [], p, l;
3949
3950             if (o.format == 'html') {
3951                 // Protect some elements
3952                 p = t._protect({
3953                     content : h,
3954                     patterns : [
3955                         /(<script[^>]*>)(.*?)(<\/script>)/g,
3956                         /(<style[^>]*>)(.*?)(<\/style>)/g,
3957                         /(<pre[^>]*>)(.*?)(<\/pre>)/g
3958                     ]
3959                 });
3960
3961                 h = p.content;
3962
3963                 // Entity encode
3964                 if (s.entity_encoding !== 'raw') {
3965                     if (s.entity_encoding.indexOf('named') != -1) {
3966                         t.setEntities(s.entities);
3967                         l = t.entityLookup;
3968
3969                         h = h.replace(t.entitiesRE, function(a) {
3970                             var v;
3971
3972                             if (v = l[a])
3973                                 a = '&' + v + ';';
3974
3975                             return a;
3976                         });
3977                     }
3978
3979                     if (s.entity_encoding.indexOf('numeric') != -1) {
3980                         h = h.replace(/[\u007E-\uFFFF]/g, function(a) {
3981                             return '&#' + a.charCodeAt(0) + ';';
3982                         });
3983                     }
3984                 }
3985
3986                 // Use BR instead of &nbsp; padded P elements inside editor and use <p>&nbsp;</p> outside editor
3987 /*                if (o.set)
3988                     h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p><br /></p>');
3989                 else
3990                     h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p>$1</p>');*/
3991
3992                 // Since Gecko and Safari keeps whitespace in the DOM we need to
3993                 // remove it inorder to match other browsers. But I think Gecko and Safari is right.
3994                 // This process is only done when getting contents out from the editor.
3995                 if (!o.set) {
3996                     // We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char
3997                     h = h.replace(/<p>\s+<\/p>|<p([^>]+)>\s+<\/p>/g, s.entity_encoding == 'numeric' ? '<p$1>&#160;</p>' : '<p$1>&nbsp;</p>');
3998
3999                     if (s.remove_linebreaks) {
4000                         h = h.replace(/\r?\n|\r/g, ' ');
4001                         h = h.replace(/(<[^>]+>)\s+/g, '$1 ');
4002                         h = h.replace(/\s+(<\/[^>]+>)/g, ' $1');
4003                         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
4004                         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
4005                         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
4006                     }
4007
4008                     // Simple indentation
4009                     if (s.apply_source_formatting && s.indent_mode == 'simple') {
4010                         // Add line breaks before and after block elements
4011                         h = h.replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n');
4012                         h = h.replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>');
4013                         h = h.replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '</$1>\n');
4014                         h = h.replace(/\n\n/g, '\n');
4015                     }
4016                 }
4017
4018                 h = t._unprotect(h, p);
4019
4020                 // Restore the \u00a0 character if raw mode is enabled
4021                 if (s.entity_encoding == 'raw')
4022                     h = h.replace(/<p>&nbsp;<\/p>|<p([^>]+)>&nbsp;<\/p>/g, '<p$1>\u00a0</p>');
4023             }
4024
4025             o.content = h;
4026         },
4027
4028         _serializeNode : function(n, inn) {
4029             var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv;
4030
4031             if (!s.node_filter || s.node_filter(n)) {
4032                 switch (n.nodeType) {
4033                     case 1: // Element
4034                         if (n.hasAttribute ? n.hasAttribute('mce_bogus') : n.getAttribute('mce_bogus'))
4035                             return;
4036
4037                         iv = false;
4038                         hc = n.hasChildNodes();
4039                         nn = n.getAttribute('mce_name') || n.nodeName.toLowerCase();
4040
4041                         // Add correct prefix on IE
4042                         if (isIE) {
4043                             if (n.scopeName !== 'HTML' && n.scopeName !== 'html')
4044                                 nn = n.scopeName + ':' + nn;
4045                         }
4046
4047                         // Remove mce prefix on IE needed for the abbr element
4048                         if (nn.indexOf('mce:') === 0)
4049                             nn = nn.substring(4);
4050
4051                         // Check if valid
4052                         if (!t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) {
4053                             iv = true;
4054                             break;
4055                         }
4056
4057                         if (isIE) {
4058                             // Fix IE content duplication (DOM can have multiple copies of the same node)
4059                             if (s.fix_content_duplication) {
4060                                 if (n.mce_serialized == t.key)
4061                                     return;
4062
4063                                 n.mce_serialized = t.key;
4064                             }
4065
4066                             // IE sometimes adds a / infront of the node name
4067                             if (nn.charAt(0) == '/')
4068                                 nn = nn.substring(1);
4069                         } else if (isGecko) {
4070                             // Ignore br elements
4071                             if (n.nodeName === 'BR' && n.getAttribute('type') == '_moz')
4072                                 return;
4073                         }
4074
4075                         // Check if valid child
4076                         if (t.childRules) {
4077                             if (t.parentElementsRE.test(t.elementName)) {
4078                                 if (!t.childRules[t.elementName].test(nn)) {
4079                                     iv = true;
4080                                     break;
4081                                 }
4082                             }
4083
4084                             t.elementName = nn;
4085                         }
4086
4087                         ru = t.findRule(nn);
4088                         nn = ru.name || nn;
4089
4090                         // Skip empty nodes or empty node name in IE
4091                         if ((!hc && ru.noEmpty) || (isIE && !nn)) {
4092                             iv = true;
4093                             break;
4094                         }
4095
4096                         // Check required
4097                         if (ru.requiredAttribs) {
4098                             a = ru.requiredAttribs;
4099
4100                             for (i = a.length - 1; i >= 0; i--) {
4101                                 if (this.dom.getAttrib(n, a[i]) !== '')
4102                                     break;
4103                             }
4104
4105                             // None of the required was there
4106                             if (i == -1) {
4107                                 iv = true;
4108                                 break;
4109                             }
4110                         }
4111
4112                         w.writeStartElement(nn);
4113
4114                         // Add ordered attributes
4115                         if (ru.attribs) {
4116                             for (i=0, at = ru.attribs, l = at.length; i<l; i++) {
4117                                 a = at[i];
4118                                 v = t._getAttrib(n, a);
4119
4120                                 if (v !== null)
4121                                     w.writeAttribute(a.name, v);
4122                             }
4123                         }
4124
4125                         // Add wild attributes
4126                         if (ru.validAttribsRE) {
4127                             at = isIE ? getIEAtts(n) : n.attributes;
4128                             for (i=at.length-1; i>-1; i--) {
4129                                 no = at[i];
4130
4131                                 if (no.specified) {
4132                                     a = no.nodeName.toLowerCase();
4133
4134                                     if (s.invalid_attrs.test(a) || !ru.validAttribsRE.test(a))
4135                                         continue;
4136
4137                                     ar = t.findAttribRule(ru, a);
4138                                     v = t._getAttrib(n, ar, a);
4139
4140                                     if (v !== null)
4141                                         w.writeAttribute(a, v);
4142                                 }
4143                             }
4144                         }
4145
4146                         // Padd empty nodes with a &nbsp;
4147                         if (!hc && ru.padd)
4148                             w.writeText('\u00a0');
4149
4150                         break;
4151
4152                     case 3: // Text
4153                         // Check if valid child
4154                         if (t.childRules && t.parentElementsRE.test(t.elementName)) {
4155                             if (!t.childRules[t.elementName].test(n.nodeName))
4156                                 return;
4157                         }
4158
4159                         return w.writeText(n.nodeValue);
4160
4161                     case 4: // CDATA
4162                         return w.writeCDATA(n.nodeValue);
4163
4164                     case 8: // Comment
4165                         return w.writeComment(n.nodeValue);
4166                 }
4167             } else if (n.nodeType == 1)
4168                 hc = n.hasChildNodes();
4169
4170             if (hc) {
4171                 cn = n.firstChild;
4172
4173                 while (cn) {
4174                     t._serializeNode(cn);
4175                     t.elementName = nn;
4176                     cn = cn.nextSibling;
4177                 }
4178             }
4179
4180             // Write element end
4181             if (!iv) {
4182                 if (hc || !s.closed.test(nn))
4183                     w.writeFullEndElement();
4184                 else
4185                     w.writeEndElement();
4186             }
4187         },
4188
4189         _protect : function(o) {
4190             o.items = o.items || [];
4191
4192             function enc(s) {
4193                 return s.replace(/[\r\n\\]/g, function(c) {
4194                     if (c === '\n')
4195                         return '\\n';
4196                     else if (c === '\\')
4197                         return '\\\\';
4198
4199                     return '\\r';
4200                 });
4201             };
4202
4203             function dec(s) {
4204                 return s.replace(/\\[\\rn]/g, function(c) {
4205                     if (c === '\\n')
4206                         return '\n';
4207                     else if (c === '\\\\')
4208                         return '\\';
4209
4210                     return '\r';
4211                 });
4212             };
4213
4214             each(o.patterns, function(p) {
4215                 o.content = dec(enc(o.content).replace(p, function(x, a, b, c) {
4216                     o.items.push(dec(b));
4217                     return a + '<!--mce:' + (o.items.length - 1) + '-->' + c;
4218                 }));
4219             });
4220
4221             return o;
4222         },
4223
4224         _unprotect : function(h, o) {
4225             h = h.replace(/\<!--mce:([0-9]+)--\>/g, function(a, b) {
4226                 return o.items[parseInt(b)];
4227             });
4228
4229             o.items = [];
4230
4231             return h;
4232         },
4233
4234         _setup : function() {
4235             var t = this, s = this.settings;
4236
4237             if (t.done)
4238                 return;
4239
4240             t.done = 1;
4241
4242             t.setRules(s.valid_elements);
4243             t.addRules(s.extended_valid_elements);
4244             t.addValidChildRules(s.valid_child_elements);
4245
4246             if (s.invalid_elements)
4247                 t.invalidElementsRE = new RegExp('^(' + wildcardToRE(s.invalid_elements.replace(',', '|').toLowerCase()) + ')$');
4248
4249             if (s.attrib_value_filter)
4250                 t.attribValueFilter = s.attribValueFilter;
4251         },
4252
4253         _getAttrib : function(n, a, na) {
4254             var i, v;
4255
4256             na = na || a.name;
4257
4258             if (a.forcedVal && (v = a.forcedVal)) {
4259                 if (v === '{$uid}')
4260                     return this.dom.uniqueId();
4261
4262                 return v;
4263             }
4264
4265             v = this.dom.getAttrib(n, na);
4266
4267             switch (na) {
4268                 case 'rowspan':
4269                 case 'colspan':
4270                     // Whats the point? Remove usless attribute value
4271                     if (v == '1')
4272                         v = '';
4273
4274                     break;
4275             }
4276
4277             if (this.attribValueFilter)
4278                 v = this.attribValueFilter(na, v, n);
4279
4280             if (a.validVals) {
4281                 for (i = a.validVals.length - 1; i >= 0; i--) {
4282                     if (v == a.validVals[i])
4283                         break;
4284                 }
4285
4286                 if (i == -1)
4287                     return null;
4288             }
4289
4290             if (v === '' && typeof(a.defaultVal) != 'undefined') {
4291                 v = a.defaultVal;
4292
4293                 if (v === '{$uid}')
4294                     return this.dom.uniqueId();
4295
4296                 return v;
4297             } else {
4298                 // Remove internal mceItemXX classes when content is extracted from editor
4299                 if (na == 'class' && this.processObj.get)
4300                     v = v.replace(/\s?mceItem\w+\s?/g, '');
4301             }
4302
4303             if (v === '')
4304                 return null;
4305
4306
4307             return v;
4308         }
4309
4310         });
4311 })();
4312
4313 /* file:jscripts/tiny_mce/classes/dom/ScriptLoader.js */
4314
4315 (function() {
4316     var each = tinymce.each;
4317
4318     tinymce.create('tinymce.dom.ScriptLoader', {
4319         ScriptLoader : function(s) {
4320             this.settings = s || {};
4321             this.queue = [];
4322             this.lookup = {};
4323         },
4324
4325         isDone : function(u) {
4326             return this.lookup[u] ? this.lookup[u].state == 2 : 0;
4327         },
4328
4329         markDone : function(u) {
4330             this.lookup[u] = {state : 2, url : u};
4331         },
4332
4333         add : function(u, cb, s, pr) {
4334             var t = this, lo = t.lookup, o;
4335
4336             if (o = lo[u]) {
4337                 // Is loaded fire callback
4338                 if (cb && o.state == 2)
4339                     cb.call(s || this);
4340
4341                 return o;
4342             }
4343
4344             o = {state : 0, url : u, func : cb, scope : s || this};
4345
4346             if (pr)
4347                 t.queue.unshift(o);
4348             else
4349                 t.queue.push(o);
4350
4351             lo[u] = o;
4352
4353             return o;
4354         },
4355
4356         load : function(u, cb, s) {
4357             var t = this, o;
4358
4359             if (o = t.lookup[u]) {
4360                 // Is loaded fire callback
4361                 if (cb && o.state == 2)
4362                     cb.call(s || t);
4363
4364                 return o;
4365             }
4366
4367             function loadScript(u) {
4368                 if (tinymce.dom.Event.domLoaded || t.settings.strict_mode) {
4369                     tinymce.util.XHR.send({
4370                         url : u,
4371                         error : t.settings.error,
4372                         async : false,
4373                         success : function(co) {
4374                             t.eval(co);
4375                         }
4376                     });
4377                 } else
4378                     document.write('<script type="text/javascript" src="' + u + '"></script>');
4379             };
4380
4381             if (!tinymce.is(u, 'string')) {
4382                 each(u, function(u) {
4383                     loadScript(u);
4384                 });
4385
4386                 if (cb)
4387                     cb.call(s || t);
4388             } else {
4389                 loadScript(u);
4390
4391                 if (cb)
4392                     cb.call(s || t);
4393             }
4394         },
4395
4396         loadQueue : function(cb, s) {
4397             var t = this;
4398
4399             if (!t.queueLoading) {
4400                 t.queueLoading = 1;
4401                 t.queueCallbacks = [];
4402
4403                 t.loadScripts(t.queue, function() {
4404                     t.queueLoading = 0;
4405
4406                     if (cb)
4407                         cb.call(s || t);
4408
4409                     each(t.queueCallbacks, function(o) {
4410                         o.func.call(o.scope);
4411                     });
4412                 });
4413             } else if (cb)
4414                 t.queueCallbacks.push({func : cb, scope : s || t});
4415         },
4416
4417         eval : function(co) {
4418             var w = window;
4419
4420             // Evaluate script
4421             if (!w.execScript) {
4422                 try {
4423                     eval.call(w, co);
4424                 } catch (ex) {
4425                     eval(co, w); // Firefox 3.0a8
4426                 }
4427             } else
4428                 w.execScript(co); // IE
4429         },
4430
4431         loadScripts : function(sc, cb, s) {
4432             var t = this, lo = t.lookup;
4433
4434             function done(o) {
4435                 o.state = 2; // Has been loaded
4436
4437                 // Run callback
4438                 if (o.func)
4439                     o.func.call(o.scope || t);
4440             };
4441
4442             function allDone() {
4443                 var l;
4444
4445                 // Check if all files are loaded
4446                 l = sc.length;
4447                 each(sc, function(o) {
4448                     o = lo[o.url];
4449
4450                     if (o.state === 2) {// It has finished loading
4451                         done(o);
4452                         l--;
4453                     } else
4454                         load(o);
4455                 });
4456
4457                 // They are all loaded
4458                 if (l === 0 && cb) {
4459                     cb.call(s || t);
4460                     cb = 0;
4461                 }
4462             };
4463
4464             function load(o) {
4465                 if (o.state > 0)
4466                     return;
4467
4468                 o.state = 1; // Is loading
4469
4470                 tinymce.util.XHR.send({
4471                     url : o.url,
4472                     error : t.settings.error,
4473                     success : function(co) {
4474                         t.eval(co);
4475                         done(o);
4476                         allDone();
4477                     }
4478                 });
4479             };
4480
4481             each(sc, function(o) {
4482                 var u = o.url;
4483
4484                 // Add to queue if needed
4485                 if (!lo[u]) {
4486                     lo[u] = o;
4487                     t.queue.push(o);
4488                 } else
4489                     o = lo[u];
4490
4491                 // Is already loading or has been loaded
4492                 if (o.state > 0)
4493                     return;
4494
4495                 if (!tinymce.dom.Event.domLoaded && !t.settings.strict_mode) {
4496                     var ix, ol = '';
4497
4498                     // Add onload events
4499                     if (cb || o.func) {
4500                         o.state = 1; // Is loading
4501
4502                         ix = tinymce.dom.ScriptLoader._addOnLoad(function() {
4503                             done(o);
4504                             allDone();
4505                         });
4506
4507                         if (tinymce.isIE)
4508                             ol = ' onreadystatechange="';
4509                         else
4510                             ol = ' onload="';
4511
4512                         ol += 'tinymce.dom.ScriptLoader._onLoad(this,\'' + u + '\',' + ix + ');"';
4513                     }
4514
4515                     document.write('<script type="text/javascript" src="' + u + '"' + ol + '></script>');
4516
4517                     if (!o.func)
4518                         done(o);
4519                 } else
4520                     load(o);
4521             });
4522
4523             allDone();
4524         },
4525
4526         // Static methods
4527         'static' : {
4528             _addOnLoad : function(f) {
4529                 var t = this;
4530
4531                 t._funcs = t._funcs || [];
4532                 t._funcs.push(f);
4533
4534                 return t._funcs.length - 1;
4535             },
4536
4537             _onLoad : function(e, u, ix) {
4538                 if (!tinymce.isIE || e.readyState == 'complete')
4539                     this._funcs[ix].call(this);
4540             }
4541         }
4542
4543         });
4544
4545     // Global script loader
4546     tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
4547 })();
4548
4549 /* file:jscripts/tiny_mce/classes/ui/Control.js */
4550
4551 (function() {
4552     // Shorten class names
4553     var DOM = tinymce.DOM, is = tinymce.is;
4554
4555     tinymce.create('tinymce.ui.Control', {
4556         Control : function(id, s) {
4557             this.id = id;
4558             this.settings = s = s || {};
4559             this.rendered = false;
4560             this.onRender = new tinymce.util.Dispatcher(this);
4561             this.classPrefix = '';
4562             this.scope = s.scope || this;
4563             this.disabled = 0;
4564             this.active = 0;
4565         },
4566
4567         setDisabled : function(s) {
4568             var e;
4569
4570             if (s != this.disabled) {
4571                 e = DOM.get(this.id);
4572
4573                 // Add accessibility title for unavailable actions
4574                 if (e && this.settings.unavailable_prefix) {
4575                     if (s) {
4576                         this.prevTitle = e.title;
4577                         e.title = this.settings.unavailable_prefix + ": " + e.title;
4578                     } else
4579                         e.title = this.prevTitle;
4580                 }
4581
4582                 this.setState('Disabled', s);
4583                 this.setState('Enabled', !s);
4584                 this.disabled = s;
4585             }
4586         },
4587
4588         isDisabled : function() {
4589             return this.disabled;
4590         },
4591
4592         setActive : function(s) {
4593             if (s != this.active) {
4594                 this.setState('Active', s);
4595                 this.active = s;
4596             }
4597         },
4598
4599         isActive : function() {
4600             return this.active;
4601         },
4602
4603         setState : function(c, s) {
4604             var n = DOM.get(this.id);
4605
4606             c = this.classPrefix + c;
4607
4608             if (s)
4609                 DOM.addClass(n, c);
4610             else
4611                 DOM.removeClass(n, c);
4612         },
4613
4614         isRendered : function() {
4615             return this.rendered;
4616         },
4617
4618         renderHTML : function() {
4619         },
4620
4621         renderTo : function(n) {
4622             DOM.setHTML(n, this.renderHTML());
4623         },
4624
4625         postRender : function() {
4626             var t = this, b;
4627
4628             // Set pending states
4629             if (is(t.disabled)) {
4630                 b = t.disabled;
4631                 t.disabled = -1;
4632                 t.setDisabled(b);
4633             }
4634
4635             if (is(t.active)) {
4636                 b = t.active;
4637                 t.active = -1;
4638                 t.setActive(b);
4639             }
4640         },
4641
4642         remove : function() {
4643             DOM.remove(this.id);
4644             this.destroy();
4645         },
4646
4647         destroy : function() {
4648             tinymce.dom.Event.clear(this.id);
4649         }
4650
4651         });
4652 })();
4653 /* file:jscripts/tiny_mce/classes/ui/Container.js */
4654
4655 tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {
4656     Container : function(id, s) {
4657         this.parent(id, s);
4658         this.controls = [];
4659         this.lookup = {};
4660     },
4661
4662     add : function(c) {
4663         this.lookup[c.id] = c;
4664         this.controls.push(c);
4665
4666         return c;
4667     },
4668
4669     get : function(n) {
4670         return this.lookup[n];
4671     }
4672
4673     });
4674
4675
4676 /* file:jscripts/tiny_mce/classes/ui/Separator.js */
4677
4678 tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
4679     Separator : function(id, s) {
4680         this.parent(id, s);
4681         this.classPrefix = 'mceSeparator';
4682     },
4683
4684     renderHTML : function() {
4685         return tinymce.DOM.createHTML('span', {'class' : this.classPrefix});
4686     }
4687
4688     });
4689
4690 /* file:jscripts/tiny_mce/classes/ui/MenuItem.js */
4691
4692 (function() {
4693     var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
4694
4695     tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {
4696         MenuItem : function(id, s) {
4697             this.parent(id, s);
4698             this.classPrefix = 'mceMenuItem';
4699         },
4700
4701         setSelected : function(s) {
4702             this.setState('Selected', s);
4703             this.selected = s;
4704         },
4705
4706         isSelected : function() {
4707             return this.selected;
4708         },
4709
4710         postRender : function() {
4711             var t = this;
4712             
4713             t.parent();
4714
4715             // Set pending state
4716             if (is(t.selected))
4717                 t.setSelected(t.selected);
4718         }
4719
4720         });
4721 })();
4722
4723 /* file:jscripts/tiny_mce/classes/ui/Menu.js */
4724
4725 (function() {
4726     var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
4727
4728     tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {
4729         Menu : function(id, s) {
4730             var t = this;
4731
4732             t.parent(id, s);
4733             t.items = {};
4734             t.collapsed = false;
4735             t.menuCount = 0;
4736             t.onAddItem = new tinymce.util.Dispatcher(this);
4737         },
4738
4739         expand : function(d) {
4740             var t = this;
4741
4742             if (d) {
4743                 walk(t, function(o) {
4744                     if (o.expand)
4745                         o.expand();
4746                 }, 'items', t);
4747             }
4748
4749             t.collapsed = false;
4750         },
4751
4752         collapse : function(d) {
4753             var t = this;
4754
4755             if (d) {
4756                 walk(t, function(o) {
4757                     if (o.collapse)
4758                         o.collapse();
4759                 }, 'items', t);
4760             }
4761
4762             t.collapsed = true;
4763         },
4764
4765         isCollapsed : function() {
4766             return this.collapsed;
4767         },
4768
4769         add : function(o) {
4770             if (!o.settings)
4771                 o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);
4772
4773             this.onAddItem.dispatch(this, o);
4774
4775             return this.items[o.id] = o;
4776         },
4777
4778         addSeparator : function() {
4779             return this.add({separator : true});
4780         },
4781
4782         addMenu : function(o) {
4783             if (!o.collapse)
4784                 o = this.createMenu(o);
4785
4786             this.menuCount++;
4787
4788             return this.add(o);
4789         },
4790
4791         hasMenus : function() {
4792             return this.menuCount !== 0;
4793         },
4794
4795         remove : function(o) {
4796             delete this.items[o.id];
4797         },
4798
4799         removeAll : function() {
4800             var t = this;
4801
4802             walk(t, function(o) {
4803                 if (o.removeAll)
4804                     o.removeAll();
4805                 else
4806                     o.remove();
4807
4808                 o.destroy();
4809             }, 'items', t);
4810
4811             t.items = {};
4812         },
4813
4814         createMenu : function(o) {
4815             var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);
4816
4817             m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);
4818
4819             return m;
4820         }
4821
4822         });
4823 })();
4824 /* file:jscripts/tiny_mce/classes/ui/DropMenu.js */
4825
4826 (function() {
4827     var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;
4828
4829     tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {
4830         DropMenu : function(id, s) {
4831             s = s || {};
4832             s.container = s.container || DOM.doc.body;
4833             s.offset_x = s.offset_x || 0;
4834             s.offset_y = s.offset_y || 0;
4835             s.vp_offset_x = s.vp_offset_x || 0;
4836             s.vp_offset_y = s.vp_offset_y || 0;
4837
4838             if (is(s.icons) && !s.icons)
4839                 s['class'] += ' mceNoIcons';
4840
4841             this.parent(id, s);
4842             this.onShowMenu = new tinymce.util.Dispatcher(this);
4843             this.onHideMenu = new tinymce.util.Dispatcher(this);
4844             this.classPrefix = 'mceMenu';
4845
4846             // Fix for odd IE bug: #1903622
4847             this.fixIE = tinymce.isIE && DOM.win.top != DOM.win;
4848         },
4849
4850         createMenu : function(s) {
4851             var t = this, cs = t.settings, m;
4852
4853             s.container = s.container || cs.container;
4854             s.parent = t;
4855             s.constrain = s.constrain || cs.constrain;
4856             s['class'] = s['class'] || cs['class'];
4857             s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;
4858             s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;
4859             m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);
4860
4861             m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);
4862
4863             return m;
4864         },
4865
4866         update : function() {
4867             var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
4868
4869             tw = s.max_width ? Math.min(tb.clientWidth, s.max_width) : tb.clientWidth;
4870             th = s.max_height ? Math.min(tb.clientHeight, s.max_height) : tb.clientHeight;
4871
4872             if (!DOM.boxModel)
4873                 t.element.setStyles({width : tw + 2, height : th + 2});
4874             else
4875                 t.element.setStyles({width : tw, height : th});
4876
4877             if (s.max_width)
4878                 DOM.setStyle(co, 'width', tw);
4879
4880             if (s.max_height) {
4881                 DOM.setStyle(co, 'height', th);
4882
4883                 if (tb.clientHeight < s.max_height)
4884                     DOM.setStyle(co, 'overflow', 'hidden');
4885             }
4886         },
4887
4888         showMenu : function(x, y, px) {
4889             var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;
4890
4891             t.collapse(1);
4892
4893             if (t.isMenuVisible)
4894                 return;
4895
4896             if (!t.rendered) {
4897                 co = DOM.add(t.settings.container, t.renderNode());
4898
4899                 each(t.items, function(o) {
4900                     o.postRender();
4901                 });
4902
4903                 t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
4904             } else
4905                 co = DOM.get('menu_' + t.id);
4906
4907             // Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
4908             if (!tinymce.isOpera)
4909                 DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});
4910
4911             DOM.show(co);
4912             t.update();
4913
4914             x += s.offset_x || 0;
4915             y += s.offset_y || 0;
4916             vp.w -= 4;
4917             vp.h -= 4;
4918
4919             // Move inside viewport if not submenu
4920             if (s.constrain) {
4921                 w = co.clientWidth - ot;
4922                 h = co.clientHeight - ot;
4923                 mx = vp.x + vp.w;
4924                 my = vp.y + vp.h;
4925
4926                 if ((x + s.vp_offset_x + w) > mx)
4927                     x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);
4928
4929                 if ((y + s.vp_offset_y + h) > my)
4930                     y = Math.max(0, (my - s.vp_offset_y) - h);
4931             }
4932
4933             DOM.setStyles(co, {left : x , top : y});
4934             t.element.update();
4935
4936             t.isMenuVisible = 1;
4937             t.mouseClickFunc = Event.add(co, t.fixIE ? 'mousedown' : 'click', function(e) {
4938                 var m;
4939
4940                 e = e.target;
4941
4942                 if (e && (e = DOM.getParent(e, 'TR')) && !DOM.hasClass(e, cp + 'ItemSub')) {
4943                     m = t.items[e.id];
4944
4945                     if (m.isDisabled())
4946                         return;
4947
4948                     dm = t;
4949
4950                     while (dm) {
4951                         if (dm.hideMenu)
4952                             dm.hideMenu();
4953
4954                         dm = dm.settings.parent;
4955                     }
4956
4957                     if (m.settings.onclick)
4958                         m.settings.onclick(e);
4959
4960                     return Event.cancel(e); // Cancel to fix onbeforeunload problem
4961                 }
4962             });
4963
4964             if (t.hasMenus()) {
4965                 t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {
4966                     var m, r, mi;
4967
4968                     e = e.target;
4969                     if (e && (e = DOM.getParent(e, 'TR'))) {
4970                         m = t.items[e.id];
4971
4972                         if (t.lastMenu)
4973                             t.lastMenu.collapse(1);
4974
4975                         if (m.isDisabled())
4976                             return;
4977
4978                         if (e && DOM.hasClass(e, cp + 'ItemSub')) {
4979                             //p = DOM.getPos(s.container);
4980                             r = DOM.getRect(e);
4981                             m.showMenu((r.x + r.w - ot), r.y - ot, r.x);
4982                             t.lastMenu = m;
4983                             DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');
4984                         }
4985                     }
4986                 });
4987             }
4988
4989             t.onShowMenu.dispatch(t);
4990
4991             if (s.keyboard_focus) {
4992                 Event.add(co, 'keydown', t._keyHandler, t);
4993                 DOM.select('a', 'menu_' + t.id)[0].focus(); // Select first link
4994             }
4995         },
4996
4997         hideMenu : function(c) {
4998             var t = this, co = DOM.get('menu_' + t.id), e;
4999
5000             if (!t.isMenuVisible)
5001                 return;
5002
5003             Event.remove(co, 'mouseover', t.mouseOverFunc);
5004             Event.remove(co, t.fixIE ? 'mousedown' : 'click', t.mouseClickFunc);
5005             Event.remove(co, 'keydown', t._keyHandler);
5006             DOM.hide(co);
5007             t.isMenuVisible = 0;
5008
5009             if (!c)
5010                 t.collapse(1);
5011
5012             if (t.element)
5013                 t.element.hide();
5014
5015             if (e = DOM.get(t.id))
5016                 DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');
5017
5018             t.onHideMenu.dispatch(t);
5019         },
5020
5021         add : function(o) {
5022             var t = this, co;
5023
5024             o = t.parent(o);
5025
5026             if (t.isRendered && (co = DOM.get('menu_' + t.id)))
5027                 t._add(DOM.select('tbody', co)[0], o);
5028
5029             return o;
5030         },
5031
5032         collapse : function(d) {
5033             this.parent(d);
5034             this.hideMenu(1);
5035         },
5036
5037         remove : function(o) {
5038             DOM.remove(o.id);
5039             this.destroy();
5040
5041             return this.parent(o);
5042         },
5043
5044         destroy : function() {
5045             var t = this, co = DOM.get('menu_' + t.id);
5046
5047             Event.remove(co, 'mouseover', t.mouseOverFunc);
5048             Event.remove(co, 'click', t.mouseClickFunc);
5049
5050             if (t.element)
5051                 t.element.remove();
5052
5053             DOM.remove(co);
5054         },
5055
5056         renderNode : function() {
5057             var t = this, s = t.settings, n, tb, co, w;
5058
5059             w = DOM.create('div', {id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000'});
5060             co = DOM.add(w, 'div', {id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});
5061             t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
5062
5063             if (s.menu_line)
5064                 DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});
5065
5066 //            n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
5067             n = DOM.add(co, 'table', {id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});
5068             tb = DOM.add(n, 'tbody');
5069
5070             each(t.items, function(o) {
5071                 t._add(tb, o);
5072             });
5073
5074             t.rendered = true;
5075
5076             return w;
5077         },
5078
5079         // Internal functions
5080
5081         _keyHandler : function(e) {
5082             // Accessibility feature
5083             if (e.keyCode == 27)
5084                 this.hideMenu();
5085         },
5086
5087         _add : function(tb, o) {
5088             var n, s = o.settings, a, ro, it, cp = this.classPrefix;
5089
5090             if (s.separator) {
5091                 ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});
5092                 DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});
5093
5094                 if (n = ro.previousSibling)
5095                     DOM.addClass(n, 'mceLast');
5096
5097                 return;
5098             }
5099
5100             n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});
5101             n = it = DOM.add(n, 'td');
5102             n = a = DOM.add(n, 'a', {href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});
5103
5104             DOM.addClass(it, s['class']);
5105 //            n = DOM.add(n, 'span', {'class' : 'item'});
5106             DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});
5107             n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);
5108
5109             if (o.settings.style)
5110                 DOM.setAttrib(n, 'style', o.settings.style);
5111
5112             if (tb.childNodes.length == 1)
5113                 DOM.addClass(ro, 'mceFirst');
5114
5115             if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))
5116                 DOM.addClass(ro, 'mceFirst');
5117
5118             if (o.collapse)
5119                 DOM.addClass(ro, cp + 'ItemSub');
5120
5121             if (n = ro.previousSibling)
5122                 DOM.removeClass(n, 'mceLast');
5123
5124             DOM.addClass(ro, 'mceLast');
5125         }
5126
5127         });
5128 })();
5129 /* file:jscripts/tiny_mce/classes/ui/Button.js */
5130
5131 (function() {
5132     var DOM = tinymce.DOM;
5133
5134     tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {
5135         Button : function(id, s) {
5136             this.parent(id, s);
5137             this.classPrefix = 'mceButton';
5138         },
5139
5140         renderHTML : function() {
5141             var cp = this.classPrefix, s = this.settings, h = '<a id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + '" onmousedown="return false;" onclick="return false;" title="' + DOM.encode(s.title) + '">';
5142
5143             if (s.image)
5144                 h += '<img class="mceIcon" src="' + s.image + '" /></a>';
5145             else
5146                 h += '<span class="mceIcon ' + s['class'] + '"></span></a>';
5147
5148             return h;
5149         },
5150
5151         postRender : function() {
5152             var t = this, s = t.settings;
5153
5154             tinymce.dom.Event.add(t.id, 'click', function(e) {
5155                 if (!t.isDisabled())
5156                     return s.onclick.call(s.scope, e);
5157             });
5158         }
5159
5160         });
5161 })();
5162
5163 /* file:jscripts/tiny_mce/classes/ui/ListBox.js */
5164
5165 (function() {
5166     var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
5167
5168     tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {
5169         ListBox : function(id, s) {
5170             var t = this;
5171
5172             t.parent(id, s);
5173             t.items = [];
5174             t.onChange = new Dispatcher(t);
5175             t.onPostRender = new Dispatcher(t);
5176             t.onAdd = new Dispatcher(t);
5177             t.onRenderMenu = new tinymce.util.Dispatcher(this);
5178             t.classPrefix = 'mceListBox';
5179         },
5180
5181         select : function(v) {
5182             var t = this, e, fv;
5183
5184             // Do we need to do something?
5185             if (v != t.selectedValue) {
5186                 e = DOM.get(t.id + '_text');
5187                 t.selectedValue = v;
5188
5189                 // Find item
5190                 each(t.items, function(o) {
5191                     if (o.value == v) {
5192                         DOM.setHTML(e, DOM.encode(o.title));
5193                         fv = 1;
5194                         return false;
5195                     }
5196                 });
5197
5198                 // If no item was found then present title
5199                 if (!fv) {
5200                     DOM.setHTML(e, DOM.encode(t.settings.title));
5201                     DOM.addClass(e, 'mceTitle');
5202                     e = 0;
5203                     return;
5204                 } else
5205                     DOM.removeClass(e, 'mceTitle');
5206             }
5207
5208             e = 0;
5209         },
5210
5211         add : function(n, v, o) {
5212             var t = this;
5213
5214             o = o || {};
5215             o = tinymce.extend(o, {
5216                 title : n,
5217                 value : v
5218             });
5219
5220             t.items.push(o);
5221             t.onAdd.dispatch(t, o);
5222         },
5223
5224         getLength : function() {
5225             return this.items.length;
5226         },
5227
5228         renderHTML : function() {
5229             var h = '', t = this, s = t.settings, cp = t.classPrefix;
5230
5231             h = '<table id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';
5232             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>';
5233             h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span></span>') + '</td>';
5234             h += '</tr></tbody></table>';
5235
5236             return h;
5237         },
5238
5239         showMenu : function() {
5240             var t = this, p1, p2, e = DOM.get(this.id), m;
5241
5242             if (t.isDisabled() || t.items.length == 0)
5243                 return;
5244
5245             if (!t.isMenuRendered) {
5246                 t.renderMenu();
5247                 t.isMenuRendered = true;
5248             }
5249
5250             p1 = DOM.getPos(this.settings.menu_container);
5251             p2 = DOM.getPos(e);
5252
5253             m = t.menu;
5254             m.settings.offset_x = p2.x;
5255             m.settings.offset_y = p2.y;
5256             m.settings.keyboard_focus = t._focused;
5257
5258             // Select in menu
5259             if (t.oldID)
5260                 m.items[t.oldID].setSelected(0);
5261
5262             each(t.items, function(o) {
5263                 if (o.value === t.selectedValue) {
5264                     m.items[o.id].setSelected(1);
5265                     t.oldID = o.id;
5266                 }
5267             });
5268
5269             m.showMenu(0, e.clientHeight);
5270
5271             Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
5272             DOM.addClass(t.id, t.classPrefix + 'Selected');
5273         },
5274
5275         hideMenu : function(e) {
5276             var t = this;
5277
5278             if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceMenu');})) {
5279                 DOM.removeClass(t.id, t.classPrefix + 'Selected');
5280                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
5281
5282                 if (t.menu)
5283                     t.menu.hideMenu();
5284             }
5285         },
5286
5287         renderMenu : function() {
5288             var t = this, m;
5289
5290             m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
5291                 menu_line : 1,
5292                 'class' : t.classPrefix + 'Menu mceNoIcons',
5293                 max_width : 150,
5294                 max_height : 150
5295             });
5296
5297             m.onHideMenu.add(t.hideMenu, t);
5298
5299             m.add({
5300                 title : t.settings.title,
5301                 'class' : 'mceMenuItemTitle'
5302             }).setDisabled(1);
5303
5304             each(t.items, function(o) {
5305                 o.id = DOM.uniqueId();
5306                 o.onclick = function() {
5307                     if (t.settings.onselect(o.value) !== false)
5308                         t.select(o.value); // Must be runned after
5309                 };
5310
5311                 m.add(o);
5312             });
5313
5314             t.onRenderMenu.dispatch(t, m);
5315             t.menu = m;
5316         },
5317
5318         postRender : function() {
5319             var t = this, cp = t.classPrefix;
5320
5321             Event.add(t.id, 'click', t.showMenu, t);
5322             Event.add(t.id + '_text', 'focus', function() {t._focused = 1;});
5323             Event.add(t.id + '_text', 'blur', function() {t._focused = 0;});
5324
5325             // Old IE doesn't have hover on all elements
5326             if (tinymce.isIE6 || !DOM.boxModel) {
5327                 Event.add(t.id, 'mouseover', function() {
5328                     if (!DOM.hasClass(t.id, cp + 'Disabled'))
5329                         DOM.addClass(t.id, cp + 'Hover');
5330                 });
5331
5332                 Event.add(t.id, 'mouseout', function() {
5333                     if (!DOM.hasClass(t.id, cp + 'Disabled'))
5334                         DOM.removeClass(t.id, cp + 'Hover');
5335                 });
5336             }
5337
5338             t.onPostRender.dispatch(t, DOM.get(t.id));
5339         },
5340
5341         destroy : function() {
5342             this.parent();
5343
5344             Event.clear(this.id + '_text');
5345         }
5346
5347         });
5348 })();
5349 /* file:jscripts/tiny_mce/classes/ui/NativeListBox.js */
5350
5351 (function() {
5352     var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
5353
5354     tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {
5355         NativeListBox : function(id, s) {
5356             this.parent(id, s);
5357             this.classPrefix = 'mceNativeListBox';
5358         },
5359
5360         setDisabled : function(s) {
5361             DOM.get(this.id).disabled = s;
5362         },
5363
5364         isDisabled : function() {
5365             return DOM.get(this.id).disabled;
5366         },
5367
5368         select : function(v) {
5369             var e = DOM.get(this.id), ol = e.options;
5370
5371             v = '' + (v || '');
5372
5373             e.selectedIndex = 0;
5374             each(ol, function(o, i) {
5375                 if (o.value == v) {
5376                     e.selectedIndex = i;
5377                     return false;
5378                 }
5379             });
5380         },
5381
5382         add : function(n, v, a) {
5383             var o, t = this;
5384
5385             a = a || {};
5386             a.value = v;
5387
5388             if (t.isRendered())
5389                 DOM.add(DOM.get(this.id), 'option', a, n);
5390
5391             o = {
5392                 title : n,
5393                 value : v,
5394                 attribs : a
5395             };
5396
5397             t.items.push(o);
5398             t.onAdd.dispatch(t, o);
5399         },
5400
5401         getLength : function() {
5402             return DOM.get(this.id).options.length - 1;
5403         },
5404
5405         renderHTML : function() {
5406             var h, t = this;
5407
5408             h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');
5409
5410             each(t.items, function(it) {
5411                 h += DOM.createHTML('option', {value : it.value}, it.title);
5412             });
5413
5414             h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox'}, h);
5415
5416             return h;
5417         },
5418
5419         postRender : function() {
5420             var t = this, ch;
5421
5422             t.rendered = true;
5423
5424             function onChange(e) {
5425                 var v = e.target.options[e.target.selectedIndex].value;
5426
5427                 t.onChange.dispatch(t, v);
5428
5429                 if (t.settings.onselect)
5430                     t.settings.onselect(v);
5431             };
5432
5433             Event.add(t.id, 'change', onChange);
5434
5435             // Accessibility keyhandler
5436             Event.add(t.id, 'keydown', function(e) {
5437                 var bf;
5438
5439                 Event.remove(t.id, 'change', ch);
5440
5441                 bf = Event.add(t.id, 'blur', function() {
5442                     Event.add(t.id, 'change', onChange);
5443                     Event.remove(t.id, 'blur', bf);
5444                 });
5445
5446                 if (e.keyCode == 13 || e.keyCode == 32) {
5447                     onChange(e);
5448                     return Event.cancel(e);
5449                 }
5450             });
5451
5452             t.onPostRender.dispatch(t, DOM.get(t.id));
5453         }
5454
5455         });
5456 })();
5457 /* file:jscripts/tiny_mce/classes/ui/MenuButton.js */
5458
5459 (function() {
5460     var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
5461
5462     tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {
5463         MenuButton : function(id, s) {
5464             this.parent(id, s);
5465             this.onRenderMenu = new tinymce.util.Dispatcher(this);
5466             s.menu_container = s.menu_container || DOM.doc.body;
5467         },
5468
5469         showMenu : function() {
5470             var t = this, p1, p2, e = DOM.get(t.id), m;
5471
5472             if (t.isDisabled())
5473                 return;
5474
5475             if (!t.isMenuRendered) {
5476                 t.renderMenu();
5477                 t.isMenuRendered = true;
5478             }
5479
5480             p1 = DOM.getPos(t.settings.menu_container);
5481             p2 = DOM.getPos(e);
5482
5483             m = t.menu;
5484             m.settings.offset_x = p2.x;
5485             m.settings.offset_y = p2.y;
5486             m.settings.vp_offset_x = p2.x;
5487             m.settings.vp_offset_y = p2.y;
5488             m.settings.keyboard_focus = t._focused;
5489             m.showMenu(0, e.clientHeight);
5490
5491             Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
5492             t.setState('Selected', 1);
5493         },
5494
5495         renderMenu : function() {
5496             var t = this, m;
5497
5498             m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
5499                 menu_line : 1,
5500                 'class' : this.classPrefix + 'Menu',
5501                 icons : t.settings.icons
5502             });
5503
5504             m.onHideMenu.add(t.hideMenu, t);
5505
5506             t.onRenderMenu.dispatch(t, m);
5507             t.menu = m;
5508         },
5509
5510         hideMenu : function(e) {
5511             var t = this;
5512
5513             if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceMenu');})) {
5514                 t.setState('Selected', 0);
5515                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
5516                 if (t.menu)
5517                     t.menu.hideMenu();
5518             }
5519         },
5520
5521         postRender : function() {
5522             var t = this, s = t.settings;
5523
5524             Event.add(t.id, 'click', function() {
5525                 if (!t.isDisabled()) {
5526                     if (s.onclick)
5527                         s.onclick(t.value);
5528
5529                     t.showMenu();
5530                 }
5531             });
5532         }
5533
5534         });
5535 })();
5536
5537 /* file:jscripts/tiny_mce/classes/ui/SplitButton.js */
5538
5539 (function() {
5540     var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
5541
5542     tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {
5543         SplitButton : function(id, s) {
5544             this.parent(id, s);
5545             this.classPrefix = 'mceSplitButton';
5546         },
5547
5548         renderHTML : function() {
5549             var h, t = this, s = t.settings, h1;
5550
5551             h = '<tbody><tr>';
5552
5553             if (s.image)
5554                 h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'mceAction ' + s['class']});
5555             else
5556                 h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');
5557
5558             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>';
5559     
5560             h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']});
5561             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>';
5562
5563             h += '</tr></tbody>';
5564
5565             return DOM.createHTML('table', {id : t.id, 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', onmousedown : 'return false;', title : s.title}, h);
5566         },
5567
5568         postRender : function() {
5569             var t = this, s = t.settings;
5570
5571             if (s.onclick) {
5572                 Event.add(t.id + '_action', 'click', function() {
5573                     if (!t.isDisabled())
5574                         s.onclick(t.value);
5575                 });
5576             }
5577
5578             Event.add(t.id + '_open', 'click', t.showMenu, t);
5579             Event.add(t.id + '_open', 'focus', function() {t._focused = 1;});
5580             Event.add(t.id + '_open', 'blur', function() {t._focused = 0;});
5581
5582             // Old IE doesn't have hover on all elements
5583             if (tinymce.isIE6 || !DOM.boxModel) {
5584                 Event.add(t.id, 'mouseover', function() {
5585                     if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
5586                         DOM.addClass(t.id, 'mceSplitButtonHover');
5587                 });
5588
5589                 Event.add(t.id, 'mouseout', function() {
5590                     if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
5591                         DOM.removeClass(t.id, 'mceSplitButtonHover');
5592                 });
5593             }
5594         },
5595
5596         destroy : function() {
5597             this.parent();
5598
5599             Event.clear(this.id + '_action');
5600             Event.clear(this.id + '_open');
5601         }
5602
5603         });
5604 })();
5605
5606 /* file:jscripts/tiny_mce/classes/ui/ColorSplitButton.js */
5607
5608 (function() {
5609     var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
5610
5611     tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
5612         ColorSplitButton : function(id, s) {
5613             var t = this;
5614
5615             t.parent(id, s);
5616
5617             t.settings = s = tinymce.extend({
5618                 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',
5619                 grid_width : 8,
5620                 default_color : '#888888'
5621             }, t.settings);
5622
5623             t.value = s.default_color;
5624         },
5625
5626         showMenu : function() {
5627             var t = this, r, p, e, p2;
5628
5629             if (t.isDisabled())
5630                 return;
5631
5632             if (!t.isMenuRendered) {
5633                 t.renderMenu();
5634                 t.isMenuRendered = true;
5635             }
5636
5637             e = DOM.get(t.id);
5638             DOM.show(t.id + '_menu');
5639             DOM.addClass(e, 'mceSplitButtonSelected');
5640             p2 = DOM.getPos(e);
5641             DOM.setStyles(t.id + '_menu', {
5642                 left : p2.x,
5643                 top : p2.y + e.clientHeight,
5644                 zIndex : 200000
5645             });
5646             e = 0;
5647
5648             Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
5649
5650             if (t._focused) {
5651                 t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
5652                     if (e.keyCode == 27)
5653                         t.hideMenu();
5654                 });
5655
5656                 DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
5657             }
5658         },
5659
5660         hideMenu : function(e) {
5661             var t = this;
5662
5663             if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceSplitButtonMenu');})) {
5664                 DOM.removeClass(t.id, 'mceSplitButtonSelected');
5665                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
5666                 Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
5667                 DOM.hide(t.id + '_menu');
5668             }
5669         },
5670
5671         renderMenu : function() {
5672             var t = this, m, i = 0, s = t.settings, n, tb, tr, w;
5673
5674             w = DOM.add(s.menu_container, 'div', {id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
5675             m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
5676             DOM.add(m, 'span', {'class' : 'mceMenuLine'});
5677
5678             n = DOM.add(m, 'table', {'class' : 'mceColorSplitMenu'});
5679             tb = DOM.add(n, 'tbody');
5680
5681             // Generate color grid
5682             i = 0;
5683             each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
5684                 c = c.replace(/^#/, '');
5685
5686                 if (!i--) {
5687                     tr = DOM.add(tb, 'tr');
5688                     i = s.grid_width - 1;
5689                 }
5690
5691                 n = DOM.add(tr, 'td');
5692
5693                 n = DOM.add(n, 'a', {
5694                     href : 'javascript:;',
5695                     style : {
5696                         backgroundColor : '#' + c
5697                     },
5698                     mce_color : '#' + c
5699                 });
5700             });
5701
5702             if (s.more_colors_func) {
5703                 n = DOM.add(tb, 'tr');
5704                 n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
5705                 n = DOM.add(n, 'a', {id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
5706
5707                 Event.add(n, 'click', function(e) {
5708                     s.more_colors_func.call(s.more_colors_scope || this);
5709                     return Event.cancel(e); // Cancel to fix onbeforeunload problem
5710                 });
5711             }
5712
5713             DOM.addClass(m, 'mceColorSplitMenu');
5714
5715             Event.add(t.id + '_menu', 'click', function(e) {
5716                 var c;
5717
5718                 e = e.target;
5719
5720                 if (e.nodeName == 'A' && (c = e.getAttribute('mce_color')))
5721                     t.setColor(c);
5722             });
5723
5724             return w;
5725         },
5726
5727         setColor : function(c) {
5728             var t = this;
5729
5730             DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
5731
5732             t.value = c;
5733             t.hideMenu();
5734             t.settings.onselect(c);
5735         },
5736
5737         postRender : function() {
5738             var t = this, id = t.id;
5739
5740             t.parent();
5741             DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
5742         },
5743
5744         destroy : function() {
5745             this.parent();
5746
5747             Event.clear(this.id + '_menu');
5748             Event.clear(this.id + '_more');
5749             DOM.remove(this.id + '_menu');
5750         }
5751
5752         });
5753 })();
5754
5755 /* file:jscripts/tiny_mce/classes/ui/Toolbar.js */
5756
5757 tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
5758     renderHTML : function() {
5759         var t = this, h = '', c, co, dom = tinymce.DOM, s = t.settings, i, pr, nx, cl;
5760
5761         cl = t.controls;
5762         for (i=0; i<cl.length; i++) {
5763             // Get current control, prev control, next control and if the control is a list box or not
5764             co = cl[i];
5765             pr = cl[i - 1];
5766             nx = cl[i + 1];
5767
5768             // Add toolbar start
5769             if (i === 0) {
5770                 c = 'mceToolbarStart';
5771
5772                 if (co.Button)
5773                     c += ' mceToolbarStartButton';
5774                 else if (co.SplitButton)
5775                     c += ' mceToolbarStartSplitButton';
5776                 else if (co.ListBox)
5777                     c += ' mceToolbarStartListBox';
5778
5779                 h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
5780             }
5781
5782             // Add toolbar end before list box and after the previous button
5783             // This is to fix the o2k7 editor skins
5784             if (pr && co.ListBox) {
5785                 if (pr.Button || pr.SplitButton)
5786                     h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));
5787             }
5788
5789             // Render control HTML
5790
5791             // IE 8 quick fix, needed to propertly generate a hit area for anchors
5792             if (dom.stdMode)
5793                 h += '<td style="position: relative">' + co.renderHTML() + '</td>';
5794             else
5795                 h += '<td>' + co.renderHTML() + '</td>';
5796
5797             // Add toolbar start after list box and before the next button
5798             // This is to fix the o2k7 editor skins
5799             if (nx && co.ListBox) {
5800                 if (nx.Button || nx.SplitButton)
5801                     h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));
5802             }
5803         }
5804
5805         c = 'mceToolbarEnd';
5806
5807         if (co.Button)
5808             c += ' mceToolbarEndButton';
5809         else if (co.SplitButton)
5810             c += ' mceToolbarEndSplitButton';
5811         else if (co.ListBox)
5812             c += ' mceToolbarEndListBox';
5813
5814         h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
5815
5816         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>');
5817     }
5818
5819     });
5820
5821 /* file:jscripts/tiny_mce/classes/AddOnManager.js */
5822
5823 (function() {
5824     var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
5825
5826     tinymce.create('tinymce.AddOnManager', {
5827         items : [],
5828         urls : {},
5829         lookup : {},
5830         onAdd : new Dispatcher(this),
5831
5832         get : function(n) {
5833             return this.lookup[n];
5834         },
5835
5836         requireLangPack : function(n) {
5837             var u, s;
5838
5839             if (tinymce.EditorManager.settings) {
5840                 u = this.urls[n] + '/langs/' + tinymce.EditorManager.settings.language + '.js';
5841                 s = tinymce.EditorManager.settings;
5842
5843                 if (s) {
5844                     if (!tinymce.dom.Event.domLoaded && !s.strict_mode)
5845                         tinymce.ScriptLoader.load(u);
5846                     else
5847                         tinymce.ScriptLoader.add(u);
5848                 }
5849             }
5850         },
5851
5852         add : function(id, o) {
5853             this.items.push(o);
5854             this.lookup[id] = o;
5855             this.onAdd.dispatch(this, id, o);
5856
5857             return o;
5858         },
5859
5860         load : function(n, u, cb, s) {
5861             var t = this;
5862
5863             if (t.urls[n])
5864                 return;
5865
5866             if (u.indexOf('/') != 0 && u.indexOf('://') == -1)
5867                 u = tinymce.baseURL + '/' +  u;
5868
5869             t.urls[n] = u.substring(0, u.lastIndexOf('/'));
5870             tinymce.ScriptLoader.add(u, cb, s);
5871         }
5872
5873         });
5874
5875     // Create plugin and theme managers
5876     tinymce.PluginManager = new tinymce.AddOnManager();
5877     tinymce.ThemeManager = new tinymce.AddOnManager();
5878 }());
5879 /* file:jscripts/tiny_mce/classes/EditorManager.js */
5880
5881 (function() {
5882     // Shorten names
5883     var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode;
5884
5885     tinymce.create('static tinymce.EditorManager', {
5886         editors : {},
5887         i18n : {},
5888         activeEditor : null,
5889
5890         preInit : function() {
5891             var t = this, lo = window.location;
5892
5893             // Setup some URLs where the editor API is located and where the document is
5894             tinymce.documentBaseURL = lo.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
5895             if (!/[\/\\]$/.test(tinymce.documentBaseURL))
5896                 tinymce.documentBaseURL += '/';
5897
5898             tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);
5899             tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL);
5900
5901             // Setup document domain
5902             if (tinymce.EditorManager.baseURI.host != lo.hostname && lo.hostname)
5903                 document.domain = tinymce.relaxedDomain = lo.hostname.replace(/.*\.(.+\..+)$/, '$1');
5904
5905             // Add before unload listener
5906             // This was required since IE was leaking memory if you added and removed beforeunload listeners
5907             // with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
5908             t.onBeforeUnload = new tinymce.util.Dispatcher(t);
5909
5910             // Must be on window or IE will leak if the editor is placed in frame or iframe
5911             Event.add(window, 'beforeunload', function(e) {
5912                 t.onBeforeUnload.dispatch(t, e);
5913             });
5914         },
5915
5916         init : function(s) {
5917             var t = this, pl, sl = tinymce.ScriptLoader, c;
5918
5919             function execCallback(se, n, s) {
5920                 var f = se[n];
5921
5922                 if (!f)
5923                     return;
5924
5925                 if (tinymce.is(f, 'string')) {
5926                     s = f.replace(/\.\w+$/, '');
5927                     s = s ? tinymce.resolve(s) : 0;
5928                     f = tinymce.resolve(f);
5929                 }
5930
5931                 return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
5932             };
5933
5934             s = extend({
5935                 theme : "simple",
5936                 language : "en",
5937                 strict_loading_mode : document.contentType == 'application/xhtml+xml'
5938             }, s);
5939
5940             t.settings = s;
5941
5942             // If page not loaded and strict mode isn't enabled then load them
5943             if (!Event.domLoaded && !s.strict_loading_mode) {
5944                 // Load language
5945                 if (s.language)
5946                     sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
5947
5948                 // Load theme
5949                 if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
5950                     ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
5951
5952                 // Load plugins
5953                 if (s.plugins) {
5954                     pl = explode(s.plugins);
5955
5956                     // Load compat2x first
5957                     if (tinymce.inArray(pl, 'compat2x') != -1)
5958                         PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js');
5959
5960                     // Load rest if plugins
5961                     each(pl, function(v) {
5962                         if (v && v.charAt(0) != '-' && !PluginManager.urls[v]) {
5963                             // Skip safari plugin for other browsers
5964                             if (!tinymce.isWebKit && v == 'safari')
5965                                 return;
5966
5967                             PluginManager.load(v, 'plugins/' + v + '/editor_plugin' + tinymce.suffix + '.js');
5968                         }
5969                     });
5970                 }
5971
5972                 sl.loadQueue();
5973             }
5974
5975             // Legacy call
5976             Event.add(document, 'init', function() {
5977                 var l, co;
5978
5979                 execCallback(s, 'onpageload');
5980
5981                 // Verify that it's a valid browser
5982                 if (s.browsers) {
5983                     l = false;
5984
5985                     each(explode(s.browsers), function(v) {
5986                         switch (v) {
5987                             case 'ie':
5988                             case 'msie':
5989                                 if (tinymce.isIE)
5990                                     l = true;
5991                                 break;
5992
5993                             case 'gecko':
5994                                 if (tinymce.isGecko)
5995                                     l = true;
5996                                 break;
5997
5998                             case 'safari':
5999                             case 'webkit':
6000                                 if (tinymce.isWebKit)
6001                                     l = true;
6002                                 break;
6003
6004                             case 'opera':
6005                                 if (tinymce.isOpera)
6006                                     l = true;
6007
6008                                 break;
6009                         }
6010                     });
6011
6012                     // Not a valid one
6013                     if (!l)
6014                         return;
6015                 }
6016
6017                 switch (s.mode) {
6018                     case "exact":
6019                         l = s.elements || '';
6020
6021                         if(l.length > 0) {
6022                             each(explode(l), function(v) {
6023                                 if (DOM.get(v))
6024                                     new tinymce.Editor(v, s).render(1);
6025                                 else {
6026                                     c = 0;
6027
6028                                     each(document.forms, function(f) {
6029                                         each(f.elements, function(e) {
6030                                             if (e.name === v) {
6031                                                 v = 'mce_editor_' + c;
6032                                                 DOM.setAttrib(e, 'id', v);
6033                                                 new tinymce.Editor(v, s).render(1);
6034                                             }
6035                                         });
6036                                     });
6037                                 }
6038                             });
6039                         }
6040                         break;
6041
6042                     case "textareas":
6043                     case "specific_textareas":
6044                         function hasClass(n, c) {
6045                             return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
6046                         };
6047
6048                         each(DOM.select('textarea'), function(v) {
6049                             if (s.editor_deselector && hasClass(v, s.editor_deselector))
6050                                 return;
6051
6052                             if (!s.editor_selector || hasClass(v, s.editor_selector)) {
6053                                 v.id = v.id || v.name;
6054
6055                                 // Generate unique name if missing or already exists
6056                                 if (!v.id || t.get(v.id))
6057                                     v.id = DOM.uniqueId();
6058
6059                                 new tinymce.Editor(v.id, s).render(1);
6060                             }
6061                         });
6062                         break;
6063                 }
6064
6065                 // Call onInit when all editors are initialized
6066                 if (s.oninit) {
6067                     l = co = 0;
6068
6069                     each (t.editors, function(ed) {
6070                         co++;
6071
6072                         if (!ed.initialized) {
6073                             // Wait for it
6074                             ed.onInit.add(function() {
6075                                 l++;
6076
6077                                 // All done
6078                                 if (l == co)
6079                                     execCallback(s, 'oninit');
6080                             });
6081                         } else
6082                             l++;
6083
6084                         // All done
6085                         if (l == co)
6086                             execCallback(s, 'oninit');                    
6087                     });
6088                 }
6089             });
6090         },
6091
6092         get : function(id) {
6093             return this.editors[id];
6094         },
6095
6096         getInstanceById : function(id) {
6097             return this.get(id);
6098         },
6099
6100         add : function(e) {
6101             this.editors[e.id] = e;
6102             this._setActive(e);
6103
6104             return e;
6105         },
6106
6107         remove : function(e) {
6108             var t = this;
6109
6110             // Not in the collection
6111             if (!t.editors[e.id])
6112                 return null;
6113
6114             delete t.editors[e.id];
6115
6116             // Select another editor since the active one was removed
6117             if (t.activeEditor == e) {
6118                 each(t.editors, function(e) {
6119                     t._setActive(e);
6120                     return false; // Break
6121                 });
6122             }
6123
6124             e.destroy();
6125
6126             return e;
6127         },
6128
6129         execCommand : function(c, u, v) {
6130             var t = this, ed = t.get(v), w;
6131
6132             // Manager commands
6133             switch (c) {
6134                 case "mceFocus":
6135                     ed.focus();
6136                     return true;
6137
6138                 case "mceAddEditor":
6139                 case "mceAddControl":
6140                     new tinymce.Editor(v, t.settings).render();
6141                     return true;
6142
6143                 case "mceAddFrameControl":
6144                     w = v.window;
6145
6146                     // Add tinyMCE global instance and tinymce namespace to specified window
6147                     w.tinyMCE = tinyMCE;
6148                     w.tinymce = tinymce;
6149
6150                     tinymce.DOM.doc = w.document;
6151                     tinymce.DOM.win = w;
6152
6153                     ed = new tinymce.Editor(v.element_id, v);
6154                     ed.render();
6155
6156                     // Fix IE memory leaks
6157                     if (tinymce.isIE) {
6158                         function clr() {
6159                             ed.destroy();
6160                             w.detachEvent('onunload', clr);
6161                             w = w.tinyMCE = w.tinymce = null; // IE leak
6162                         };
6163
6164                         w.attachEvent('onunload', clr);
6165                     }
6166
6167                     v.page_window = null;
6168
6169                     return true;
6170
6171                 case "mceRemoveEditor":
6172                 case "mceRemoveControl":
6173                     ed.remove();
6174                     return true;
6175
6176                 case 'mceToggleEditor':
6177                     if (!ed) {
6178                         t.execCommand('mceAddControl', 0, v);
6179                         return true;
6180                     }
6181
6182                     if (ed.isHidden())
6183                         ed.show();
6184                     else
6185                         ed.hide();
6186
6187                     return true;
6188             }
6189
6190             // Run command on active editor
6191             if (t.activeEditor)
6192                 return t.activeEditor.execCommand(c, u, v);
6193
6194             return false;
6195         },
6196
6197         execInstanceCommand : function(id, c, u, v) {
6198             var ed = this.get(id);
6199
6200             if (ed)
6201                 return ed.execCommand(c, u, v);
6202
6203             return false;
6204         },
6205
6206         triggerSave : function() {
6207             each(this.editors, function(e) {
6208                 e.save();
6209             });
6210         },
6211
6212         addI18n : function(p, o) {
6213             var lo, i18n = this.i18n;
6214
6215             if (!tinymce.is(p, 'string')) {
6216                 each(p, function(o, lc) {
6217                     each(o, function(o, g) {
6218                         each(o, function(o, k) {
6219                             if (g === 'common')
6220                                 i18n[lc + '.' + k] = o;
6221                             else
6222                                 i18n[lc + '.' + g + '.' + k] = o;
6223                         });
6224                     });
6225                 });
6226             } else {
6227                 each(o, function(o, k) {
6228                     i18n[p + '.' + k] = o;
6229                 });
6230             }
6231         },
6232
6233         // Private methods
6234
6235         _setActive : function(e) {
6236             this.selectedInstance = this.activeEditor = e;
6237         }
6238
6239         });
6240
6241     tinymce.EditorManager.preInit();
6242 })();
6243
6244 // Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call
6245 var tinyMCE = window.tinyMCE = tinymce.EditorManager;
6246
6247 /* file:jscripts/tiny_mce/classes/Editor.js */
6248
6249 (function() {
6250     var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, Dispatcher = tinymce.util.Dispatcher;
6251     var each = tinymce.each, isGecko = tinymce.isGecko, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit;
6252     var is = tinymce.is, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, EditorManager = tinymce.EditorManager;
6253     var inArray = tinymce.inArray, grep = tinymce.grep, explode = tinymce.explode;
6254
6255     tinymce.create('tinymce.Editor', {
6256         Editor : function(id, s) {
6257             var t = this;
6258
6259             t.id = t.editorId = id;
6260             t.execCommands = {};
6261             t.queryStateCommands = {};
6262             t.queryValueCommands = {};
6263             t.plugins = {};
6264
6265             // Add events to the editor
6266             each([
6267                 'onPreInit',
6268                 'onBeforeRenderUI',
6269                 'onPostRender',
6270                 'onInit',
6271                 'onRemove',
6272                 'onActivate',
6273                 'onDeactivate',
6274                 'onClick',
6275                 'onEvent',
6276                 'onMouseUp',
6277                 'onMouseDown',
6278                 'onDblClick',
6279                 'onKeyDown',
6280                 'onKeyUp',
6281                 'onKeyPress',
6282                 'onContextMenu',
6283                 'onSubmit',
6284                 'onReset',
6285                 'onPaste',
6286                 'onPreProcess',
6287                 'onPostProcess',
6288                 'onBeforeSetContent',
6289                 'onBeforeGetContent',
6290                 'onSetContent',
6291                 'onGetContent',
6292                 'onLoadContent',
6293                 'onSaveContent',
6294                 'onNodeChange',
6295                 'onChange',
6296                 'onBeforeExecCommand',
6297                 'onExecCommand',
6298                 'onUndo',
6299                 'onRedo',
6300                 'onVisualAid',
6301                 'onSetProgressState'
6302             ], function(e) {
6303                 t[e] = new Dispatcher(t);
6304             });
6305
6306             // Default editor config
6307             t.settings = s = extend({
6308                 id : id,
6309                 language : 'en',
6310                 docs_language : 'en',
6311                 theme : 'simple',
6312                 skin : 'default',
6313                 delta_width : 0,
6314                 delta_height : 0,
6315                 popup_css : '',
6316                 plugins : '',
6317                 document_base_url : tinymce.documentBaseURL,
6318                 add_form_submit_trigger : 1,
6319                 submit_patch : 1,
6320                 add_unload_trigger : 1,
6321                 convert_urls : 1,
6322                 relative_urls : 1,
6323                 remove_script_host : 1,
6324                 table_inline_editing : 0,
6325                 object_resizing : 1,
6326                 cleanup : 1,
6327                 accessibility_focus : 1,
6328                 custom_shortcuts : 1,
6329                 custom_undo_redo_keyboard_shortcuts : 1,
6330                 custom_undo_redo_restore_selection : 1,
6331                 custom_undo_redo : 1,
6332                 doctype : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">',
6333                 visual_table_class : 'mceItemTable',
6334                 visual : 1,
6335                 inline_styles : true,
6336                 convert_fonts_to_spans : true,
6337                 font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large',
6338                 apply_source_formatting : 1,
6339                 directionality : 'ltr',
6340                 forced_root_block : 'p',
6341                 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[align],-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote,-table[border=0|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|_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],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',
6342                 hidden_input : 1,
6343                 padd_empty_editor : 1,
6344                 render_ui : 1,
6345                 init_theme : 1,
6346                 force_p_newlines : 1,
6347                 indentation : '30px'
6348             }, s);
6349
6350             // Setup URIs
6351             t.documentBaseURI = new tinymce.util.URI(s.document_base_url || tinymce.documentBaseURL, {
6352                 base_uri : tinyMCE.baseURI
6353             });
6354             t.baseURI = EditorManager.baseURI;
6355
6356             // Call setup
6357             t.execCallback('setup', t);
6358         },
6359
6360         render : function(nst) {
6361             var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader;
6362
6363             // Page is not loaded yet, wait for it
6364             if (!Event.domLoaded) {
6365                 Event.add(document, 'init', function() {
6366                     t.render();
6367                 });
6368                 return;
6369             }
6370
6371             // Force strict loading mode if render us called by user and not internally
6372             if (!nst) {
6373                 s.strict_loading_mode = 1;
6374                 tinyMCE.settings = s;
6375             }
6376
6377             // Element not found, then skip initialization
6378             if (!t.getElement())
6379                 return;
6380
6381             if (s.strict_loading_mode) {
6382                 sl.settings.strict_mode = s.strict_loading_mode;
6383                 tinymce.DOM.settings.strict = 1;
6384             }
6385
6386             // Add hidden input for non input elements inside form elements
6387             if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
6388                 DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
6389
6390             t.windowManager = new tinymce.WindowManager(t);
6391
6392             if (s.encoding == 'xml') {
6393                 t.onGetContent.add(function(ed, o) {
6394                     if (o.get)
6395                         o.content = DOM.encode(o.content);
6396                 });
6397             }
6398
6399             if (s.add_form_submit_trigger) {
6400                 t.onSubmit.addToTop(function() {
6401                     if (t.initialized) {
6402                         t.save();
6403                         t.isNotDirty = 1;
6404                     }
6405                 });
6406             }
6407
6408             if (s.add_unload_trigger) {
6409                 t._beforeUnload = tinyMCE.onBeforeUnload.add(function() {
6410                     if (t.initialized && !t.destroyed)
6411                         t.save({format : 'raw', no_events : true});
6412                 });
6413             }
6414
6415             tinymce.addUnload(t.destroy, t);
6416
6417             if (s.submit_patch) {
6418                 t.onBeforeRenderUI.add(function() {
6419                     var n = t.getElement().form;
6420
6421                     if (!n)
6422                         return;
6423
6424                     // Already patched
6425                     if (n._mceOldSubmit)
6426                         return;
6427
6428                     // Check page uses id="submit" or name="submit" for it's submit button
6429                     if (!n.submit.nodeType && !n.submit.length) {
6430                         t.formElement = n;
6431                         n._mceOldSubmit = n.submit;
6432                         n.submit = function() {
6433                             // Save all instances
6434                             EditorManager.triggerSave();
6435                             t.isNotDirty = 1;
6436
6437                             return this._mceOldSubmit(this);
6438                         };
6439                     }
6440
6441                     n = null;
6442                 });
6443             }
6444
6445             // Load scripts
6446             function loadScripts() {
6447                 if (s.language)
6448                     sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
6449
6450                 if (s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
6451                     ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
6452
6453                 each(explode(s.plugins), function(p) {
6454                     if (p && p.charAt(0) != '-' && !PluginManager.urls[p]) {
6455                         // Skip safari plugin for other browsers
6456                         if (!isWebKit && p == 'safari')
6457                             return;
6458
6459                         PluginManager.load(p, 'plugins/' + p + '/editor_plugin' + tinymce.suffix + '.js');
6460                     }
6461                 });
6462
6463                 // Init when que is loaded
6464                 sl.loadQueue(function() {
6465                     if (s.ask) {
6466                         function ask() {
6467                             t.windowManager.confirm(t.getLang('edit_confirm'), function(s) {
6468                                 if (s)
6469                                     t.init();
6470                                 else
6471                                     Event.remove(t.id, 'focus', ask);
6472                             });
6473                         };
6474
6475                         Event.add(t.id, 'focus', ask);
6476                         return;
6477                     }
6478
6479                     if (!t.removed)
6480                         t.init();
6481                 });
6482             };
6483
6484             // Load compat2x first
6485             if (s.plugins.indexOf('compat2x') != -1) {
6486                 PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js');
6487                 sl.loadQueue(loadScripts);
6488             } else
6489                 loadScripts();
6490         },
6491
6492         init : function() {
6493             var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u, bi, bc, re;
6494
6495             EditorManager.add(t);
6496
6497             // Create theme
6498             s.theme = s.theme.replace(/-/, '');
6499             o = ThemeManager.get(s.theme);
6500             t.theme = new o();
6501
6502             if (t.theme.init && s.init_theme)
6503                 t.theme.init(t, ThemeManager.urls[s.theme] || tinymce.documentBaseURL.replace(/\/$/, ''));
6504
6505             // Create all plugins
6506             each(explode(s.plugins.replace(/\-/g, '')), function(p) {
6507                 var c = PluginManager.get(p), u = PluginManager.urls[p] || tinymce.documentBaseURL.replace(/\/$/, ''), po;
6508
6509                 if (c) {
6510                     po = new c(t, u);
6511
6512                     t.plugins[p] = po;
6513
6514                     if (po.init)
6515                         po.init(t, u);
6516                 }
6517             });
6518
6519             // Setup popup CSS path(s)
6520             if (s.popup_css)
6521                 s.popup_css = t.documentBaseURI.toAbsolute(s.popup_css);
6522             else
6523                 s.popup_css = t.baseURI.toAbsolute("themes/" + s.theme + "/skins/" + s.skin + "/dialog.css");
6524
6525             if (s.popup_css_add)
6526                 s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add);
6527
6528             // Setup control factory
6529             t.controlManager = new tinymce.ControlManager(t);
6530             t.undoManager = new tinymce.UndoManager(t);
6531
6532             // Pass through
6533             t.undoManager.onAdd.add(function(um, l) {
6534                 return t.onChange.dispatch(t, l, um);
6535             });
6536
6537             t.undoManager.onUndo.add(function(um, l) {
6538                 return t.onUndo.dispatch(t, l, um);
6539             });
6540
6541             t.undoManager.onRedo.add(function(um, l) {
6542                 return t.onRedo.dispatch(t, l, um);
6543             });
6544
6545             if (s.custom_undo_redo) {
6546                 t.onExecCommand.add(function(ed, cmd, ui, val, a) {
6547                     if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!a || !a.skip_undo))
6548                         t.undoManager.add();
6549                 });
6550             }
6551
6552             t.onExecCommand.add(function(ed, c) {
6553                 // Don't refresh the select lists until caret move
6554                 if (!/^(FontName|FontSize)$/.test(c))
6555                     t.nodeChanged();
6556             });
6557
6558             // Remove ghost selections on images and tables in Gecko
6559             if (isGecko) {
6560                 function repaint(a, o) {
6561                     if (!o || !o.initial)
6562                         t.execCommand('mceRepaint');
6563                 };
6564
6565                 t.onUndo.add(repaint);
6566                 t.onRedo.add(repaint);
6567                 t.onSetContent.add(repaint);
6568             }
6569
6570             // Enables users to override the control factory
6571             t.onBeforeRenderUI.dispatch(t, t.controlManager);
6572
6573             // Measure box
6574             if (s.render_ui) {
6575                 w = s.width || e.style.width || e.clientWidth;
6576                 h = s.height || e.style.height || e.clientHeight;
6577                 t.orgDisplay = e.style.display;
6578                 re = /^[0-9\.]+(|px)$/i;
6579
6580                 if (re.test('' + w))
6581                     w = Math.max(parseInt(w) + (o.deltaWidth || 0), 100);
6582
6583                 if (re.test('' + h))
6584                     h = Math.max(parseInt(h) + (o.deltaHeight || 0), 100);
6585
6586                 // Render UI
6587                 o = t.theme.renderUI({
6588                     targetNode : e,
6589                     width : w,
6590                     height : h,
6591                     deltaWidth : s.delta_width,
6592                     deltaHeight : s.delta_height
6593                 });
6594
6595                 t.editorContainer = o.editorContainer;
6596             }
6597
6598             
6599             // Resize editor
6600             DOM.setStyles(o.sizeContainer || o.editorContainer, {
6601                 width : w,
6602                 height : h
6603             });
6604
6605             h = (o.iframeHeight || h) + ((h + '').indexOf('%') == -1 ? (o.deltaHeight || 0) : '');
6606             if (h < 100)
6607                 h = 100;
6608
6609             t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + t.documentBaseURI.getURI() + '"></base>';
6610             t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
6611
6612             if (tinymce.relaxedDomain)
6613                 t.iframeHTML += '<script type="text/javascript">document.domain = "' + tinymce.relaxedDomain + '";</script>';
6614
6615             bi = s.body_id || 'tinymce';
6616             if (bi.indexOf('=') != -1) {
6617                 bi = t.getParam('body_id', '', 'hash');
6618                 bi = bi[t.id] || bi;
6619             }
6620
6621             bc = s.body_class || '';
6622             if (bc.indexOf('=') != -1) {
6623                 bc = t.getParam('body_class', '', 'hash');
6624                 bc = bc[t.id] || '';
6625             }
6626
6627             t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';
6628
6629             // Domain relaxing enabled, then set document domain
6630             if (tinymce.relaxedDomain) {
6631                 // We need to write the contents here in IE since multiple writes messes up refresh button and back button
6632                 if (isIE)
6633                     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();})()';
6634                 else if (tinymce.isOpera)
6635                     u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()';                    
6636             }
6637
6638             // Create iframe
6639             n = DOM.add(o.iframeContainer, 'iframe', {
6640                 id : t.id + "_ifr",
6641                 src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7
6642                 frameBorder : '0',
6643                 style : {
6644                     width : '100%',
6645                     height : h
6646                 }
6647             });
6648
6649             t.contentAreaContainer = o.iframeContainer;
6650             DOM.get(o.editorContainer).style.display = t.orgDisplay;
6651             DOM.get(t.id).style.display = 'none';
6652
6653             // Safari 2.x requires us to wait for the load event and load a real HTML doc
6654             if (tinymce.isOldWebKit) {
6655                 Event.add(n, 'load', t.setupIframe, t);
6656                 n.src = tinymce.baseURL + '/plugins/safari/blank.htm';
6657             } else {
6658                 if (!isIE || !tinymce.relaxedDomain)
6659                     t.setupIframe();
6660
6661                 e = n = o = null; // Cleanup
6662             }
6663         },
6664
6665         setupIframe : function() {
6666             var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b;
6667
6668             // Setup iframe body
6669             if (!isIE || !tinymce.relaxedDomain) {
6670                 d.open();
6671                 d.write(t.iframeHTML);
6672                 d.close();
6673             }
6674
6675             // Design mode needs to be added here Ctrl+A will fail otherwise
6676             if (!isIE) {
6677                 try {
6678                     d.designMode = 'On';
6679                 } catch (ex) {
6680                     // Will fail on Gecko if the editor is placed in an hidden container element
6681                     // The design mode will be set ones the editor is focused
6682                 }
6683             }
6684
6685             // IE needs to use contentEditable or it will display non secure items for HTTPS
6686             if (isIE) {
6687                 // It will not steal focus if we hide it while setting contentEditable
6688                 b = t.getBody();
6689                 DOM.hide(b);
6690                 b.contentEditable = true;
6691                 DOM.show(b);
6692             }
6693
6694             // Setup objects
6695             t.dom = new tinymce.DOM.DOMUtils(t.getDoc(), {
6696                 keep_values : true,
6697                 url_converter : t.convertURL,
6698                 url_converter_scope : t,
6699                 hex_colors : s.force_hex_style_colors,
6700                 class_filter : s.class_filter,
6701                 update_styles : 1,
6702                 fix_ie_paragraphs : 1
6703             });
6704
6705             t.serializer = new tinymce.dom.Serializer({
6706                 entity_encoding : s.entity_encoding,
6707                 entities : s.entities,
6708                 valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements,
6709                 extended_valid_elements : s.extended_valid_elements,
6710                 valid_child_elements : s.valid_child_elements,
6711                 invalid_elements : s.invalid_elements,
6712                 fix_table_elements : s.fix_table_elements,
6713                 fix_list_elements : s.fix_list_elements,
6714                 fix_content_duplication : s.fix_content_duplication,
6715                 convert_fonts_to_spans : s.convert_fonts_to_spans,
6716                 font_size_classes  : s.font_size_classes,
6717                 font_size_style_values : s.font_size_style_values,
6718                 apply_source_formatting : s.apply_source_formatting,
6719                 remove_linebreaks : s.remove_linebreaks,
6720                 dom : t.dom
6721             });
6722
6723             t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer);
6724             t.forceBlocks = new tinymce.ForceBlocks(t, {
6725                 forced_root_block : s.forced_root_block
6726             });
6727             t.editorCommands = new tinymce.EditorCommands(t);
6728
6729             // Pass through
6730             t.serializer.onPreProcess.add(function(se, o) {
6731                 return t.onPreProcess.dispatch(t, o, se);
6732             });
6733
6734             t.serializer.onPostProcess.add(function(se, o) {
6735                 return t.onPostProcess.dispatch(t, o, se);
6736             });
6737
6738             t.onPreInit.dispatch(t);
6739
6740             if (!s.gecko_spellcheck)
6741                 t.getBody().spellcheck = 0;
6742
6743             t._addEvents();
6744
6745             t.controlManager.onPostRender.dispatch(t, t.controlManager);
6746             t.onPostRender.dispatch(t);
6747
6748             if (s.directionality)
6749                 t.getBody().dir = s.directionality;
6750
6751             if (s.nowrap)
6752                 t.getBody().style.whiteSpace = "nowrap";
6753
6754             if (s.auto_resize)
6755                 t.onNodeChange.add(t.resizeToContent, t);
6756
6757             if (s.custom_elements) {
6758                 function handleCustom(ed, o) {
6759                     each(explode(s.custom_elements), function(v) {
6760                         var n;
6761
6762                         if (v.indexOf('~') === 0) {
6763                             v = v.substring(1);
6764                             n = 'span';
6765                         } else
6766                             n = 'div';
6767
6768                         o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' mce_name="$1"$2>');
6769                         o.content = o.content.replace(new RegExp('</(' + v + ')>', 'g'), '</' + n + '>');
6770                     });
6771                 };
6772
6773                 t.onBeforeSetContent.add(handleCustom);
6774                 t.onPostProcess.add(function(ed, o) {
6775                     if (o.set)
6776                         handleCustom(ed, o)
6777                 });
6778             }
6779
6780             if (s.handle_node_change_callback) {
6781                 t.onNodeChange.add(function(ed, cm, n) {
6782                     t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed());
6783                 });
6784             }
6785
6786             if (s.save_callback) {
6787                 t.onSaveContent.add(function(ed, o) {
6788                     var h = t.execCallback('save_callback', t.id, o.content, t.getBody());
6789
6790                     if (h)
6791                         o.content = h;
6792                 });
6793             }
6794
6795             if (s.onchange_callback) {
6796                 t.onChange.add(function(ed, l) {
6797                     t.execCallback('onchange_callback', t, l);
6798                 });
6799             }
6800
6801             if (s.convert_newlines_to_brs) {
6802                 t.onBeforeSetContent.add(function(ed, o) {
6803                     if (o.initial)
6804                         o.content = o.content.replace(/\r?\n/g, '<br />');
6805                 });
6806             }
6807
6808             if (s.fix_nesting && isIE) {
6809                 t.onBeforeSetContent.add(function(ed, o) {
6810                     o.content = t._fixNesting(o.content);
6811                 });
6812             }
6813
6814             if (s.preformatted) {
6815                 t.onPostProcess.add(function(ed, o) {
6816                     o.content = o.content.replace(/^\s*<pre.*?>/, '');
6817                     o.content = o.content.replace(/<\/pre>\s*$/, '');
6818
6819                     if (o.set)
6820                         o.content = '<pre class="mceItemHidden">' + o.content + '</pre>';
6821                 });
6822             }
6823
6824             if (s.verify_css_classes) {
6825                 t.serializer.attribValueFilter = function(n, v) {
6826                     var s, cl;
6827
6828                     if (n == 'class') {
6829                         // Build regexp for classes
6830                         if (!t.classesRE) {
6831                             cl = t.dom.getClasses();
6832
6833                             if (cl.length > 0) {
6834                                 s = '';
6835
6836                                 each (cl, function(o) {
6837                                     s += (s ? '|' : '') + o['class'];
6838                                 });
6839
6840                                 t.classesRE = new RegExp('(' + s + ')', 'gi');
6841                             }
6842                         }
6843
6844                         return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : '';
6845                     }
6846
6847                     return v;
6848                 };
6849             }
6850
6851             if (s.convert_fonts_to_spans)
6852                 t._convertFonts();
6853
6854             if (s.inline_styles)
6855                 t._convertInlineElements();
6856
6857             if (s.cleanup_callback) {
6858                 t.onBeforeSetContent.add(function(ed, o) {
6859                     o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
6860                 });
6861
6862                 t.onPreProcess.add(function(ed, o) {
6863                     if (o.set)
6864                         t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o);
6865
6866                     if (o.get)
6867                         t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o);
6868                 });
6869
6870                 t.onPostProcess.add(function(ed, o) {
6871                     if (o.set)
6872                         o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
6873
6874                     if (o.get)                        
6875                         o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o);
6876                 });
6877             }
6878
6879             if (s.save_callback) {
6880                 t.onGetContent.add(function(ed, o) {
6881                     if (o.save)
6882                         o.content = t.execCallback('save_callback', t.id, o.content, t.getBody());
6883                 });
6884             }
6885
6886             if (s.handle_event_callback) {
6887                 t.onEvent.add(function(ed, e, o) {
6888                     if (t.execCallback('handle_event_callback', e, ed, o) === false)
6889                         Event.cancel(e);
6890                 });
6891             }
6892
6893             t.onSetContent.add(function() {
6894                 // Safari needs some time, it will crash the browser when a link is created otherwise
6895                 // I think this crash issue is resolved in the latest 3.0.4
6896                 //window.setTimeout(function() {
6897                     t.addVisual(t.getBody());
6898                 //}, 1);
6899             });
6900
6901             // Remove empty contents
6902             if (s.padd_empty_editor) {
6903                 t.onPostProcess.add(function(ed, o) {
6904                     o.content = o.content.replace(/^<p>(&nbsp;|#160;|\s|\u00a0)<\/p>$/, '');
6905                 });
6906             }
6907
6908             if (isGecko) {
6909                 try {
6910                     // Design mode must be set here once again to fix a bug where
6911                     // Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again
6912                     d.designMode = 'Off';
6913                     d.designMode = 'On';
6914                 } catch (ex) {
6915                     // Will fail on Gecko if the editor is placed in an hidden container element
6916                     // The design mode will be set ones the editor is focused
6917                 }
6918             }
6919
6920             // A small timeout was needed since firefox will remove. Bug: #1838304
6921             setTimeout(function () {
6922                 if (t.removed)
6923                     return;
6924
6925                 t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')});
6926                 t.startContent = t.getContent({format : 'raw'});
6927                 t.undoManager.add({initial : true});
6928                 t.initialized = true;
6929
6930                 t.onInit.dispatch(t);
6931                 t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc());
6932                 t.execCallback('init_instance_callback', t);
6933                 t.focus(true);
6934                 t.nodeChanged({initial : 1});
6935
6936                 // Load specified content CSS last
6937                 if (s.content_css) {
6938                     tinymce.each(explode(s.content_css), function(u) {
6939                         t.dom.loadCSS(t.documentBaseURI.toAbsolute(u));
6940                     });
6941                 }
6942
6943                 // Handle auto focus
6944                 if (s.auto_focus) {
6945                     setTimeout(function () {
6946                         var ed = EditorManager.get(s.auto_focus);
6947
6948                         ed.selection.select(ed.getBody(), 1);
6949                         ed.selection.collapse(1);
6950                         ed.getWin().focus();
6951                     }, 100);
6952                 }
6953             }, 1);
6954     
6955             e = null;
6956         },
6957
6958         
6959         focus : function(sf) {
6960             var oed, t = this;
6961
6962             if (!sf) {
6963                 t.getWin().focus();
6964
6965                             }
6966
6967             if (EditorManager.activeEditor != t) {
6968                 if ((oed = EditorManager.activeEditor) != null)
6969                     oed.onDeactivate.dispatch(oed, t);
6970
6971                 t.onActivate.dispatch(t, oed);
6972             }
6973
6974             EditorManager._setActive(t);
6975         },
6976
6977         execCallback : function(n) {
6978             var t = this, f = t.settings[n], s;
6979
6980             if (!f)
6981                 return;
6982
6983             // Look through lookup
6984             if (t.callbackLookup && (s = t.callbackLookup[n])) {
6985                 f = s.func;
6986                 s = s.scope;
6987             }
6988
6989             if (is(f, 'string')) {
6990                 s = f.replace(/\.\w+$/, '');
6991                 s = s ? tinymce.resolve(s) : 0;
6992                 f = tinymce.resolve(f);
6993                 t.callbackLookup = t.callbackLookup || {};
6994                 t.callbackLookup[n] = {func : f, scope : s};
6995             }
6996
6997             return f.apply(s || t, Array.prototype.slice.call(arguments, 1));
6998         },
6999
7000         translate : function(s) {
7001             var c = this.settings.language, i18n = EditorManager.i18n;
7002
7003             if (!s)
7004                 return '';
7005
7006             return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) {
7007                 return i18n[c + '.' + b] || '{#' + b + '}';
7008             });
7009         },
7010
7011         getLang : function(n, dv) {
7012             return EditorManager.i18n[this.settings.language + '.' + n] || (is(dv) ? dv : '{#' + n + '}');
7013         },
7014
7015         getParam : function(n, dv, ty) {
7016             var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o;
7017
7018             if (ty === 'hash') {
7019                 o = {};
7020
7021                 if (is(v, 'string')) {
7022                     each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) {
7023                         v = v.split('=');
7024
7025                         if (v.length > 1)
7026                             o[tr(v[0])] = tr(v[1]);
7027                         else
7028                             o[tr(v[0])] = tr(v);
7029                     });
7030                 } else
7031                     o = v;
7032
7033                 return o;
7034             }
7035
7036             return v;
7037         },
7038
7039         nodeChanged : function(o) {
7040             var t = this, s = t.selection, n = s.getNode() || t.getBody();
7041
7042             // Fix for bug #1896577 it seems that this can not be fired while the editor is loading
7043             if (t.initialized) {
7044                 t.onNodeChange.dispatch(
7045                     t,
7046                     o ? o.controlManager || t.controlManager : t.controlManager,
7047                     isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n, // Fix for IE initial state
7048                     s.isCollapsed(),
7049                     o
7050                 );
7051             }
7052         },
7053
7054         addButton : function(n, s) {
7055             var t = this;
7056
7057             t.buttons = t.buttons || {};
7058             t.buttons[n] = s;
7059         },
7060
7061         addCommand : function(n, f, s) {
7062             this.execCommands[n] = {func : f, scope : s || this};
7063         },
7064
7065         addQueryStateHandler : function(n, f, s) {
7066             this.queryStateCommands[n] = {func : f, scope : s || this};
7067         },
7068
7069         addQueryValueHandler : function(n, f, s) {
7070             this.queryValueCommands[n] = {func : f, scope : s || this};
7071         },
7072
7073         addShortcut : function(pa, desc, cmd_func, sc) {
7074             var t = this, c;
7075
7076             if (!t.settings.custom_shortcuts)
7077                 return false;
7078
7079             t.shortcuts = t.shortcuts || {};
7080
7081             if (is(cmd_func, 'string')) {
7082                 c = cmd_func;
7083
7084                 cmd_func = function() {
7085                     t.execCommand(c, false, null);
7086                 };
7087             }
7088
7089             if (is(cmd_func, 'object')) {
7090                 c = cmd_func;
7091
7092                 cmd_func = function() {
7093                     t.execCommand(c[0], c[1], c[2]);
7094                 };
7095             }
7096
7097             each(explode(pa), function(pa) {
7098                 var o = {
7099                     func : cmd_func,
7100                     scope : sc || this,
7101                     desc : desc,
7102                     alt : false,
7103                     ctrl : false,
7104                     shift : false
7105                 };
7106
7107                 each(explode(pa, '+'), function(v) {
7108                     switch (v) {
7109                         case 'alt':
7110                         case 'ctrl':
7111                         case 'shift':
7112                             o[v] = true;
7113                             break;
7114
7115                         default:
7116                             o.charCode = v.charCodeAt(0);
7117                             o.keyCode = v.toUpperCase().charCodeAt(0);
7118                     }
7119                 });
7120
7121                 t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o;
7122             });
7123
7124             return true;
7125         },
7126
7127         execCommand : function(cmd, ui, val, a) {
7128             var t = this, s = 0, o;
7129
7130             if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus))
7131                 t.focus();
7132
7133             o = {};
7134             t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o);
7135             if (o.terminate)
7136                 return false;
7137
7138             // Comamnd callback
7139             if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) {
7140                 t.onExecCommand.dispatch(t, cmd, ui, val, a);
7141                 return true;
7142             }
7143
7144             // Registred commands
7145             if (o = t.execCommands[cmd]) {
7146                 s = o.func.call(o.scope, ui, val);
7147                 t.onExecCommand.dispatch(t, cmd, ui, val, a);
7148                 return s;
7149             }
7150
7151             // Plugin commands
7152             each(t.plugins, function(p) {
7153                 if (p.execCommand && p.execCommand(cmd, ui, val)) {
7154                     t.onExecCommand.dispatch(t, cmd, ui, val, a);
7155                     s = 1;
7156                     return false;
7157                 }
7158             });
7159
7160             if (s)
7161                 return true;
7162
7163             // Theme commands
7164             if (t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) {
7165                 t.onExecCommand.dispatch(t, cmd, ui, val, a);
7166                 return true;
7167             }
7168
7169             // Editor commands
7170             if (t.editorCommands.execCommand(cmd, ui, val)) {
7171                 t.onExecCommand.dispatch(t, cmd, ui, val, a);
7172                 return true;
7173             }
7174
7175             // Browser commands
7176             t.getDoc().execCommand(cmd, ui, val);
7177             t.onExecCommand.dispatch(t, cmd, ui, val, a);
7178         },
7179
7180         queryCommandState : function(c) {
7181             var t = this, o;
7182
7183             // Is hidden then return undefined
7184             if (t._isHidden())
7185                 return;
7186
7187             // Registred commands
7188             if (o = t.queryStateCommands[c])
7189                 return o.func.call(o.scope);
7190
7191             // Registred commands
7192             o = t.editorCommands.queryCommandState(c);
7193             if (o !== -1)
7194                 return o;
7195
7196             // Browser commands
7197             try {
7198                 return this.getDoc().queryCommandState(c);
7199             } catch (ex) {
7200                 // Fails sometimes see bug: 1896577
7201             }
7202         },
7203
7204         queryCommandValue : function(c) {
7205             var t = this, o;
7206
7207             // Is hidden then return undefined
7208             if (t._isHidden())
7209                 return;
7210
7211             // Registred commands
7212             if (o = t.queryValueCommands[c])
7213                 return o.func.call(o.scope);
7214
7215             // Registred commands
7216             o = t.editorCommands.queryCommandValue(c);
7217             if (is(o))
7218                 return o;
7219
7220             // Browser commands
7221             try {
7222                 return this.getDoc().queryCommandValue(c);
7223             } catch (ex) {
7224                 // Fails sometimes see bug: 1896577
7225             }
7226         },
7227
7228         show : function() {
7229             var t = this;
7230
7231             DOM.show(t.getContainer());
7232             DOM.hide(t.id);
7233             t.load();
7234         },
7235
7236         hide : function() {
7237             var t = this, d = t.getDoc();
7238
7239             // Fixed bug where IE has a blinking cursor left from the editor
7240             if (isIE && d)
7241                 d.execCommand('SelectAll');
7242
7243             // We must save before we hide so Safari doesn't crash
7244             t.save();
7245             DOM.hide(t.getContainer());
7246             DOM.setStyle(t.id, 'display', t.orgDisplay);
7247         },
7248
7249         isHidden : function() {
7250             return !DOM.isHidden(this.id);
7251         },
7252
7253         setProgressState : function(b, ti, o) {
7254             this.onSetProgressState.dispatch(this, b, ti, o);
7255
7256             return b;
7257         },
7258
7259         resizeToContent : function() {
7260             var t = this;
7261
7262             DOM.setStyle(t.id + "_ifr", 'height', t.getBody().scrollHeight);
7263         },
7264
7265         load : function(o) {
7266             var t = this, e = t.getElement(), h;
7267
7268             o = o || {};
7269             o.load = true;
7270
7271             h = t.setContent(is(e.value) ? e.value : e.innerHTML, o);
7272             o.element = e;
7273
7274             if (!o.no_events)
7275                 t.onLoadContent.dispatch(t, o);
7276
7277             o.element = e = null;
7278
7279             return h;
7280         },
7281
7282         save : function(o) {
7283             var t = this, e = t.getElement(), h, f;
7284
7285             if (!t.initialized)
7286                 return;
7287
7288             o = o || {};
7289             o.save = true;
7290
7291             o.element = e;
7292             h = o.content = t.getContent(o);
7293
7294             if (!o.no_events)
7295                 t.onSaveContent.dispatch(t, o);
7296
7297             h = o.content;
7298
7299             if (!/TEXTAREA|INPUT/i.test(e.nodeName)) {
7300                 e.innerHTML = h;
7301
7302                 // Update hidden form element
7303                 if (f = DOM.getParent(t.id, 'form')) {
7304                     each(f.elements, function(e) {
7305                         if (e.name == t.id) {
7306                             e.value = h;
7307                             return false;
7308                         }
7309                     });
7310                 }
7311             } else
7312                 e.value = h;
7313
7314             o.element = e = null;
7315
7316             return h;
7317         },
7318
7319         setContent : function(h, o) {
7320             var t = this;
7321
7322             o = o || {};
7323             o.format = o.format || 'html';
7324             o.set = true;
7325             o.content = h;
7326
7327             if (!o.no_events)
7328                 t.onBeforeSetContent.dispatch(t, o);
7329
7330             // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
7331             // It will also be impossible to place the caret in the editor unless there is a BR element present
7332             if (!tinymce.isIE && (h.length === 0 || /^\s+$/.test(h))) {
7333                 o.content = t.dom.setHTML(t.getBody(), '<br mce_bogus="1" />', 1);
7334                 o.format = 'raw';
7335             }
7336
7337             o.content = t.dom.setHTML(t.getBody(), tinymce.trim(o.content));
7338
7339             if (o.format != 'raw' && t.settings.cleanup) {
7340                 o.getInner = true;
7341                 o.content = t.dom.setHTML(t.getBody(), t.serializer.serialize(t.getBody(), o));
7342             }
7343
7344             if (!o.no_events)
7345                 t.onSetContent.dispatch(t, o);
7346
7347             return o.content;
7348         },
7349
7350         getContent : function(o) {
7351             var t = this, h;
7352
7353             o = o || {};
7354             o.format = o.format || 'html';
7355             o.get = true;
7356
7357             if (!o.no_events)
7358                 t.onBeforeGetContent.dispatch(t, o);
7359
7360             if (o.format != 'raw' && t.settings.cleanup) {
7361                 o.getInner = true;
7362                 h = t.serializer.serialize(t.getBody(), o);
7363             } else
7364                 h = t.getBody().innerHTML;
7365
7366             h = h.replace(/^\s*|\s*$/g, '');
7367             o = {content : h};
7368             t.onGetContent.dispatch(t, o);
7369
7370             return o.content;
7371         },
7372
7373         isDirty : function() {
7374             var t = this;
7375
7376             return tinymce.trim(t.startContent) != tinymce.trim(t.getContent({format : 'raw', no_events : 1})) && !t.isNotDirty;
7377         },
7378
7379         getContainer : function() {
7380             var t = this;
7381
7382             if (!t.container)
7383                 t.container = DOM.get(t.editorContainer || t.id + '_parent');
7384
7385             return t.container;
7386         },
7387
7388         getContentAreaContainer : function() {
7389             return this.contentAreaContainer;
7390         },
7391
7392         getElement : function() {
7393             return DOM.get(this.settings.content_element || this.id);
7394         },
7395
7396         getWin : function() {
7397             var t = this, e;
7398
7399             if (!t.contentWindow) {
7400                 e = DOM.get(t.id + "_ifr");
7401
7402                 if (e)
7403                     t.contentWindow = e.contentWindow;
7404             }
7405
7406             return t.contentWindow;
7407         },
7408
7409         getDoc : function() {
7410             var t = this, w;
7411
7412             if (!t.contentDocument) {
7413                 w = t.getWin();
7414
7415                 if (w)
7416                     t.contentDocument = w.document;
7417             }
7418
7419             return t.contentDocument;
7420         },
7421
7422         getBody : function() {
7423             return this.bodyElement || this.getDoc().body;
7424         },
7425
7426         convertURL : function(u, n, e) {
7427             var t = this, s = t.settings;
7428
7429             // Use callback instead
7430             if (s.urlconverter_callback)
7431                 return t.execCallback('urlconverter_callback', u, e, true, n);
7432
7433             // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
7434             if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
7435                 return u;
7436
7437             // Convert to relative
7438             if (s.relative_urls)
7439                 return t.documentBaseURI.toRelative(u);
7440
7441             // Convert to absolute
7442             u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);
7443
7444             return u;
7445         },
7446
7447         addVisual : function(e) {
7448             var t = this, s = t.settings;
7449
7450             e = e || t.getBody();
7451
7452             if (!is(t.hasVisual))
7453                 t.hasVisual = s.visual;
7454
7455             each(t.dom.select('table,a', e), function(e) {
7456                 var v;
7457
7458                 switch (e.nodeName) {
7459                     case 'TABLE':
7460                         v = t.dom.getAttrib(e, 'border');
7461
7462                         if (!v || v == '0') {
7463                             if (t.hasVisual)
7464                                 t.dom.addClass(e, s.visual_table_class);
7465                             else
7466                                 t.dom.removeClass(e, s.visual_table_class);
7467                         }
7468
7469                         return;
7470
7471                     case 'A':
7472                         v = t.dom.getAttrib(e, 'name');
7473
7474                         if (v) {
7475                             if (t.hasVisual)
7476                                 t.dom.addClass(e, 'mceItemAnchor');
7477                             else
7478                                 t.dom.removeClass(e, 'mceItemAnchor');
7479                         }
7480
7481                         return;
7482                 }
7483             });
7484
7485             t.onVisualAid.dispatch(t, e, t.hasVisual);
7486         },
7487
7488         remove : function() {
7489             var t = this, e = t.getContainer();
7490
7491             t.removed = 1; // Cancels post remove event execution
7492             t.hide();
7493
7494             t.execCallback('remove_instance_callback', t);
7495             t.onRemove.dispatch(t);
7496
7497             // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command
7498             t.onExecCommand.listeners = [];
7499
7500             EditorManager.remove(t);
7501             DOM.remove(e);
7502         },
7503
7504         destroy : function(s) {
7505             var t = this;
7506
7507             // One time is enough
7508             if (t.destroyed)
7509                 return;
7510
7511             if (!s) {
7512                 tinymce.removeUnload(t.destroy);
7513                 tinyMCE.onBeforeUnload.remove(t._beforeUnload);
7514
7515                 // Manual destroy
7516                 if (t.theme.destroy)
7517                     t.theme.destroy();
7518
7519                 // Destroy controls, selection and dom
7520                 t.controlManager.destroy();
7521                 t.selection.destroy();
7522                 t.dom.destroy();
7523
7524                 // Remove all events
7525                 Event.clear(t.getWin());
7526                 Event.clear(t.getDoc());
7527                 Event.clear(t.getBody());
7528                 Event.clear(t.formElement);
7529             }
7530
7531             if (t.formElement) {
7532                 t.formElement.submit = t.formElement._mceOldSubmit;
7533                 t.formElement._mceOldSubmit = null;
7534             }
7535
7536             t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null;
7537
7538             if (t.selection)
7539                 t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null;
7540
7541             t.destroyed = 1;
7542         },
7543
7544         // Internal functions
7545
7546         _addEvents : function() {
7547             // 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset
7548             var t = this, i, s = t.settings, lo = {
7549                 mouseup : 'onMouseUp',
7550                 mousedown : 'onMouseDown',
7551                 click : 'onClick',
7552                 keyup : 'onKeyUp',
7553                 keydown : 'onKeyDown',
7554                 keypress : 'onKeyPress',
7555                 submit : 'onSubmit',
7556                 reset : 'onReset',
7557                 contextmenu : 'onContextMenu',
7558                 dblclick : 'onDblClick',
7559                 paste : 'onPaste' // Doesn't work in all browsers yet
7560             };
7561
7562             function eventHandler(e, o) {
7563                 var ty = e.type;
7564
7565                 // Don't fire events when it's removed
7566                 if (t.removed)
7567                     return;
7568
7569                 // Generic event handler
7570                 if (t.onEvent.dispatch(t, e, o) !== false) {
7571                     // Specific event handler
7572                     t[lo[e.fakeType || e.type]].dispatch(t, e, o);
7573                 }
7574             };
7575
7576             // Add DOM events
7577             each(lo, function(v, k) {
7578                 switch (k) {
7579                     case 'contextmenu':
7580                         if (tinymce.isOpera) {
7581                             // Fake contextmenu on Opera
7582                             Event.add(t.getDoc(), 'mousedown', function(e) {
7583                                 if (e.ctrlKey) {
7584                                     e.fakeType = 'contextmenu';
7585                                     eventHandler(e);
7586                                 }
7587                             });
7588                         } else
7589                             Event.add(t.getDoc(), k, eventHandler);
7590                         break;
7591
7592                     case 'paste':
7593                         Event.add(t.getBody(), k, function(e) {
7594                             var tx, h, el, r;
7595
7596                             // Get plain text data
7597                             if (e.clipboardData)
7598                                 tx = e.clipboardData.getData('text/plain');
7599                             else if (tinymce.isIE)
7600                                 tx = t.getWin().clipboardData.getData('Text');
7601
7602                             // Get HTML data
7603                             /*if (tinymce.isIE) {
7604                                 el = DOM.add(DOM.doc.body, 'div', {style : 'visibility:hidden;overflow:hidden;position:absolute;width:1px;height:1px'});
7605                                 r = DOM.doc.body.createTextRange();
7606                                 r.moveToElementText(el);
7607                                 r.execCommand('Paste');
7608                                 h = el.innerHTML;
7609                                 DOM.remove(el);
7610                             }*/
7611
7612                             eventHandler(e, {text : tx, html : h});
7613                         });
7614                         break;
7615
7616                     case 'submit':
7617                     case 'reset':
7618                         Event.add(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler);
7619                         break;
7620
7621                     default:
7622                         Event.add(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler);
7623                 }
7624             });
7625
7626             Event.add(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) {
7627                 t.focus(true);
7628             });
7629
7630             
7631             // Fixes bug where a specified document_base_uri could result in broken images
7632             // This will also fix drag drop of images in Gecko
7633             if (tinymce.isGecko) {
7634                 // Convert all images to absolute URLs
7635 /*                t.onSetContent.add(function(ed, o) {
7636                     each(ed.dom.select('img'), function(e) {
7637                         var v;
7638
7639                         if (v = e.getAttribute('mce_src'))
7640                             e.src = t.documentBaseURI.toAbsolute(v);
7641                     })
7642                 });*/
7643
7644                 Event.add(t.getDoc(), 'DOMNodeInserted', function(e) {
7645                     var v;
7646
7647                     e = e.target;
7648
7649                     if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('mce_src')))
7650                         e.src = t.documentBaseURI.toAbsolute(v);
7651                 });
7652             }
7653
7654             // Set various midas options in Gecko
7655             if (isGecko) {
7656                 function setOpts() {
7657                     var t = this, d = t.getDoc(), s = t.settings;
7658
7659                     if (isGecko) {
7660                         if (t._isHidden()) {
7661                             try {
7662                                 if (!s.content_editable)
7663                                     d.designMode = 'On';
7664                             } catch (ex) {
7665                                 // Fails if it's hidden
7666                             }
7667                         }
7668
7669                         try {
7670                             // Try new Gecko method
7671                             d.execCommand("styleWithCSS", 0, false);
7672                         } catch (ex) {
7673                             // Use old method
7674                             if (!t._isHidden())
7675                                 d.execCommand("useCSS", 0, true);
7676                         }
7677
7678                         if (!s.table_inline_editing)
7679                             try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {}
7680
7681                         if (!s.object_resizing)
7682                             try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {}
7683                     }
7684                 };
7685
7686                 t.onBeforeExecCommand.add(setOpts);
7687                 t.onMouseDown.add(setOpts);
7688             }
7689
7690             // Add node change handlers
7691             t.onMouseUp.add(t.nodeChanged);
7692             t.onClick.add(t.nodeChanged);
7693             t.onKeyUp.add(function(ed, e) {
7694                 if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.keyCode == 46 || e.keyCode == 8 || e.ctrlKey)
7695                     t.nodeChanged();
7696             });
7697
7698             // Add reset handler
7699             t.onReset.add(function() {
7700                 t.setContent(t.startContent, {format : 'raw'});
7701             });
7702
7703             if (t.getParam('tab_focus')) {
7704                 function tabCancel(ed, e) {
7705                     if (e.keyCode === 9)
7706                         return Event.cancel(e);
7707                 };
7708
7709                 function tabHandler(ed, e) {
7710                     var x, i, f, el, v;
7711
7712                     function find(d) {
7713                         f = DOM.getParent(ed.id, 'form');
7714                         el = f.elements;
7715
7716                         if (f) {
7717                             each(el, function(e, i) {
7718                                 if (e.id == ed.id) {
7719                                     x = i;
7720                                     return false;
7721                                 }
7722                             });
7723
7724                             if (d > 0) {
7725                                 for (i = x + 1; i < el.length; i++) {
7726                                     if (el[i].type != 'hidden')
7727                                         return el[i];
7728                                 }
7729                             } else {
7730                                 for (i = x - 1; i >= 0; i--) {
7731                                     if (el[i].type != 'hidden')
7732                                         return el[i];
7733                                 }
7734                             }
7735                         }
7736
7737                         return null;
7738                     };
7739
7740                     if (e.keyCode === 9) {
7741                         v = explode(ed.getParam('tab_focus'));
7742
7743                         if (v.length == 1) {
7744                             v[1] = v[0];
7745                             v[0] = ':prev';
7746                         }
7747
7748                         // Find element to focus
7749                         if (e.shiftKey) {
7750                             if (v[0] == ':prev')
7751                                 el = find(-1);
7752                             else
7753                                 el = DOM.get(v[0]);
7754                         } else {
7755                             if (v[1] == ':next')
7756                                 el = find(1);
7757                             else
7758                                 el = DOM.get(v[1]);
7759                         }
7760
7761                         if (el) {
7762                             if (ed = EditorManager.get(el.id || el.name))
7763                                 ed.focus();
7764                             else
7765                                 window.setTimeout(function() {window.focus();el.focus();}, 10);
7766
7767                             return Event.cancel(e);
7768                         }
7769                     }
7770                 };
7771
7772                 t.onKeyUp.add(tabCancel);
7773
7774                 if (isGecko) {
7775                     t.onKeyPress.add(tabHandler);
7776                     t.onKeyDown.add(tabCancel);
7777                 } else
7778                     t.onKeyDown.add(tabHandler);
7779             }
7780
7781             // Add shortcuts
7782             if (s.custom_shortcuts) {
7783                 if (s.custom_undo_redo_keyboard_shortcuts) {
7784                     t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo');
7785                     t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo');
7786                 }
7787
7788                 // Add default shortcuts for gecko
7789                 if (isGecko) {
7790                     t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');
7791                     t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');
7792                     t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');
7793                 }
7794
7795                 // BlockFormat shortcuts keys
7796                 for (i=1; i<=6; i++)
7797                     t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, '<h' + i + '>']);
7798
7799                 t.addShortcut('ctrl+7', '', ['FormatBlock', false, '<p>']);
7800                 t.addShortcut('ctrl+8', '', ['FormatBlock', false, '<div>']);
7801                 t.addShortcut('ctrl+9', '', ['FormatBlock', false, '<address>']);
7802
7803                 function find(e) {
7804                     var v = null;
7805
7806                     if (!e.altKey && !e.ctrlKey && !e.metaKey)
7807                         return v;
7808
7809                     each(t.shortcuts, function(o) {
7810                         if (o.ctrl != e.ctrlKey && (!tinymce.isMac || o.ctrl == e.metaKey))
7811                             return;
7812
7813                         if (o.alt != e.altKey)
7814                             return;
7815
7816                         if (o.shift != e.shiftKey)
7817                             return;
7818
7819                         if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
7820                             v = o;
7821                             return false;
7822                         }
7823                     });
7824
7825                     return v;
7826                 };
7827
7828                 t.onKeyUp.add(function(ed, e) {
7829                     var o = find(e);
7830
7831                     if (o)
7832                         return Event.cancel(e);
7833                 });
7834
7835                 t.onKeyPress.add(function(ed, e) {
7836                     var o = find(e);
7837
7838                     if (o)
7839                         return Event.cancel(e);
7840                 });
7841
7842                 t.onKeyDown.add(function(ed, e) {
7843                     var o = find(e);
7844
7845                     if (o) {
7846                         o.func.call(o.scope);
7847                         return Event.cancel(e);
7848                     }
7849                 });
7850             }
7851
7852             if (tinymce.isIE) {
7853                 // Fix so resize will only update the width and height attributes not the styles of an image
7854                 // It will also block mceItemNoResize items
7855                 Event.add(t.getDoc(), 'controlselect', function(e) {
7856                     var re = t.resizeInfo, cb;
7857
7858                     e = e.target;
7859                     e.removeAttribute('mce_style'); // Remove this one since it might change
7860
7861                     // Don't do this action for non image elements
7862                     if (e.nodeName !== 'IMG')
7863                         return;
7864
7865                     if (re)
7866                         Event.remove(re.node, re.ev, re.cb);
7867
7868                     if (!t.dom.hasClass(e, 'mceItemNoResize')) {
7869                         ev = 'resizeend';
7870                         cb = Event.add(e, ev, function(e) {
7871                             var v;
7872
7873                             e = e.target;
7874
7875                             if (v = t.dom.getStyle(e, 'width')) {
7876                                 t.dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, ''));
7877                                 t.dom.setStyle(e, 'width', '');
7878                             }
7879
7880                             if (v = t.dom.getStyle(e, 'height')) {
7881                                 t.dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, ''));
7882                                 t.dom.setStyle(e, 'height', '');
7883                             }
7884                         });
7885                     } else {
7886                         ev = 'resizestart';
7887                         cb = Event.add(e, 'resizestart', Event.cancel, Event);
7888                     }
7889
7890                     re = t.resizeInfo = {
7891                         node : e,
7892                         ev : ev,
7893                         cb : cb
7894                     };
7895                 });
7896
7897                 t.onKeyDown.add(function(ed, e) {
7898                     switch (e.keyCode) {
7899                         case 8:
7900                             // Fix IE control + backspace browser bug
7901                             if (t.selection.getRng().item) {
7902                                 t.selection.getRng().item(0).removeNode();
7903                                 return Event.cancel(e);
7904                             }
7905                     }
7906                 });
7907             }
7908
7909             if (tinymce.isOpera) {
7910                 t.onClick.add(function(ed, e) {
7911                     Event.prevent(e);
7912                 });
7913             }
7914
7915             // Add custom undo/redo handlers
7916             if (s.custom_undo_redo) {
7917                 function addUndo() {
7918                     t.undoManager.typing = 0;
7919                     t.undoManager.add();
7920                 };
7921
7922                 // Add undo level on editor blur
7923                 if (tinymce.isIE) {
7924                     Event.add(t.getWin(), 'blur', function(e) {
7925                         var n;
7926
7927                         // Check added for fullscreen bug
7928                         if (t.selection) {
7929                             n = t.selection.getNode();
7930
7931                             // Add undo level is selection was lost to another document
7932                             if (!t.removed && n.ownerDocument && n.ownerDocument != t.getDoc())
7933                                 addUndo();
7934                         }
7935                     });
7936                 } else {
7937                     Event.add(t.getDoc(), 'blur', function() {
7938                         if (t.selection && !t.removed)
7939                             addUndo();
7940                     });
7941                 }
7942
7943                 t.onMouseDown.add(addUndo);
7944
7945                 t.onKeyUp.add(function(ed, e) {
7946                     if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) {
7947                         t.undoManager.typing = 0;
7948                         t.undoManager.add();
7949                     }
7950                 });
7951
7952                 t.onKeyDown.add(function(ed, e) {
7953                     // Is caracter positon keys
7954                     if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {
7955                         if (t.undoManager.typing) {
7956                             t.undoManager.add();
7957                             t.undoManager.typing = 0;
7958                         }
7959
7960                         return;
7961                     }
7962
7963                     if (!t.undoManager.typing) {
7964                         t.undoManager.add();
7965                         t.undoManager.typing = 1;
7966                     }
7967                 });
7968             }
7969         },
7970
7971         _convertInlineElements : function() {
7972             var t = this, s = t.settings, dom = t.dom, v, e, na, st, sp;
7973
7974             function convert(ed, o) {
7975                 if (!s.inline_styles)
7976                     return;
7977
7978                 if (o.get) {
7979                     each(t.dom.select('table,u,strike', o.node), function(n) {
7980                         switch (n.nodeName) {
7981                             case 'TABLE':
7982                                 if (v = dom.getAttrib(n, 'height')) {
7983                                     dom.setStyle(n, 'height', v);
7984                                     dom.setAttrib(n, 'height', '');
7985                                 }
7986                                 break;
7987
7988                             case 'U':
7989                             case 'STRIKE':
7990                                 sp = dom.create('span', {style : dom.getAttrib(n, 'style')});
7991                                 sp.style.textDecoration = n.nodeName == 'U' ? 'underline' : 'line-through';
7992                                 dom.setAttrib(sp, 'mce_style', '');
7993                                 dom.replace(sp, n, 1);
7994                                 break;
7995                         }
7996                     });
7997                 } else if (o.set) {
7998                     each(t.dom.select('table,span', o.node), function(n) {
7999                         if (n.nodeName == 'TABLE') {
8000                             if (v = dom.getStyle(n, 'height'))
8001                                 dom.setAttrib(n, 'height', v.replace(/[^0-9%]+/g, ''));
8002                         } else {
8003                             // Convert spans to elements
8004                             if (n.style.textDecoration == 'underline')
8005                                 na = 'u';
8006                             else if (n.style.textDecoration == 'line-through')
8007                                 na = 'strike';
8008                             else
8009                                 na = '';
8010
8011                             if (na) {
8012                                 n.style.textDecoration = '';
8013                                 dom.setAttrib(n, 'mce_style', '');
8014
8015                                 e = dom.create(na, {
8016                                     style : dom.getAttrib(n, 'style')
8017                                 });
8018
8019                                 dom.replace(e, n, 1);
8020                             }
8021                         }
8022                     });
8023                 }
8024             };
8025
8026             t.onPreProcess.add(convert);
8027
8028             if (!s.cleanup_on_startup) {
8029                 t.onInit.add(function() {
8030                     convert(t, {node : t.getBody(), set : 1});
8031                 });
8032             }
8033         },
8034
8035         _convertFonts : function() {
8036             var t = this, s = t.settings, dom = t.dom, fz, fzn, sl, cl;
8037
8038             // No need
8039             if (!s.inline_styles)
8040                 return;
8041
8042             // Font pt values and font size names
8043             fz = [8, 10, 12, 14, 18, 24, 36];
8044             fzn = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large'];
8045
8046             if (sl = s.font_size_style_values)
8047                 sl = explode(sl);
8048
8049             if (cl = s.font_size_classes)
8050                 cl = explode(cl);
8051
8052             function convertToFonts(no) {
8053                 var n, f, nl, x, i, v, st;
8054
8055                 // Convert spans to fonts on non WebKit browsers
8056                 if (tinymce.isWebKit || !s.inline_styles)
8057                     return;
8058
8059                 nl = t.dom.select('span', no);
8060                 for (x = nl.length - 1; x >= 0; x--) {
8061                     n = nl[x];
8062
8063                     f = dom.create('font', {
8064                         color : dom.toHex(dom.getStyle(n, 'color')),
8065                         face : dom.getStyle(n, 'fontFamily'),
8066                         style : dom.getAttrib(n, 'style'),
8067                         'class' : dom.getAttrib(n, 'class')
8068                     });
8069
8070                     // Clear color and font family
8071                     st = f.style;
8072                     if (st.color || st.fontFamily) {
8073                         st.color = st.fontFamily = '';
8074                         dom.setAttrib(f, 'mce_style', ''); // Remove cached style data
8075                     }
8076
8077                     if (sl) {
8078                         i = inArray(sl, dom.getStyle(n, 'fontSize'));
8079
8080                         if (i != -1) {
8081                             dom.setAttrib(f, 'size', '' + (i + 1 || 1));
8082                             f.style.fontSize = '';
8083                         }
8084                     } else if (cl) {
8085                         i = inArray(cl, dom.getAttrib(n, 'class'));
8086                         v = dom.getStyle(n, 'fontSize');
8087
8088                         if (i == -1 && v.indexOf('pt') > 0)
8089                             i = inArray(fz, parseInt(v));
8090
8091                         if (i == -1)
8092                             i = inArray(fzn, v);
8093
8094                         if (i != -1) {
8095                             dom.setAttrib(f, 'size', '' + (i + 1 || 1));
8096                             f.style.fontSize = '';
8097                         }
8098                     }
8099
8100                     if (f.color || f.face || f.size) {
8101                         f.style.fontFamily = '';
8102                         dom.setAttrib(f, 'mce_style', '');
8103                         dom.replace(f, n, 1);
8104                     }
8105
8106                     f = n = null;
8107                 }
8108             };
8109
8110             // Run on setup
8111             t.onSetContent.add(function(ed, o) {
8112                 convertToFonts(ed.getBody());
8113             });
8114
8115             // Run on cleanup
8116             t.onPreProcess.add(function(ed, o) {
8117                 var n, sp, nl, x;
8118
8119                 // Keep unit tests happy
8120                 if (!s.inline_styles)
8121                     return;
8122
8123                 if (o.get) {
8124                     nl = t.dom.select('font', o.node);
8125                     for (x = nl.length - 1; x >= 0; x--) {
8126                         n = nl[x];
8127
8128                         sp = dom.create('span', {
8129                             style : dom.getAttrib(n, 'style'),
8130                             'class' : dom.getAttrib(n, 'class')
8131                         });
8132
8133                         dom.setStyles(sp, {
8134                             fontFamily : dom.getAttrib(n, 'face'),
8135                             color : dom.getAttrib(n, 'color'),
8136                             backgroundColor : n.style.backgroundColor
8137                         });
8138
8139                         if (n.size) {
8140                             if (sl)
8141                                 dom.setStyle(sp, 'fontSize', sl[parseInt(n.size) - 1]);
8142                             else
8143                                 dom.setAttrib(sp, 'class', cl[parseInt(n.size) - 1]);
8144                         }
8145
8146                         dom.setAttrib(sp, 'mce_style', '');
8147                         dom.replace(sp, n, 1);
8148                     }
8149                 }
8150             });
8151         },
8152
8153         _isHidden : function() {
8154             var s;
8155
8156             if (!isGecko)
8157                 return 0;
8158
8159             // Weird, wheres that cursor selection?
8160             s = this.selection.getSel();
8161             return (!s || !s.rangeCount || s.rangeCount == 0);
8162         },
8163
8164         // Fix for bug #1867292
8165         _fixNesting : function(s) {
8166             var d = [], i;
8167
8168             s = s.replace(/<(\/)?([^\s>]+)[^>]*?>/g, function(a, b, c) {
8169                 var e;
8170
8171                 // Handle end element
8172                 if (b === '/') {
8173                     if (!d.length)
8174                         return '';
8175
8176                     if (c !== d[d.length - 1].tag) {
8177                         for (i=d.length - 1; i>=0; i--) {
8178                             if (d[i].tag === c) {
8179                                 d[i].close = 1;
8180                                 break;
8181                             }
8182                         }
8183
8184                         return '';
8185                     } else {
8186                         d.pop();
8187
8188                         if (d.length && d[d.length - 1].close) {
8189                             a = a + '</' + d[d.length - 1].tag + '>';
8190                             d.pop();
8191                         }
8192                     }
8193                 } else {
8194                     // Ignore these
8195                     if (/^(br|hr|input|meta|img|link|param)$/i.test(c))
8196                         return a;
8197
8198                     // Ignore closed ones
8199                     if (/\/>$/.test(a))
8200                         return a;
8201
8202                     d.push({tag : c}); // Push start element
8203                 }
8204
8205                 return a;
8206             });
8207
8208             // End all open tags
8209             for (i=d.length - 1; i>=0; i--)
8210                 s += '</' + d[i].tag + '>';
8211
8212             return s;
8213         }
8214
8215         });
8216 })();
8217
8218 /* file:jscripts/tiny_mce/classes/EditorCommands.js */
8219
8220 (function() {
8221     var each = tinymce.each, isIE = tinymce.isIE, isGecko = tinymce.isGecko, isOpera = tinymce.isOpera, isWebKit = tinymce.isWebKit;
8222
8223     tinymce.create('tinymce.EditorCommands', {
8224         EditorCommands : function(ed) {
8225             this.editor = ed;
8226         },
8227
8228         execCommand : function(cmd, ui, val) {
8229             var t = this, ed = t.editor, f;
8230
8231             switch (cmd) {
8232                 case 'Cut':
8233                 case 'Copy':
8234                 case 'Paste':
8235                     try {
8236                         ed.getDoc().execCommand(cmd, ui, val);
8237                     } catch (ex) {
8238                         if (isGecko) {
8239                             ed.windowManager.confirm(ed.getLang('clipboard_msg'), function(s) {
8240                                 if (s)
8241                                     window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');
8242                             });
8243                         } else
8244                             ed.windowManager.alert(ed.getLang('clipboard_no_support'));
8245                     }
8246
8247                     return true;
8248
8249                 // Ignore these
8250                 case 'mceResetDesignMode':
8251                 case 'mceBeginUndoLevel':
8252                     return true;
8253
8254                 // Ignore these
8255                 case 'unlink':
8256                     t.UnLink();
8257                     return true;
8258
8259                 // Bundle these together
8260                 case 'JustifyLeft':
8261                 case 'JustifyCenter':
8262                 case 'JustifyRight':
8263                 case 'JustifyFull':
8264                     t.mceJustify(cmd, cmd.substring(7).toLowerCase());
8265                     return true;
8266
8267                 case 'mceEndUndoLevel':
8268                 case 'mceAddUndoLevel':
8269                     ed.undoManager.add();
8270                     return true;
8271
8272                 default:
8273                     f = this[cmd];
8274
8275                     if (f) {
8276                         f.call(this, ui, val);
8277                         return true;
8278                     }
8279             }
8280
8281             return false;
8282         },
8283
8284         Indent : function() {
8285             var ed = this.editor, d = ed.dom, s = ed.selection, e, iv, iu;
8286
8287             // Setup indent level
8288             iv = ed.settings.indentation;
8289             iu = /[a-z%]+$/i.exec(iv);
8290             iv = parseInt(iv);
8291
8292             if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {
8293                 each(this._getSelectedBlocks(), function(e) {
8294                     d.setStyle(e, 'paddingLeft', (parseInt(e.style.paddingLeft || 0) + iv) + iu);
8295                 });
8296
8297                 return;
8298             }
8299
8300             ed.getDoc().execCommand('Indent', false, null);
8301
8302             if (isIE) {
8303                 d.getParent(s.getNode(), function(n) {
8304                     if (n.nodeName == 'BLOCKQUOTE') {
8305                         n.dir = n.style.cssText = '';
8306                     }
8307                 });
8308             }
8309         },
8310
8311         Outdent : function() {
8312             var ed = this.editor, d = ed.dom, s = ed.selection, e, v, iv, iu;
8313
8314             // Setup indent level
8315             iv = ed.settings.indentation;
8316             iu = /[a-z%]+$/i.exec(iv);
8317             iv = parseInt(iv);
8318
8319             if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {
8320                 each(this._getSelectedBlocks(), function(e) {
8321                     v = Math.max(0, parseInt(e.style.paddingLeft || 0) - iv);
8322                     d.setStyle(e, 'paddingLeft', v ? v + iu : '');
8323                 });
8324
8325                 return;
8326             }
8327
8328             ed.getDoc().execCommand('Outdent', false, null);
8329         },
8330
8331         mceSetAttribute : function(u, v) {
8332             var ed = this.editor, d = ed.dom, e;
8333
8334             if (e = d.getParent(ed.selection.getNode(), d.isBlock))
8335                 d.setAttrib(e, v.name, v.value);
8336         },
8337
8338         mceSetContent : function(u, v) {
8339             this.editor.setContent(v);
8340         },
8341
8342         mceToggleVisualAid : function() {
8343             var ed = this.editor;
8344
8345             ed.hasVisual = !ed.hasVisual;
8346             ed.addVisual();
8347         },
8348
8349         mceReplaceContent : function(u, v) {
8350             var s = this.editor.selection;
8351
8352             s.setContent(v.replace(/\{\$selection\}/g, s.getContent({format : 'text'})));
8353         },
8354
8355         mceInsertLink : function(u, v) {
8356             var ed = this.editor, e = ed.dom.getParent(ed.selection.getNode(), 'A');
8357
8358             if (tinymce.is(v, 'string'))
8359                 v = {href : v};
8360
8361             function set(e) {
8362                 each(v, function(v, k) {
8363                     ed.dom.setAttrib(e, k, v);
8364                 });
8365             };
8366
8367             if (!e) {
8368                 ed.execCommand('CreateLink', false, 'javascript:mctmp(0);');
8369                 each(ed.dom.select('a'), function(e) {
8370                     if (e.href == 'javascript:mctmp(0);')
8371                         set(e);
8372                 });
8373             } else {
8374                 if (v.href)
8375                     set(e);
8376                 else
8377                     ed.dom.remove(e, 1);
8378             }
8379         },
8380
8381         UnLink : function() {
8382             var ed = this.editor, s = ed.selection;
8383
8384             if (s.isCollapsed())
8385                 s.select(s.getNode());
8386
8387             ed.getDoc().execCommand('unlink', false, null);
8388             s.collapse(0);
8389         },
8390
8391         FontName : function(u, v) {
8392             var t = this, ed = t.editor, s = ed.selection, e;
8393
8394             if (!v) {
8395                 if (s.isCollapsed())
8396                     s.select(s.getNode());
8397
8398                 t.RemoveFormat();
8399             } else
8400                 ed.getDoc().execCommand('FontName', false, v);
8401         },
8402
8403         queryCommandValue : function(c) {
8404             var f = this['queryValue' + c];
8405
8406             if (f)
8407                 return f.call(this, c);
8408
8409             return false;
8410         },
8411
8412         queryCommandState : function(cmd) {
8413             var f;
8414
8415             switch (cmd) {
8416                 // Bundle these together
8417                 case 'JustifyLeft':
8418                 case 'JustifyCenter':
8419                 case 'JustifyRight':
8420                 case 'JustifyFull':
8421                     return this.queryStateJustify(cmd, cmd.substring(7).toLowerCase());
8422
8423                 default:
8424                     if (f = this['queryState' + cmd])
8425                         return f.call(this, cmd);
8426             }
8427
8428             return -1;
8429         },
8430
8431         _queryState : function(c) {
8432             try {
8433                 return this.editor.getDoc().queryCommandState(c);
8434             } catch (ex) {
8435                 // Ignore exception
8436             }
8437         },
8438
8439         _queryVal : function(c) {
8440             try {
8441                 return this.editor.getDoc().queryCommandValue(c);
8442             } catch (ex) {
8443                 // Ignore exception
8444             }
8445         },
8446
8447         queryValueFontSize : function() {
8448             var ed = this.editor, v = 0, p;
8449
8450             if (isOpera || isWebKit) {
8451                 if (p = ed.dom.getParent(ed.selection.getNode(), 'FONT'))
8452                     v = p.size;
8453
8454                 return v;
8455             }
8456
8457             return this._queryVal('FontSize');
8458         },
8459
8460         queryValueFontName : function() {
8461             var ed = this.editor, v = 0, p;
8462
8463             if (p = ed.dom.getParent(ed.selection.getNode(), 'FONT'))
8464                 v = p.face;
8465
8466             if (!v)
8467                 v = this._queryVal('FontName');
8468
8469             return v;
8470         },
8471
8472         mceJustify : function(c, v) {
8473             var ed = this.editor, se = ed.selection, n = se.getNode(), nn = n.nodeName, bl, nb, dom = ed.dom, rm;
8474
8475             if (ed.settings.inline_styles && this.queryStateJustify(c, v))
8476                 rm = 1;
8477
8478             bl = dom.getParent(n, ed.dom.isBlock);
8479
8480             if (nn == 'IMG') {
8481                 if (v == 'full')
8482                     return;
8483
8484                 if (rm) {
8485                     if (v == 'center')
8486                         dom.setStyle(n.parentNode, 'textAlign', '');
8487
8488                     dom.setStyle(n, 'float', '');
8489                     this.mceRepaint();
8490                     return;
8491                 }
8492
8493                 if (v == 'center') {
8494                     // Do not change table elements
8495                     if (/^(TD|TH)$/.test(bl.nodeName))
8496                         bl = 0;
8497
8498                     if (!bl || bl.childNodes.length > 1) {
8499                         nb = dom.create('p');
8500                         nb.appendChild(n.cloneNode(false));
8501
8502                         if (bl)
8503                             dom.insertAfter(nb, bl);
8504                         else
8505                             dom.insertAfter(nb, n);
8506
8507                         dom.remove(n);
8508                         n = nb.firstChild;
8509                         bl = nb;
8510                     }
8511
8512                     dom.setStyle(bl, 'textAlign', v);
8513                     dom.setStyle(n, 'float', '');
8514                 } else {
8515                     dom.setStyle(n, 'float', v);
8516                     dom.setStyle(n.parentNode, 'textAlign', '');
8517                 }
8518
8519                 this.mceRepaint();
8520                 return;
8521             }
8522
8523             // Handle the alignment outselfs, less quirks in all browsers
8524             if (ed.settings.inline_styles && ed.settings.forced_root_block) {
8525                 if (rm)
8526                     v = '';
8527
8528                 each(this._getSelectedBlocks(dom.getParent(se.getStart(), dom.isBlock), dom.getParent(se.getEnd(), dom.isBlock)), function(e) {
8529                     dom.setAttrib(e, 'align', '');
8530                     dom.setStyle(e, 'textAlign', v == 'full' ? 'justify' : v);
8531                 });
8532
8533                 return;
8534             } else if (!rm)
8535                 ed.getDoc().execCommand(c, false, null);
8536
8537             if (ed.settings.inline_styles) {
8538                 if (rm) {
8539                     dom.getParent(ed.selection.getNode(), function(n) {
8540                         if (n.style && n.style.textAlign)
8541                             dom.setStyle(n, 'textAlign', '');
8542                     });
8543
8544                     return;
8545                 }
8546
8547                 each(dom.select('*'), function(n) {
8548                     var v = n.align;
8549
8550                     if (v) {
8551                         if (v == 'full')
8552                             v = 'justify';
8553
8554                         dom.setStyle(n, 'textAlign', v);
8555                         dom.setAttrib(n, 'align', '');
8556                     }
8557                 });
8558             }
8559         },
8560
8561         mceSetCSSClass : function(u, v) {
8562             this.mceSetStyleInfo(0, {command : 'setattrib', name : 'class', value : v});
8563         },
8564
8565         getSelectedElement : function() {
8566             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;
8567
8568             if (se.isCollapsed() || r.item)
8569                 return se.getNode();
8570
8571             // Setup regexp
8572             re = ed.settings.merge_styles_invalid_parents;
8573             if (tinymce.is(re, 'string'))
8574                 re = new RegExp(re, 'i');
8575
8576             if (isIE) {
8577                 r1 = r.duplicate();
8578                 r1.collapse(true);
8579                 sc = r1.parentElement();
8580
8581                 r2 = r.duplicate();
8582                 r2.collapse(false);
8583                 ec = r2.parentElement();
8584
8585                 if (sc != ec) {
8586                     r1.move('character', 1);
8587                     sc = r1.parentElement();
8588                 }
8589
8590                 if (sc == ec) {
8591                     r1 = r.duplicate();
8592                     r1.moveToElementText(sc);
8593
8594                     if (r1.compareEndPoints('StartToStart', r) == 0 && r1.compareEndPoints('EndToEnd', r) == 0)
8595                         return re && re.test(sc.nodeName) ? null : sc;
8596                 }
8597             } else {
8598                 function getParent(n) {
8599                     return dom.getParent(n, function(n) {return n.nodeType == 1;});
8600                 };
8601
8602                 sc = r.startContainer;
8603                 ec = r.endContainer;
8604                 so = r.startOffset;
8605                 eo = r.endOffset;
8606
8607                 if (!r.collapsed) {
8608                     if (sc == ec) {
8609                         if (so - eo < 2) {
8610                             if (sc.hasChildNodes()) {
8611                                 sp = sc.childNodes[so];
8612                                 return re && re.test(sp.nodeName) ? null : sp;
8613                             }
8614                         }
8615                     }
8616                 }
8617
8618                 if (sc.nodeType != 3 || ec.nodeType != 3)
8619                     return null;
8620
8621                 if (so == 0) {
8622                     sp = getParent(sc);
8623
8624                     if (sp && sp.firstChild != sc)
8625                         sp = null;
8626                 }
8627
8628                 if (so == sc.nodeValue.length) {
8629                     e = sc.nextSibling;
8630
8631                     if (e && e.nodeType == 1)
8632                         sp = sc.nextSibling;
8633                 }
8634
8635                 if (eo == 0) {
8636                     e = ec.previousSibling;
8637
8638                     if (e && e.nodeType == 1)
8639                         ep = e;
8640                 }
8641
8642                 if (eo == ec.nodeValue.length) {
8643                     ep = getParent(ec);
8644
8645                     if (ep && ep.lastChild != ec)
8646                         ep = null;
8647                 }
8648
8649                 // Same element
8650                 if (sp == ep)
8651                     return re && sp && re.test(sp.nodeName) ? null : sp;
8652             }
8653
8654             return null;
8655         },
8656
8657         InsertHorizontalRule : function() {
8658             // Fix for Gecko <hr size="1" /> issue and IE bug rep(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");
8659             if (isGecko || isIE)
8660                 this.editor.selection.setContent('<hr />');
8661             else
8662                 this.editor.getDoc().execCommand('InsertHorizontalRule', false, '');
8663         },
8664
8665         RemoveFormat : function() {
8666             var t = this, ed = t.editor, s = ed.selection, b;
8667
8668             // Safari breaks tables
8669             if (isWebKit)
8670                 s.setContent(s.getContent({format : 'raw'}).replace(/(<(span|b|i|strong|em|strike) [^>]+>|<(span|b|i|strong|em|strike)>|<\/(span|b|i|strong|em|strike)>|)/g, ''), {format : 'raw'});
8671             else
8672                 ed.getDoc().execCommand('RemoveFormat', false, null);
8673
8674             t.mceSetStyleInfo(0, {command : 'removeformat'});
8675             ed.addVisual();
8676         },
8677
8678         mceSetStyleInfo : function(u, v) {
8679             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;
8680
8681             function set(n, e) {
8682                 if (n.nodeType == 1) {
8683                     switch (v.command) {
8684                         case 'setattrib':
8685                             return dom.setAttrib(n, v.name, v.value);
8686
8687                         case 'setstyle':
8688                             return dom.setStyle(n, v.name, v.value);
8689
8690                         case 'removeformat':
8691                             return dom.setAttrib(n, 'class', '');
8692                     }
8693                 }
8694             };
8695
8696             // Setup regexp
8697             re = ed.settings.merge_styles_invalid_parents;
8698             if (tinymce.is(re, 'string'))
8699                 re = new RegExp(re, 'i');
8700
8701             // Set style info on selected element
8702             if (e = t.getSelectedElement())
8703                 set(e, 1);
8704             else {
8705                 // Generate wrappers and set styles on them
8706                 d.execCommand('FontName', false, '__');
8707                 each(isWebKit ? dom.select('span') : dom.select('font'), function(n) {
8708                     var sp, e;
8709
8710                     if (dom.getAttrib(n, 'face') == '__' || n.style.fontFamily === '__') {
8711                         sp = dom.create(nn, {mce_new : '1'});
8712
8713                         set(sp);
8714
8715                         each (n.childNodes, function(n) {
8716                             sp.appendChild(n.cloneNode(true));
8717                         });
8718
8719                         dom.replace(sp, n);
8720                     }
8721                 });
8722             }
8723
8724             // Remove wrappers inside new ones
8725             each(dom.select(nn).reverse(), function(n) {
8726                 var p = n.parentNode;
8727
8728                 // Check if it's an old span in a new wrapper
8729                 if (!dom.getAttrib(n, 'mce_new')) {
8730                     // Find new wrapper
8731                     p = dom.getParent(n, function(n) {
8732                         return n.nodeType == 1 && dom.getAttrib(n, 'mce_new');
8733                     });
8734
8735                     if (p)
8736                         dom.remove(n, 1);
8737                 }
8738             });
8739
8740             // Merge wrappers with parent wrappers
8741             each(dom.select(nn).reverse(), function(n) {
8742                 var p = n.parentNode;
8743
8744                 if (!p || !dom.getAttrib(n, 'mce_new'))
8745                     return;
8746
8747                 // Has parent of the same type and only child
8748                 if (p.nodeName == nn.toUpperCase() && p.childNodes.length == 1)
8749                     return dom.remove(p, 1);
8750
8751                 // Has parent that is more suitable to have the class and only child
8752                 if (n.nodeType == 1 && (!re || !re.test(p.nodeName)) && p.childNodes.length == 1) {
8753                     set(p); // Set style info on parent instead
8754                     dom.setAttrib(n, 'class', '');
8755                 }
8756             });
8757
8758             // Remove empty wrappers
8759             each(dom.select(nn).reverse(), function(n) {
8760                 if (dom.getAttrib(n, 'mce_new') || (dom.getAttribs(n).length <= 1 && n.className === '')) {
8761                     if (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style'))
8762                         return dom.remove(n, 1);
8763
8764                     dom.setAttrib(n, 'mce_new', ''); // Remove mce_new marker
8765                 }
8766             });
8767
8768             s.moveToBookmark(b);
8769         },
8770
8771         queryStateJustify : function(c, v) {
8772             var ed = this.editor, n = ed.selection.getNode(), dom = ed.dom;
8773
8774             if (n && n.nodeName == 'IMG') {
8775                 if (dom.getStyle(n, 'float') == v)
8776                     return 1;
8777
8778                 return n.parentNode.style.textAlign == v;
8779             }
8780
8781             n = dom.getParent(ed.selection.getStart(), function(n) {
8782                 return n.nodeType == 1 && n.style.textAlign;
8783             });
8784
8785             if (v == 'full')
8786                 v = 'justify';
8787
8788             if (ed.settings.inline_styles)
8789                 return (n && n.style.textAlign == v);
8790
8791             return this._queryState(c);
8792         },
8793
8794         HiliteColor : function(ui, val) {
8795             var t = this, ed = t.editor, d = ed.getDoc();
8796
8797             function set(s) {
8798                 if (!isGecko)
8799                     return;
8800
8801                 try {
8802                     // Try new Gecko method
8803                     d.execCommand("styleWithCSS", 0, s);
8804                 } catch (ex) {
8805                     // Use old
8806                     d.execCommand("useCSS", 0, !s);
8807                 }
8808             };
8809
8810             if (isGecko || isOpera) {
8811                 set(true);
8812                 d.execCommand('hilitecolor', false, val);
8813                 set(false);
8814             } else
8815                 d.execCommand('BackColor', false, val);
8816         },
8817
8818         Undo : function() {
8819             var ed = this.editor;
8820
8821             if (ed.settings.custom_undo_redo) {
8822                 ed.undoManager.undo();
8823                 ed.nodeChanged();
8824             } else
8825                 ed.getDoc().execCommand('Undo', false, null);
8826         },
8827
8828         Redo : function() {
8829             var ed = this.editor;
8830
8831             if (ed.settings.custom_undo_redo) {
8832                 ed.undoManager.redo();
8833                 ed.nodeChanged();
8834             } else
8835                 ed.getDoc().execCommand('Redo', false, null);
8836         },
8837
8838         FormatBlock : function(ui, val) {
8839             var t = this, ed = t.editor;
8840
8841             val = ed.settings.forced_root_block ? (val || '<p>') : val;
8842
8843             if (/^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(ed.selection.getNode().nodeName))
8844                 t.mceRemoveNode();
8845
8846             if (val.indexOf('<') == -1)
8847                 val = '<' + val + '>';
8848
8849             if (tinymce.isGecko)
8850                 val = val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi, '$1');
8851
8852             ed.getDoc().execCommand('FormatBlock', false, val);
8853         },
8854
8855         mceCleanup : function() {
8856             var ed = this.editor, s = ed.selection, b = s.getBookmark();
8857             ed.setContent(ed.getContent());
8858             s.moveToBookmark(b);
8859         },
8860
8861         mceRemoveNode : function(ui, val) {
8862             var ed = this.editor, s = ed.selection, b, n = val || s.getNode();
8863
8864             // Make sure that the body node isn't removed
8865             if (n == ed.getBody())
8866                 return;
8867
8868             b = s.getBookmark();
8869             ed.dom.remove(n, 1);
8870             s.moveToBookmark(b);
8871             ed.nodeChanged();
8872         },
8873
8874         mceSelectNodeDepth : function(ui, val) {
8875             var ed = this.editor, s = ed.selection, c = 0;
8876
8877             ed.dom.getParent(s.getNode(), function(n) {
8878                 if (n.nodeType == 1 && c++ == val) {
8879                     s.select(n);
8880                     ed.nodeChanged();
8881                     return false;
8882                 }
8883             }, ed.getBody());
8884         },
8885
8886         mceSelectNode : function(u, v) {
8887             this.editor.selection.select(v);
8888         },
8889
8890         mceInsertContent : function(ui, val) {
8891             this.editor.selection.setContent(val);
8892         },
8893
8894         mceInsertRawHTML : function(ui, val) {
8895             var ed = this.editor;
8896
8897             ed.selection.setContent('tiny_mce_marker');
8898             ed.setContent(ed.getContent().replace(/tiny_mce_marker/g, val));
8899         },
8900
8901         mceRepaint : function() {
8902             var s, b, e = this.editor;
8903
8904             if (tinymce.isGecko) {
8905                 try {
8906                     s = e.selection;
8907                     b = s.getBookmark(true);
8908
8909                     if (s.getSel())
8910                         s.getSel().selectAllChildren(e.getBody());
8911
8912                     s.collapse(true);
8913                     s.moveToBookmark(b);
8914                 } catch (ex) {
8915                     // Ignore
8916                 }
8917             }
8918         },
8919
8920         queryStateUnderline : function() {
8921             var ed = this.editor, n;
8922
8923             if (n && n.nodeName == 'A')
8924                 return false;
8925
8926             return this._queryState('Underline');
8927         },
8928
8929         queryStateOutdent : function() {
8930             var ed = this.editor, n;
8931
8932             if (ed.settings.inline_styles) {
8933                 if ((n = ed.dom.getParent(ed.selection.getStart(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)
8934                     return true;
8935
8936                 if ((n = ed.dom.getParent(ed.selection.getEnd(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)
8937                     return true;
8938             } else
8939                 return !!ed.dom.getParent(ed.selection.getNode(), 'BLOCKQUOTE');
8940
8941             return this.queryStateInsertUnorderedList() || this.queryStateInsertOrderedList();
8942         },
8943
8944         queryStateInsertUnorderedList : function() {
8945             return this.editor.dom.getParent(this.editor.selection.getNode(), 'UL');
8946         },
8947
8948         queryStateInsertOrderedList : function() {
8949             return this.editor.dom.getParent(this.editor.selection.getNode(), 'OL');
8950         },
8951
8952         queryStatemceBlockQuote : function() {
8953             return !!this.editor.dom.getParent(this.editor.selection.getStart(), function(n) {return n.nodeName === 'BLOCKQUOTE';});
8954         },
8955
8956         mceBlockQuote : function() {
8957             var t = this, ed = t.editor, s = ed.selection, dom = ed.dom, sb, eb, n, bm, bq, r, bq2, i, nl;
8958
8959             function getBQ(e) {
8960                 return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';});
8961             };
8962
8963             // Get start/end block
8964             sb = dom.getParent(s.getStart(), dom.isBlock);
8965             eb = dom.getParent(s.getEnd(), dom.isBlock);
8966
8967             // Remove blockquote(s)
8968             if (bq = getBQ(sb)) {
8969                 if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))
8970                     bm = s.getBookmark();
8971
8972                 // Move all elements after the end block into new bq
8973                 if (getBQ(eb)) {
8974                     bq2 = bq.cloneNode(false);
8975
8976                     while (n = eb.nextSibling)
8977                         bq2.appendChild(n.parentNode.removeChild(n));
8978                 }
8979
8980                 // Add new bq after
8981                 if (bq2)
8982                     dom.insertAfter(bq2, bq);
8983
8984                 // Move all selected blocks after the current bq
8985                 nl = t._getSelectedBlocks(sb, eb);
8986                 for (i = nl.length - 1; i >= 0; i--) {
8987                     dom.insertAfter(nl[i], bq);
8988                 }
8989
8990                 // Empty bq, then remove it
8991                 if (/^\s*$/.test(bq.innerHTML))
8992                     dom.remove(bq, 1); // Keep children so boomark restoration works correctly
8993
8994                 // Empty bq, then remote it
8995                 if (bq2 && /^\s*$/.test(bq2.innerHTML))
8996                     dom.remove(bq2, 1); // Keep children so boomark restoration works correctly
8997
8998                 if (!bm) {
8999                     // Move caret inside empty block element
9000                     if (!isIE) {
9001                         r = ed.getDoc().createRange();
9002                         r.setStart(sb, 0);
9003                         r.setEnd(sb, 0);
9004                         s.setRng(r);
9005                     } else {
9006                         s.select(sb);
9007                         s.collapse(0);
9008
9009                         // IE misses the empty block some times element so we must move back the caret
9010                         if (dom.getParent(s.getStart(), dom.isBlock) != sb) {
9011                             r = s.getRng();
9012                             r.move('character', -1);
9013                             r.select();
9014                         }
9015                     }
9016                 } else
9017                     t.editor.selection.moveToBookmark(bm);
9018
9019                 return;
9020             }
9021
9022             // Since IE can start with a totally empty document we need to add the first bq and paragraph
9023             if (isIE && !sb && !eb) {
9024                 t.editor.getDoc().execCommand('Indent');
9025                 n = getBQ(s.getNode());
9026                 n.style.margin = n.dir = ''; // IE adds margin and dir to bq
9027                 return;
9028             }
9029
9030             if (!sb || !eb)
9031                 return;
9032
9033             // If empty paragraph node then do not use bookmark
9034             if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))
9035                 bm = s.getBookmark();
9036
9037             // Move selected block elements into a bq
9038             each(t._getSelectedBlocks(getBQ(s.getStart()), getBQ(s.getEnd())), function(e) {
9039                 // Found existing BQ add to this one
9040                 if (e.nodeName == 'BLOCKQUOTE' && !bq) {
9041                     bq = e;
9042                     return;
9043                 }
9044
9045                 // No BQ found, create one
9046                 if (!bq) {
9047                     bq = dom.create('blockquote');
9048                     e.parentNode.insertBefore(bq, e);
9049                 }
9050
9051                 // Add children from existing BQ
9052                 if (e.nodeName == 'BLOCKQUOTE' && bq) {
9053                     n = e.firstChild;
9054
9055                     while (n) {
9056                         bq.appendChild(n.cloneNode(true));
9057                         n = n.nextSibling;
9058                     }
9059
9060                     dom.remove(e);
9061                     return;
9062                 }
9063
9064                 // Add non BQ element to BQ
9065                 bq.appendChild(dom.remove(e));
9066             });
9067
9068             if (!bm) {
9069                 // Move caret inside empty block element
9070                 if (!isIE) {
9071                     r = ed.getDoc().createRange();
9072                     r.setStart(sb, 0);
9073                     r.setEnd(sb, 0);
9074                     s.setRng(r);
9075                 } else {
9076                     s.select(sb);
9077                     s.collapse(1);
9078                 }
9079             } else
9080                 s.moveToBookmark(bm);
9081         },
9082 /*
9083         _mceBlockQuote : function() {
9084             var t = this, s = t.editor.selection, b = s.getBookmark(), bq, dom = t.editor.dom;
9085
9086             function findBQ(e) {
9087                 return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';});
9088             };
9089
9090             // Remove blockquote(s)
9091             if (findBQ(s.getStart())) {
9092                 each(t._getSelectedBlocks(findBQ(s.getStart()), findBQ(s.getEnd())), function(e) {
9093                     // Found BQ lets remove it
9094                     if (e.nodeName == 'BLOCKQUOTE')
9095                         dom.remove(e, 1);
9096                 });
9097
9098                 t.editor.selection.moveToBookmark(b);
9099                 return;
9100             }
9101
9102             each(t._getSelectedBlocks(findBQ(s.getStart()), findBQ(s.getEnd())), function(e) {
9103                 var n;
9104
9105                 // Found existing BQ add to this one
9106                 if (e.nodeName == 'BLOCKQUOTE' && !bq) {
9107                     bq = e;
9108                     return;
9109                 }
9110
9111                 // No BQ found, create one
9112                 if (!bq) {
9113                     bq = dom.create('blockquote');
9114                     e.parentNode.insertBefore(bq, e);
9115                 }
9116
9117                 // Add children from existing BQ
9118                 if (e.nodeName == 'BLOCKQUOTE' && bq) {
9119                     n = e.firstChild;
9120
9121                     while (n) {
9122                         bq.appendChild(n.cloneNode(true));
9123                         n = n.nextSibling;
9124                     }
9125
9126                     dom.remove(e);
9127
9128                     return;
9129                 }
9130
9131                 // Add non BQ element to BQ
9132                 bq.appendChild(dom.remove(e));
9133             });
9134
9135             t.editor.selection.moveToBookmark(b);
9136         },
9137 */
9138         _getSelectedBlocks : function(st, en) {
9139             var ed = this.editor, dom = ed.dom, s = ed.selection, sb, eb, n, bl = [];
9140
9141             sb = dom.getParent(st || s.getStart(), dom.isBlock);
9142             eb = dom.getParent(en || s.getEnd(), dom.isBlock);
9143
9144             if (sb)
9145                 bl.push(sb);
9146
9147             if (sb && eb && sb != eb) {
9148                 n = sb;
9149
9150                 while ((n = n.nextSibling) && n != eb) {
9151                     if (dom.isBlock(n))
9152                         bl.push(n);
9153                 }
9154             }
9155
9156             if (eb && sb != eb)
9157                 bl.push(eb);
9158
9159             return bl;
9160         }
9161     });
9162 })();
9163
9164
9165 /* file:jscripts/tiny_mce/classes/UndoManager.js */
9166
9167 tinymce.create('tinymce.UndoManager', {
9168     index : 0,
9169     data : null,
9170     typing : 0,
9171
9172     UndoManager : function(ed) {
9173         var t = this, Dispatcher = tinymce.util.Dispatcher;
9174
9175         t.editor = ed;
9176         t.data = [];
9177         t.onAdd = new Dispatcher(this);
9178         t.onUndo = new Dispatcher(this);
9179         t.onRedo = new Dispatcher(this);
9180     },
9181
9182     add : function(l) {
9183         var t = this, i, ed = t.editor, b, s = ed.settings, la;
9184
9185         l = l || {};
9186         l.content = l.content || ed.getContent({format : 'raw', no_events : 1});
9187
9188         // Add undo level if needed
9189         l.content = l.content.replace(/^\s*|\s*$/g, '');
9190         la = t.data[t.index > 0 ? t.index - 1 : 0];
9191         if (!l.initial && la && l.content == la.content)
9192             return null;
9193
9194         // Time to compress
9195         if (s.custom_undo_redo_levels) {
9196             if (t.data.length > s.custom_undo_redo_levels) {
9197                 for (i = 0; i < t.data.length - 1; i++)
9198                     t.data[i] = t.data[i + 1];
9199
9200                 t.data.length--;
9201                 t.index = t.data.length;
9202             }
9203         }
9204
9205         if (s.custom_undo_redo_restore_selection && !l.initial)
9206             l.bookmark = b = l.bookmark || ed.selection.getBookmark();
9207
9208         if (t.index < t.data.length && t.data[t.index].initial)
9209             t.index++;
9210
9211         // Add level
9212         t.data.length = t.index + 1;
9213         t.data[t.index++] = l;
9214
9215         if (l.initial)
9216             t.index = 0;
9217
9218         // Set initial bookmark use first real undo level
9219         if (t.data.length == 2 && t.data[0].initial)
9220             t.data[0].bookmark = b;
9221
9222         t.onAdd.dispatch(t, l);
9223         ed.isNotDirty = 0;
9224
9225         //console.dir(t.data);
9226
9227         return l;
9228     },
9229
9230     undo : function() {
9231         var t = this, ed = t.editor, l = l, i;
9232
9233         if (t.typing) {
9234             t.add();
9235             t.typing = 0;
9236         }
9237
9238         if (t.index > 0) {
9239             // If undo on last index then take snapshot
9240             if (t.index == t.data.length && t.index > 1) {
9241                 i = t.index;
9242                 t.typing = 0;
9243
9244                 if (!t.add())
9245                     t.index = i;
9246
9247                 --t.index;
9248             }
9249
9250             l = t.data[--t.index];
9251             ed.setContent(l.content, {format : 'raw'});
9252             ed.selection.moveToBookmark(l.bookmark);
9253
9254             t.onUndo.dispatch(t, l);
9255         }
9256
9257         return l;
9258     },
9259
9260     redo : function() {
9261         var t = this, ed = t.editor, l = null;
9262
9263         if (t.index < t.data.length - 1) {
9264             l = t.data[++t.index];
9265             ed.setContent(l.content, {format : 'raw'});
9266             ed.selection.moveToBookmark(l.bookmark);
9267
9268             t.onRedo.dispatch(t, l);
9269         }
9270
9271         return l;
9272     },
9273
9274     clear : function() {
9275         var t = this;
9276
9277         t.data = [];
9278         t.index = 0;
9279         t.typing = 0;
9280         t.add({initial : true});
9281     },
9282
9283     hasUndo : function() {
9284         return this.index != 0 || this.typing;
9285     },
9286
9287     hasRedo : function() {
9288         return this.index < this.data.length - 1;
9289     }
9290
9291     });
9292 /* file:jscripts/tiny_mce/classes/ForceBlocks.js */
9293
9294 (function() {
9295     // Shorten names
9296     var Event, isIE, isGecko, isOpera, each, extend;
9297
9298     Event = tinymce.dom.Event;
9299     isIE = tinymce.isIE;
9300     isGecko = tinymce.isGecko;
9301     isOpera = tinymce.isOpera;
9302     each = tinymce.each;
9303     extend = tinymce.extend;
9304
9305     tinymce.create('tinymce.ForceBlocks', {
9306         ForceBlocks : function(ed) {
9307             var t = this, s = ed.settings, elm;
9308
9309             t.editor = ed;
9310             t.dom = ed.dom;
9311             elm = (s.forced_root_block || 'p').toLowerCase();
9312             s.element = elm.toUpperCase();
9313
9314             ed.onPreInit.add(t.setup, t);
9315
9316             t.reOpera = new RegExp('(\\u00a0|&#160;|&nbsp;)<\/' + elm + '>', 'gi');
9317             t.rePadd = new RegExp('<p( )([^>]+)><\\\/p>|<p( )([^>]+)\\\/>|<p( )([^>]+)>\\s+<\\\/p>|<p><\\\/p>|<p\\\/>|<p>\\s+<\\\/p>'.replace(/p/g, elm), 'gi');
9318             t.reNbsp2BR1 = new RegExp('<p( )([^>]+)>[\\s\\u00a0]+<\\\/p>|<p>[\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi');
9319             t.reNbsp2BR2 = new RegExp('<p( )([^>]+)>(&nbsp;|&#160;)<\\\/p>|<p>(&nbsp;|&#160;)<\\\/p>'.replace(/p/g, elm), 'gi');
9320             t.reBR2Nbsp = new RegExp('<p( )([^>]+)>\\s*<br \\\/>\\s*<\\\/p>|<p>\\s*<br \\\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');
9321             t.reTrailBr = new RegExp('\\s*<br \\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');
9322
9323             function padd(ed, o) {
9324                 if (isOpera)
9325                     o.content = o.content.replace(t.reOpera, '</' + elm + '>');
9326
9327                 o.content = o.content.replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0</' + elm + '>');
9328
9329                 if (!isIE && !isOpera && o.set) {
9330                     // Use &nbsp; instead of BR in padded paragraphs
9331                     o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2><br /></' + elm + '>');
9332                     o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2><br /></' + elm + '>');
9333                 } else {
9334                     o.content = o.content.replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0</' + elm + '>');
9335                     o.content = o.content.replace(t.reTrailBr, '</' + elm + '>');
9336                 }
9337             };
9338
9339             ed.onBeforeSetContent.add(padd);
9340             ed.onPostProcess.add(padd);
9341
9342             if (s.forced_root_block) {
9343                 ed.onInit.add(t.forceRoots, t);
9344                 ed.onSetContent.add(t.forceRoots, t);
9345                 ed.onBeforeGetContent.add(t.forceRoots, t);
9346             }
9347         },
9348
9349         setup : function() {
9350             var t = this, ed = t.editor, s = ed.settings;
9351
9352             // Force root blocks when typing and when getting output
9353             if (s.forced_root_block) {
9354                 ed.onKeyUp.add(t.forceRoots, t);
9355                 ed.onPreProcess.add(t.forceRoots, t);
9356             }
9357
9358             if (s.force_br_newlines) {
9359                 // Force IE to produce BRs on enter
9360                 if (isIE) {
9361                     ed.onKeyPress.add(function(ed, e) {
9362                         var n, s = ed.selection;
9363
9364                         if (e.keyCode == 13 && s.getNode().nodeName != 'LI') {
9365                             s.setContent('<br id="__" /> ', {format : 'raw'});
9366                             n = ed.dom.get('__');
9367                             n.removeAttribute('id');
9368                             s.select(n);
9369                             s.collapse();
9370                             return Event.cancel(e);
9371                         }
9372                     });
9373                 }
9374
9375                 return;
9376             }
9377
9378             if (!isIE && s.force_p_newlines) {
9379 /*                ed.onPreProcess.add(function(ed, o) {
9380                     each(ed.dom.select('br', o.node), function(n) {
9381                         var p = n.parentNode;
9382
9383                         // Replace <p><br /></p> with <p>&nbsp;</p>
9384                         if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) {
9385                             p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n);
9386                         }
9387                     });
9388                 });*/
9389
9390                 ed.onKeyPress.add(function(ed, e) {
9391                     if (e.keyCode == 13 && !e.shiftKey) {
9392                         if (!t.insertPara(e))
9393                             Event.cancel(e);
9394                     }
9395                 });
9396
9397                 if (isGecko) {
9398                     ed.onKeyDown.add(function(ed, e) {
9399                         if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
9400                             t.backspaceDelete(e, e.keyCode == 8);
9401                     });
9402                 }
9403             }
9404
9405             function ren(rn, na) {
9406                 var ne = ed.dom.create(na);
9407
9408                 each(rn.attributes, function(a) {
9409                     if (a.specified && a.nodeValue)
9410                         ne.setAttribute(a.nodeName.toLowerCase(), a.nodeValue);
9411                 });
9412
9413                 each(rn.childNodes, function(n) {
9414                     ne.appendChild(n.cloneNode(true));
9415                 });
9416
9417                 rn.parentNode.replaceChild(ne, rn);
9418
9419                 return ne;
9420             };
9421
9422             // Replaces IE:s auto generated paragraphs with the specified element name
9423             if (isIE && s.element != 'P') {
9424                 ed.onKeyPress.add(function(ed, e) {
9425                     t.lastElm = ed.selection.getNode().nodeName;
9426                 });
9427
9428                 ed.onKeyUp.add(function(ed, e) {
9429                     var bl, sel = ed.selection, n = sel.getNode(), b = ed.getBody();
9430
9431                     if (b.childNodes.length === 1 && n.nodeName == 'P') {
9432                         n = ren(n, s.element);
9433                         sel.select(n);
9434                         sel.collapse();
9435                         ed.nodeChanged();
9436                     } else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') {
9437                         bl = ed.dom.getParent(n, 'P');
9438
9439                         if (bl) {
9440                             ren(bl, s.element);
9441                             ed.nodeChanged();
9442                         }
9443                     }
9444                 });
9445             }
9446         },
9447
9448         find : function(n, t, s) {
9449             var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, false), c = -1;
9450
9451             while (n = w.nextNode()) {
9452                 c++;
9453
9454                 // Index by node
9455                 if (t == 0 && n == s)
9456                     return c;
9457
9458                 // Node by index
9459                 if (t == 1 && c == s)
9460                     return n;
9461             }
9462
9463             return -1;
9464         },
9465
9466         forceRoots : function(ed, e) {
9467             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;
9468             var nx, bl, bp, sp, le, nl = b.childNodes, i;
9469
9470             // Fix for bug #1863847
9471             if (e && e.keyCode == 13)
9472                 return true;
9473
9474             // Wrap non blocks into blocks
9475             for (i = nl.length - 1; i >= 0; i--) {
9476                 nx = nl[i];
9477
9478                 // Is text or non block element
9479                 if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) {
9480                     if (!bl) {
9481                         // Create new block but ignore whitespace
9482                         if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {
9483                             // Store selection
9484                             if (si == -2 && r) {
9485                                 if (!isIE) {
9486                                     so = r.startOffset;
9487                                     eo = r.endOffset;
9488                                     si = t.find(b, 0, r.startContainer);
9489                                     ei = t.find(b, 0, r.endContainer);
9490                                 } else {
9491                                     tr = d.body.createTextRange();
9492                                     tr.moveToElementText(b);
9493                                     tr.collapse(1);
9494                                     bp = tr.move('character', c) * -1;
9495
9496                                     tr = r.duplicate();
9497                                     tr.collapse(1);
9498                                     sp = tr.move('character', c) * -1;
9499
9500                                     tr = r.duplicate();
9501                                     tr.collapse(0);
9502                                     le = (tr.move('character', c) * -1) - sp;
9503
9504                                     si = sp - bp;
9505                                     ei = le;
9506                                 }
9507                             }
9508
9509                             bl = ed.dom.create(ed.settings.forced_root_block);
9510                             bl.appendChild(nx.cloneNode(1));
9511                             nx.parentNode.replaceChild(bl, nx);
9512                         }
9513                     } else {
9514                         if (bl.hasChildNodes())
9515                             bl.insertBefore(nx, bl.firstChild);
9516                         else
9517                             bl.appendChild(nx);
9518                     }
9519                 } else
9520                     bl = null; // Time to create new block
9521             }
9522
9523             // Restore selection
9524             if (si != -2) {
9525                 if (!isIE) {
9526                     bl = d.getElementsByTagName(ed.settings.element)[0];
9527                     r = d.createRange();
9528
9529                     // Select last location or generated block
9530                     if (si != -1)
9531                         r.setStart(t.find(b, 1, si), so);
9532                     else
9533                         r.setStart(bl, 0);
9534
9535                     // Select last location or generated block
9536                     if (ei != -1)
9537                         r.setEnd(t.find(b, 1, ei), eo);
9538                     else
9539                         r.setEnd(bl, 0);
9540
9541                     if (s) {
9542                         s.removeAllRanges();
9543                         s.addRange(r);
9544                     }
9545                 } else {
9546                     try {
9547                         r = s.createRange();
9548                         r.moveToElementText(b);
9549                         r.collapse(1);
9550                         r.moveStart('character', si);
9551                         r.moveEnd('character', ei);
9552                         r.select();
9553                     } catch (ex) {
9554                         // Ignore
9555                     }
9556                 }
9557             }
9558         },
9559
9560         getParentBlock : function(n) {
9561             var d = this.dom;
9562
9563             return d.getParent(n, d.isBlock);
9564         },
9565
9566         insertPara : function(e) {
9567             var t = this, ed = t.editor, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body;
9568             var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = ed.dom.getViewPort(ed.getWin()), y, ch;
9569
9570             function isEmpty(n) {
9571                 n = n.innerHTML;
9572                 n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars
9573                 n = n.replace(/<[^>]+>/g, ''); // Remove all tags
9574
9575                 return n.replace(/[ \t\r\n]+/g, '') == '';
9576             };
9577
9578             // If root blocks are forced then use Operas default behavior since it's really good
9579 // Removed due to bug: #1853816
9580 //            if (se.forced_root_block && isOpera)
9581 //                return true;
9582
9583             // Setup before range
9584             rb = d.createRange();
9585
9586             // If is before the first block element and in body, then move it into first block element
9587             rb.setStart(s.anchorNode, s.anchorOffset);
9588             rb.collapse(true);
9589
9590             // Setup after range
9591             ra = d.createRange();
9592
9593             // If is before the first block element and in body, then move it into first block element
9594             ra.setStart(s.focusNode, s.focusOffset);
9595             ra.collapse(true);
9596
9597             // Setup start/end points
9598             dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;
9599             sn = dir ? s.anchorNode : s.focusNode;
9600             so = dir ? s.anchorOffset : s.focusOffset;
9601             en = dir ? s.focusNode : s.anchorNode;
9602             eo = dir ? s.focusOffset : s.anchorOffset;
9603
9604             // If the caret is in an invalid location in FF we need to move it into the first block
9605             if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) {
9606                 sn = en = sn.firstChild;
9607                 so = eo = 0;
9608                 rb = d.createRange();
9609                 rb.setStart(sn, 0);
9610                 ra = d.createRange();
9611                 ra.setStart(en, 0);
9612             }
9613
9614             // Never use body as start or end node
9615             sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
9616             sn = sn.nodeName == "BODY" ? sn.firstChild : sn;
9617             en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
9618             en = en.nodeName == "BODY" ? en.firstChild : en;
9619
9620             // Get start and end blocks
9621             sb = t.getParentBlock(sn);
9622             eb = t.getParentBlock(en);
9623             bn = sb ? sb.nodeName : se.element; // Get block name to create
9624
9625             // Return inside list use default browser behavior
9626             if (t.dom.getParent(sb, function(n) { return /OL|UL|PRE/.test(n.nodeName); }))
9627                 return true;
9628
9629             // If caption or absolute layers then always generate new blocks within
9630             if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(sb.style.position))) {
9631                 bn = se.element;
9632                 sb = null;
9633             }
9634
9635             // If caption or absolute layers then always generate new blocks within
9636             if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(eb.style.position))) {
9637                 bn = se.element;
9638                 eb = null;
9639             }
9640
9641             // Use P instead
9642             if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(sb.style.cssFloat))) {
9643                 bn = se.element;
9644                 sb = eb = null;
9645             }
9646
9647             // Setup new before and after blocks
9648             bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn);
9649             aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn);
9650
9651             // Remove id from after clone
9652             aft.removeAttribute('id');
9653
9654             // Is header and cursor is at the end, then force paragraph under
9655             if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length)
9656                 aft = ed.dom.create(se.element);
9657
9658             // Find start chop node
9659             n = sc = sn;
9660             do {
9661                 if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
9662                     break;
9663
9664                 sc = n;
9665             } while ((n = n.previousSibling ? n.previousSibling : n.parentNode));
9666
9667             // Find end chop node
9668             n = ec = en;
9669             do {
9670                 if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
9671                     break;
9672
9673                 ec = n;
9674             } while ((n = n.nextSibling ? n.nextSibling : n.parentNode));
9675
9676             // Place first chop part into before block element
9677             if (sc.nodeName == bn)
9678                 rb.setStart(sc, 0);
9679             else
9680                 rb.setStartBefore(sc);
9681
9682             rb.setEnd(sn, so);
9683             bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
9684
9685             // Place secnd chop part within new block element
9686             try {
9687                 ra.setEndAfter(ec);
9688             } catch(ex) {
9689                 //console.debug(s.focusNode, s.focusOffset);
9690             }
9691
9692             ra.setStart(en, eo);
9693             aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
9694
9695             // Create range around everything
9696             r = d.createRange();
9697             if (!sc.previousSibling && sc.parentNode.nodeName == bn) {
9698                 r.setStartBefore(sc.parentNode);
9699             } else {
9700                 if (rb.startContainer.nodeName == bn && rb.startOffset == 0)
9701                     r.setStartBefore(rb.startContainer);
9702                 else
9703                     r.setStart(rb.startContainer, rb.startOffset);
9704             }
9705
9706             if (!ec.nextSibling && ec.parentNode.nodeName == bn)
9707                 r.setEndAfter(ec.parentNode);
9708             else
9709                 r.setEnd(ra.endContainer, ra.endOffset);
9710
9711             // Delete and replace it with new block elements
9712             r.deleteContents();
9713
9714             if (isOpera)
9715                 ed.getWin().scrollTo(0, vp.y);
9716
9717             // Never wrap blocks in blocks
9718             if (bef.firstChild && bef.firstChild.nodeName == bn)
9719                 bef.innerHTML = bef.firstChild.innerHTML;
9720
9721             if (aft.firstChild && aft.firstChild.nodeName == bn)
9722                 aft.innerHTML = aft.firstChild.innerHTML;
9723
9724             // Padd empty blocks
9725             if (isEmpty(bef))
9726                 bef.innerHTML = '<br />';
9727
9728             if (isEmpty(aft))
9729                 aft.innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there
9730
9731             // Opera needs this one backwards
9732             if (isOpera) {
9733                 r.insertNode(bef);
9734                 r.insertNode(aft);
9735             } else {
9736                 r.insertNode(aft);
9737                 r.insertNode(bef);
9738             }
9739
9740             // Normalize
9741             aft.normalize();
9742             bef.normalize();
9743
9744             // Move cursor and scroll into view
9745             r = d.createRange();
9746             r.selectNodeContents(aft);
9747             r.collapse(1);
9748             s.removeAllRanges();
9749             s.addRange(r);
9750
9751             // 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
9752             y = ed.dom.getPos(aft).y;
9753             ch = aft.clientHeight;
9754
9755             // Is element within viewport
9756             if (y < vp.y || y + ch > vp.y + vp.h) {
9757                 ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + ch);
9758                 //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));
9759             }
9760
9761             return false;
9762         },
9763
9764         backspaceDelete : function(e, bs) {
9765             var t = this, ed = t.editor, b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn;
9766
9767             // The caret sometimes gets stuck in Gecko if you delete empty paragraphs
9768             // This workaround removes the element by hand and moves the caret to the previous element
9769             if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
9770                 if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
9771                     // Find previous block element
9772                     n = sc;
9773                     while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ;
9774
9775                     if (n) {
9776                         if (sc != b.firstChild) {
9777                             // Find last text node
9778                             w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
9779                             while (tn = w.nextNode())
9780                                 n = tn;
9781
9782                             // Place caret at the end of last text node
9783                             r = ed.getDoc().createRange();
9784                             r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);
9785                             r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);
9786                             se.setRng(r);
9787
9788                             // Remove the target container
9789                             ed.dom.remove(sc);
9790                         }
9791
9792                         return Event.cancel(e);
9793                     }
9794                 }
9795             }
9796
9797             // Gecko generates BR elements here and there, we don't like those so lets remove them
9798             function handler(e) {
9799                 e = e.target;
9800
9801                 // A new BR was created in a block element, remove it
9802                 if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {
9803                     Event.remove(b, 'DOMNodeInserted', handler);
9804
9805                     // Only remove BR elements that got inserted in the middle of the text
9806                     if (e.previousSibling || e.nextSibling)
9807                         ed.dom.remove(e);
9808                 }
9809             };
9810
9811             // Listen for new nodes
9812             Event._add(b, 'DOMNodeInserted', handler);
9813
9814             // Remove listener
9815             window.setTimeout(function() {
9816                 Event._remove(b, 'DOMNodeInserted', handler);
9817             }, 1);
9818         }
9819     });
9820 })();
9821
9822 /* file:jscripts/tiny_mce/classes/ControlManager.js */
9823
9824 (function() {
9825     // Shorten names
9826     var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;
9827
9828     tinymce.create('tinymce.ControlManager', {
9829         ControlManager : function(ed, s) {
9830             var t = this, i;
9831
9832             s = s || {};
9833             t.editor = ed;
9834             t.controls = {};
9835             t.onAdd = new tinymce.util.Dispatcher(t);
9836             t.onPostRender = new tinymce.util.Dispatcher(t);
9837             t.prefix = s.prefix || ed.id + '_';
9838             t._cls = {};
9839
9840             t.onPostRender.add(function() {
9841                 each(t.controls, function(c) {
9842                     c.postRender();
9843                 });
9844             });
9845         },
9846
9847         get : function(id) {
9848             return this.controls[this.prefix + id] || this.controls[id];
9849         },
9850
9851         setActive : function(id, s) {
9852             var c = null;
9853
9854             if (c = this.get(id))
9855                 c.setActive(s);
9856
9857             return c;
9858         },
9859
9860         setDisabled : function(id, s) {
9861             var c = null;
9862
9863             if (c = this.get(id))
9864                 c.setDisabled(s);
9865
9866             return c;
9867         },
9868
9869         add : function(c) {
9870             var t = this;
9871
9872             if (c) {
9873                 t.controls[c.id] = c;
9874                 t.onAdd.dispatch(c, t);
9875             }
9876
9877             return c;
9878         },
9879
9880         createControl : function(n) {
9881             var c, t = this, ed = t.editor;
9882
9883             each(ed.plugins, function(p) {
9884                 if (p.createControl) {
9885                     c = p.createControl(n, t);
9886
9887                     if (c)
9888                         return false;
9889                 }
9890             });
9891
9892             switch (n) {
9893                 case "|":
9894                 case "separator":
9895                     return t.createSeparator();
9896             }
9897
9898             if (!c && ed.buttons && (c = ed.buttons[n]))
9899                 return t.createButton(n, c);
9900
9901             return t.add(c);
9902         },
9903
9904         createDropMenu : function(id, s, cc) {
9905             var t = this, ed = t.editor, c, bm, v, cls;
9906
9907             s = extend({
9908                 'class' : 'mceDropDown',
9909                 constrain : ed.settings.constrain_menus
9910             }, s);
9911
9912             s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';
9913             if (v = ed.getParam('skin_variant'))
9914                 s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
9915
9916             id = t.prefix + id;
9917             cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
9918             c = t.controls[id] = new cls(id, s);
9919             c.onAddItem.add(function(c, o) {
9920                 var s = o.settings;
9921
9922                 s.title = ed.getLang(s.title, s.title);
9923
9924                 if (!s.onclick) {
9925                     s.onclick = function(v) {
9926                         ed.execCommand(s.cmd, s.ui || false, s.value);
9927                     };
9928                 }
9929             });
9930
9931             ed.onRemove.add(function() {
9932                 c.destroy();
9933             });
9934
9935             // Fix for bug #1897785, #1898007
9936             if (tinymce.isIE) {
9937                 c.onShowMenu.add(function() {
9938                     var s = ed.selection, n = s.getNode();
9939
9940                     if (n.nodeName == 'IMG')
9941                         bm = s.getBookmark();
9942                     else
9943                         bm = 0;
9944                 });
9945
9946                 c.onHideMenu.add(function() {
9947                     if (bm)
9948                         ed.selection.moveToBookmark(bm);
9949                 });
9950             }
9951
9952             return t.add(c);
9953         },
9954
9955         createListBox : function(id, s, cc) {
9956             var t = this, ed = t.editor, cmd, c, cls;
9957
9958             if (t.get(id))
9959                 return null;
9960
9961             s.title = ed.translate(s.title);
9962             s.scope = s.scope || ed;
9963
9964             if (!s.onselect) {
9965                 s.onselect = function(v) {
9966                     ed.execCommand(s.cmd, s.ui || false, v || s.value);
9967                 };
9968             }
9969
9970             s = extend({
9971                 title : s.title,
9972                 'class' : 'mce_' + id,
9973                 scope : s.scope,
9974                 control_manager : t
9975             }, s);
9976
9977             id = t.prefix + id;
9978
9979             if (ed.settings.use_native_selects)
9980                 c = new tinymce.ui.NativeListBox(id, s);
9981             else {
9982                 cls = cc || t._cls.listbox || tinymce.ui.ListBox;
9983                 c = new cls(id, s);
9984             }
9985
9986             t.controls[id] = c;
9987
9988             // Fix focus problem in Safari
9989             if (tinymce.isWebKit) {
9990                 c.onPostRender.add(function(c, n) {
9991                     // Store bookmark on mousedown
9992                     Event.add(n, 'mousedown', function() {
9993                         ed.bookmark = ed.selection.getBookmark('simple');
9994                     });
9995
9996                     // Restore on focus, since it might be lost
9997                     Event.add(n, 'focus', function() {
9998                         ed.selection.moveToBookmark(ed.bookmark);
9999                         ed.bookmark = null;
10000                     });
10001                 });
10002             }
10003
10004             if (c.hideMenu)
10005                 ed.onMouseDown.add(c.hideMenu, c);
10006
10007             return t.add(c);
10008         },
10009
10010         createButton : function(id, s, cc) {
10011             var t = this, ed = t.editor, o, c, cls;
10012
10013             if (t.get(id))
10014                 return null;
10015
10016             s.title = ed.translate(s.title);
10017             s.scope = s.scope || ed;
10018
10019             if (!s.onclick && !s.menu_button) {
10020                 s.onclick = function() {
10021                     ed.execCommand(s.cmd, s.ui || false, s.value);
10022                 };
10023             }
10024
10025             s = extend({
10026                 title : s.title,
10027                 'class' : 'mce_' + id,
10028                 unavailable_prefix : ed.getLang('unavailable', ''),
10029                 scope : s.scope,
10030                 control_manager : t
10031             }, s);
10032
10033             id = t.prefix + id;
10034
10035             if (s.menu_button) {
10036                 cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;
10037                 c = new cls(id, s);
10038                 ed.onMouseDown.add(c.hideMenu, c);
10039             } else {
10040                 cls = t._cls.button || tinymce.ui.Button;
10041                 c = new cls(id, s);
10042             }
10043
10044             return t.add(c);
10045         },
10046
10047         createMenuButton : function(id, s) {
10048             s = s || {};
10049             s.menu_button = 1;
10050
10051             return this.createButton(id, s);
10052         },
10053
10054         createSplitButton : function(id, s, cc) {
10055             var t = this, ed = t.editor, cmd, c, cls;
10056
10057             if (t.get(id))
10058                 return null;
10059
10060             s.title = ed.translate(s.title);
10061             s.scope = s.scope || ed;
10062
10063             if (!s.onclick) {
10064                 s.onclick = function(v) {
10065                     ed.execCommand(s.cmd, s.ui || false, v || s.value);
10066                 };
10067             }
10068
10069             if (!s.onselect) {
10070                 s.onselect = function(v) {
10071                     ed.execCommand(s.cmd, s.ui || false, v || s.value);
10072                 };
10073             }
10074
10075             s = extend({
10076                 title : s.title,
10077                 'class' : 'mce_' + id,
10078                 scope : s.scope,
10079                 control_manager : t
10080             }, s);
10081
10082             id = t.prefix + id;
10083             cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;
10084             c = t.add(new cls(id, s));
10085             ed.onMouseDown.add(c.hideMenu, c);
10086
10087             return c;
10088         },
10089
10090         createColorSplitButton : function(id, s, cc) {
10091             var t = this, ed = t.editor, cmd, c, cls;
10092
10093             if (t.get(id))
10094                 return null;
10095
10096             s.title = ed.translate(s.title);
10097             s.scope = s.scope || ed;
10098
10099             if (!s.onclick) {
10100                 s.onclick = function(v) {
10101                     ed.execCommand(s.cmd, s.ui || false, v || s.value);
10102                 };
10103             }
10104
10105             if (!s.onselect) {
10106                 s.onselect = function(v) {
10107                     ed.execCommand(s.cmd, s.ui || false, v || s.value);
10108                 };
10109             }
10110
10111             s = extend({
10112                 title : s.title,
10113                 'class' : 'mce_' + id,
10114                 'menu_class' : ed.getParam('skin') + 'Skin',
10115                 scope : s.scope,
10116                 more_colors_title : ed.getLang('more_colors')
10117             }, s);
10118
10119             id = t.prefix + id;
10120             cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;
10121             c = new cls(id, s);
10122             ed.onMouseDown.add(c.hideMenu, c);
10123
10124             // Remove the menu element when the editor is removed
10125             ed.onRemove.add(function() {
10126                 c.destroy();
10127             });
10128
10129             return t.add(c);
10130         },
10131
10132         createToolbar : function(id, s, cc) {
10133             var c, t = this, cls;
10134
10135             id = t.prefix + id;
10136             cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;
10137             c = new cls(id, s);
10138
10139             if (t.get(id))
10140                 return null;
10141
10142             return t.add(c);
10143         },
10144
10145         createSeparator : function(cc) {
10146             var cls = cc || this._cls.separator || tinymce.ui.Separator;
10147
10148             return new cls();
10149         },
10150
10151         setControlType : function(n, c) {
10152             return this._cls[n.toLowerCase()] = c;
10153         },
10154
10155         destroy : function() {
10156             each(this.controls, function(c) {
10157                 c.destroy();
10158             });
10159
10160             this.controls = null;
10161         }
10162
10163         });
10164 })();
10165
10166 /* file:jscripts/tiny_mce/classes/WindowManager.js */
10167
10168 (function() {
10169     var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;
10170
10171     tinymce.create('tinymce.WindowManager', {
10172         WindowManager : function(ed) {
10173             var t = this;
10174
10175             t.editor = ed;
10176             t.onOpen = new Dispatcher(t);
10177             t.onClose = new Dispatcher(t);
10178             t.params = {};
10179             t.features = {};
10180         },
10181
10182         open : function(s, p) {
10183             var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;
10184
10185             // Default some options
10186             s = s || {};
10187             p = p || {};
10188             sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window
10189             sh = isOpera ? vp.h : screen.height;
10190             s.name = s.name || 'mc_' + new Date().getTime();
10191             s.width = parseInt(s.width || 320);
10192             s.height = parseInt(s.height || 240);
10193             s.resizable = true;
10194             s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);
10195             s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);
10196             p.inline = false;
10197             p.mce_width = s.width;
10198             p.mce_height = s.height;
10199             p.mce_auto_focus = s.auto_focus;
10200
10201             if (mo) {
10202                 if (isIE) {
10203                     s.center = true;
10204                     s.help = false;
10205                     s.dialogWidth = s.width + 'px';
10206                     s.dialogHeight = s.height + 'px';
10207                     s.scroll = s.scrollbars || false;
10208                 } else
10209                     s.modal = s.alwaysRaised = s.dialog = s.centerscreen = s.dependent = true;
10210             }
10211
10212             // Build features string
10213             each(s, function(v, k) {
10214                 if (tinymce.is(v, 'boolean'))
10215                     v = v ? 'yes' : 'no';
10216
10217                 if (!/^(name|url)$/.test(k)) {
10218                     if (isIE && mo)
10219                         f += (f ? ';' : '') + k + ':' + v;
10220                     else
10221                         f += (f ? ',' : '') + k + '=' + v;
10222                 }
10223             });
10224
10225             t.features = s;
10226             t.params = p;
10227             t.onOpen.dispatch(t, s, p);
10228
10229             u = s.url || s.file;
10230             if (tinymce.relaxedDomain)
10231                 u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain;
10232
10233             try {
10234                 if (isIE && mo) {
10235                     w = 1;
10236                     window.showModalDialog(s.url || s.file, window, f);
10237                 } else
10238                     w = window.open(u, s.name, f);
10239             } catch (ex) {
10240                 // Ignore
10241             }
10242
10243             if (!w)
10244                 alert(t.editor.getLang('popup_blocked'));
10245         },
10246
10247         close : function(w) {
10248             w.close();
10249             this.onClose.dispatch(this);
10250         },
10251
10252         createInstance : function(cl, a, b, c, d, e) {
10253             var f = tinymce.resolve(cl);
10254
10255             return new f(a, b, c, d, e);
10256         },
10257
10258         confirm : function(t, cb, s) {
10259             cb.call(s || this, confirm(this._decode(this.editor.getLang(t, t))));
10260         },
10261
10262         alert : function(tx, cb, s) {
10263             var t = this;
10264     
10265             alert(t._decode(t.editor.getLang(tx, tx)));
10266
10267             if (cb)
10268                 cb.call(s || t);
10269         },
10270
10271         // Internal functions
10272
10273         _decode : function(s) {
10274             return tinymce.DOM.decode(s).replace(/\\n/g, '\n');
10275         }
10276
10277         });
10278 }());