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