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